# Get Started with Auth0
Source: https://auth0.com/docs/get-started
Get started with Auth0 by setting up the tenant, applications, and identity connections you need to add authentication to your products.
Auth0 is an identity platform to manage access to your applications.
If you’re new to identity and access management (IAM), learn some of the basics and plan the solution that best fits your technology and needs. If you’re familiar with IAM, you can jump in and start building.
***
## Start Building
To get up and running swiftly, choose your application type for a step-by-step quickstart tutorial.
Mobile or desktop app that runs natively on a device, like iOS or Android.
JavaScript web app that runs in the browser, like AngularJS + Node.js or React.
Traditional web app that runs on the server, like Express.js or ASP.NET.
An API or service protected by Auth0, like Express.js API or ASP.NET API.
An AI agent to call external APIs on the user’s behalf and use human-in-the-loop controls, like LangChain or LlamaIndex.
## Learn the Basics
Build your knowledge of IAM technology and Auth0.
Explore topics related to the fundamentals of identity and access management.
Discover different use cases. Create and connect the building blocks of your IAM solution.
## Configure Auth0
Define how Auth0 works with your applications and APIs. Control who can access your Auth0 Dashboard.
Learn about Auth0 Teams, including how to enable Teams, view and manage tenants, and manage tenant members.
Configure options in Auth0 Dashboard's profile section.
Configure the behavior of your Auth0 tenant.
Control the details of how Auth0 works with your applications.
Manage access for resource requests made to your APIs.
Administer your team members’ access to your Auth0 Dashboard.
## Plan and Design
Learn about Auth0 flows and architecture so you can make informed decisions about your Auth0 implementation.
Explore the different flows of information that drive authentication and authorization.
Read about real-world customer implementations of Auth0.
# Architecture Scenarios
Source: https://auth0.com/docs/get-started/architecture-scenarios
Learn about common Auth0 architecture scenarios that you can use to solve your authorization and authentication needs.
Customers using Auth0 typically have a common set of goals and objectives, and we want to share our real-world customer implementation experiences to help you deliver your solution efficiently.
# Business to Employees
Source: https://auth0.com/docs/get-started/architecture-scenarios/b2e
Explains the architecture scenario of B2E with a large organization that wants to extend their existing enterprise directory service.
The B2E (Business to Employees) scenario involves applications that are used by employee users. These are applications that are targeted toward users who are typically acting on behalf of an organization such as an employer, a university, or a group in which they are a member, as opposed to acting on their own behalf.
Such applications that are custom written by the organization may use the OIDC/OAuth protocol to externalize authentication whereas those that have been purchased will often use the SAML protocol. In either case, the enterprise will typically want to use some form of Enterprise connection, such as a SAML Identity Provider, ADFS, Google Workspace, Azure AD or a directory service such as AD or OpenLDAP, and less frequently, a custom DB, for authentication of enterprise users.
For a business that is creating or integrating applications with Auth0 for a B2E environment, there are several requirements that are common for this scenario. This guide will summarize the most common requirements for B2E applications and explain the Auth0 features which help meet each need.
## Enterprise providers
Most businesses already have a corporate identity repository which has information on all the employee users and user profile information. It may also contain information on partners and contractors. A common requirement for the B2E scenario therefore, is to allow such users to log in via [Auth0 Enterprise connections](/docs/authenticate/identity-providers/enterprise-identity-providers) such as SAML2 providers, ADFS, Google Workspace, Azure AD or an on-premise corporate directory service. This is attractive to users because it allows them to avoid creating yet another username and password for each application and instead leverage the same login credential across all their enterprise applications.
This is especially attractive to security interests within the company because user credentials are only exposed to the identity stack instead of to each application. Furthermore, this architecture allows the business to retain control over access to applications because the enterprise identity provider provides a single shutoff point. If a user leaves the organization, administrators can simply disable the user’s account in the corporate identity provider and the user can no longer log in to any of the applications using that identity provider.
Auth0 makes it easy to enable login via a wide variety of enterprise providers with just a few simple configuration steps.
## Groups and roles
With a lot of users, you may set up groups and roles to manage access and privileges. Often, these are stored and administered in a directory service.
Auth0 can get user attributes, like groups and roles, from a directory service or enterprise identity provider during authentication. You can then make the attributes available through tokens returned to the application or with the Auth0 Management API.
## Profile translation
Sometimes a directory or identity provider returns attributes in one format, but your application uses another format. Using Auth0's [Rules](/docs/manage-users/user-accounts/metadata/manage-metadata-rules), you can [map and translate user profile attributes](https://auth0.com/rules/saml-attribute-mapping). You can even translate between OIDC/OAuth, SAML, WS-Fed, and LDAP.
For example, you retrieve attributes in SAML assertion format from a SAML Identity Provider. With a rule you can then translate the attributes to custom claims in an ID Token for an OIDC/OAuth application.
You can also map SAML attributes to the Auth0 user profile from the dashboard. To do this, go to [Connections > Enterprise > SAMLP Identity Provider](https://manage.auth0.com/#/connections/enterprise), select your SAML connection, and set your attribute mappings in the **Mappings** tab.
## Extensibility with augmented user profiles
You may want to enrich user profiles with attributes or data retrieved from other services. For example, you might receive an address or phone number and wish to translate that into a geographic region. [Auth0 Rules](/docs/customize/rules) enable you to write small snippets of code that execute during the authentication transaction. This lets you execute logic or call other services for user information, then add [user metadata](/docs/manage-users/user-accounts/metadata) to the Auth0 user profile and optionally the resulting tokens sent to your applications.
## Single Sign-on
If you have several internal applications, you can set up [Single Sign-on (SSO)](/docs/authenticate/single-sign-on) across them so users only have to log in once.
Auth0 supports integration with applications that externalize authentication using industry standard identity protocols:
* OIDC/OAuth
* SAML2
* WS-Fed
After some configuration, all your applications can leverage your enterprise identity provider. In this setup, Auth0 is the broker between your applications and enterprise identity providers.
Now when a user signs in to one application, they can access other applications integrated with Auth0 without having to log in again. This will be true until their SSO session expires. You should configure the SSO session length within Auth0 to meet security policies.
## Single Sign-on integrations
You can also integrate purchased applications with Auth0 for Single Sign-on (SSO). Auth0 provides [pre-built integrations](/docs/customize/integrations/sso-integrations) for applications such as:
* Salesforce
* Zendesk
* Slack
* New Relic
## Branding
Branding is an important part of any application. Your logo, colors and styles should be consistent in all parts of the application. You can [customize](/docs/libraries/custom-signup) the login, signup, and error pages displayed by Auth0 so it matches your application. Add your own logo, text, and colors. There's also I18N/L10N support for global rollouts. [Emails for verification or password resets](/docs/customize/email/email-templates) are customizable too.
[Login screens](/docs/libraries/lock/lock-ui-customization) should appear to come from your application’s branded domain name. To maintain consistency, you can define a [custom domain name](/docs/customize/custom-domains) for the login screen displayed by Auth0.
## Multi-factor authentication
Internal or employee applications often deal with sensitive content. [Multi-factor authentication (MFA)](/docs/secure/multi-factor-authentication) helps protect your data and applications. Auth0 provides a variety of ways to implement MFA. And for more flexibility, you can use Rules to turn it on only for the applications or user groups that need it.
## Logs export
Need to analyze logs or store them long-term? Auth0 provides extensions to [export logs to external tools](/docs/deploy-monitor/logs) for analysis and retention. You can also retrieve log data with the Management API.
## Audit
Companies have many uses for logs data, one of which is audit reports. Auth0 captures a variety of data in log files, which may be useful for your audit reporting. The logs have information on authenticated users, the identity provider used, and when significant administrative changes are made in the Auth0 dashboard.
Log events each have an event type. You can use event types as filters when querying log data with the Management API, or when exporting logs to log analysis tools.
## Monitoring
Monitoring the infrastructure and services that your applications depend on is critical. Auth0 provides an [Auth0 Status](https://status.auth0.com/) page you can subscribe to.
Auth0 makes every effort to minimize outages, but if there is any disruption to service, it will appear on the status page. To support requirements for root cause analysis documentation after a disruption, Auth0 conducts internal analysis and publishes the results on the disruption notice when the analysis is completed.
## Attack Protection
An unfortunate part of modern life on the internet is hackers. Hackers are constantly trying to find a way into applications. For example, they may try to log in using common passwords. Or they may use credentials stolen from elsewhere, hoping that users re-used the same passwords at other sites.
Auth0's [Attack Protection](/docs/secure/attack-protection) detects these situations for Auth0 Database connections and provides options for how to respond. Turn on Attack Protection and configure the response options so you can respond appropriately if such an event occurs.
## Github Deployment
Do you manage a lot of your application code in Github? You can deploy code for Actions, Rules, Hooks, or custom database access from there with Auth0's [Github Deployment extension](https://marketplace.auth0.com/integrations/github-actions).
If you have a full continuous integration/continuous deployment pipeline, use the [Auth0 Deploy CLI tool](https://github.com/auth0/auth0-deploy-cli) for greater flexibility.
# Business to Business Architecture Scenarios
Source: https://auth0.com/docs/get-started/architecture-scenarios/business-to-business
Plan a B2B SaaS identity solution on Auth0 with this multi-tenant architecture guide, covering everything from setting up your authentication, to application deployment and launch.
This guidance is relevant to **all** project stakeholders. We recommend reading it in its entirety at least once, even if you've already started your journey with Auth0. We provide a [B2B IAM Project Planning Guide](https://assets.ctfassets.net/cdy7uua7fh8z/63F0WOPJdVzsPMxV1Xvp8x/7a329487c5e890d8e820f6a48983b46a/B2B_Project_Planning.pdf) in PDF format, details about how to get started with each phase of the implementation process, and [checklists](/docs/get-started/architecture-scenarios/checklists) to help you manage the tasks in each phase.
There are many different ways Auth0 can be integrated into the B2B IAM project architecture. Auth0's flexibility comprehensively supports many different use cases however your project may not require all of the capabilities provided by Auth0. Knowing what, when, and how best to implement something will help you focus on completing the necessary tasks at the right time.
Many B2B platforms implement some form of isolation and/or branding for their customers' organization, and this can add complexity to any Identity and Access Management (IAM) system. If this applies to you, then we recommend you take some time to read through our guidance and best practice advice for [multiple organization architecture](/docs/get-started/architecture-scenarios/multiple-organization-architecture).
Customers using Auth0 for Business-to-Business (B2B) projects typically share a common set of goals and objectives, and in the sections that follow we'll focus on our real-world customer implementation experiences to help you deliver your solution efficiently.
# Business-to-Business Architecture
Source: https://auth0.com/docs/get-started/architecture-scenarios/business-to-business/architecture
How you configure your Auth0 tenant architecture affects your B2B IAM implementation.
Understanding your application is key to understanding how Auth0 can be leveraged to meet your needs. From experience, our most successful customers start with a visualization of their proposed - or in many cases existing - architecture and use this as a basis for reference as they progress. Understanding where your application fits within your organization is also important; Auth0 [Accounts and Tenants](/docs/get-started/auth0-overview/create-tenants) form the basis for the grouping and structuring of Auth0 assets, and it may be that you’ll need to leverage an existing Auth0 deployment in order to integrate with [Single Sign-on (SSO)](/docs/authenticate/single-sign-on), centralized user [Profile Management](/docs/get-started/architecture-scenarios/business-to-business/profile-management), consolidated billing, or the like.
If you do have multiple applications, and you need to leverage SSO, then we recommend you check out our [How to Implement Single Sign-On](https://auth0.com/learn/how-to-implement-single-sign-on/) training guidance before continuing.
The value of investing time on the landscape of the architecture up-front is something that we have found pays dividends in the long run, and there are a number of things you will want to consider when looking at functionality and workflow:
* What should the URL look like when Auth0 needs to present a web page to a user?
* How can Auth0 be structured to support your SDLC (Software Development Lifecycle)?
* How can you ensure that your Auth0 tenants are appropriately associated with your contract?
* What do you need to consider if there are other projects in your organization integrating with Auth0? Particularly projects that target their own, or a different domain of users (for example, applications that only employees will use)?
* How can you align the structure and domain of your customers’ organization with your Auth0 deployment?
Organizations often service more than one domain of user - customers, employees, and affiliates being the most frequently encountered, with typically little to no cross-over: employees, say, don’t use the same applications as customers and vice-versa. In some cases there can also be a need to partition further within a domain - separate groups of customers, say, who use different and unconnected products. Auth0 provides a way to segregate your users and the associated collateral, and [tenant provision](#tenant-provision) covers this in more detail. If you need to provision an independent tenant then you’ll also want to [associate this with your existing Auth0 account](#tenant-association), so that you can take full advantage of the benefits provided at your organization’s contracted subscription level.
It’s not uncommon for companies to have identity requirements that address multiple user communities: customers, partners, employees, etc. So be sure to consider other projects or future requirements when designing your architecture.
In addition, you’ll undoubtedly have an established set of processes and procedures as part of your Software Development Lifecycle (SDLC). So you’ll want to check out our [SDLC support](#sdlc-support) guidance regarding Auth0 Tenant provision in support of that too.
For customer-facing applications, we typically see [OpenID Connect (OIDC)](/docs/authenticate/protocols/openid-connect-protocol) as being the most frequently used protocol. OIDC makes use of web based workflows with browser URLs that are presented to the user. Out-of-the-box, client facing URLs as part of Auth0 OIDC support are Auth0 branded, however we recommend using the Auth0 [custom domain](#custom-domains) capability to provide for consistent corporate identity and to also address potential user confidence concerns before they arise.
Other groups within your organization may also be working with Auth0; it’s not uncommon for our customers to have disparate departments that serve different user communities. Identifying these will potentially influence your design choices, and doing so early could mitigate decisions that might prove costly later on.
If some or all of your customer organizations each need their own custom URL or they are using social providers that need a custom consent page branded to the organization, then we recommend that you create separate Auth0 tenants for those organizations; see [Tenant provision for complex organizations](#tenant-provision-for-complex-organizations) for further details.
## Tenant provision
Everything starts with an Auth0 tenant. This is where you will be configuring your use of Auth0, and the where Auth0 assets - such as [Applications](/docs/get-started/applications), [Connections](/docs/authenticate/identity-providers) and [user profiles](/docs/get-started/architecture-scenarios/business-to-business/profile-management) are defined, managed and stored. Access to an Auth0 tenant is performed via the Auth0 [Dashboard](/docs/get-started/auth0-overview/dashboard), and via the Dashboard you can also create additional, associated tenants; you’re allowed to create more than one Auth0 tenant so that you can structure your tenants in a way that will isolate different domains of users and also support your [Software Development Life Cycle](#sdlc-support) (SDLC).
Tenant names cannot be changed, nor reused once deleted. So, make sure you're happy with your name(s) before you create your Auth0 tenants.
Determining the level of isolation you require when it comes to your user domains is an important step, and together with your branding requirements will subsequently help you determine the number of Auth0 tenants that will be required in your production environment. As we recommend you create a full suite of [SDLC supporting tenants](#sdlc-support) for every Auth0 tenant you will run in a production environment, the number of Auth0 tenants you will need to manage can quickly grow. Therefore you should consider carefully before creating multiple Auth0 tenants for production, and should consult our guidance on [Branding](/docs/get-started/architecture-scenarios/business-to-business/branding) before making your final decision.
### Tenant provision for complex organizations
In most cases, provisioning separate Auth0 tenants for your customer's organizations is not necessary. This has become even easier with the release of our new [Organizations feature](/docs/manage-users/organizations/organizations-overview). However, in certain circumstances this can be something that is valuable for reducing the complexity of your setup. For instance, we recommend provisioning a separate Auth0 tenant for your customers' organization as a best practice if:
* Your customer organizations need a custom login URL that is unique to the organization. This is generally the case only if you allow your organizations to have their own vanity URL instead of using a common login URL. Auth0 supports one custom domain per tenant.
* Your customer organizations use social providers for login. In this case, it is often desirable for the organization to have a custom consent page for the social provider that is branded to their organization.
If either of these situations is true, we recommend creating a separate Auth0 tenant for each organization that has one of the above criteria.
Maintaining multiple Auth0 tenants can add complexity to your system and should not be done unless absolutely necessary.
## Tenant association
To ensure that your [tenants are all associated with your Auth0 contractual agreement](/docs/get-started/auth0-overview/create-tenants/child-tenants) and have the same features, ensure all your tenants are associated with your company account. If you have individual developers that want to create their own sandboxes for testing, make sure they get associated with your account so they have the same permissions too. To do this you should contact your Auth0 representative or the [Auth0 Support Center](https://support.auth0.com).
## Custom domains
When you setup your Auth0 tenant, the URL for accessing that tenant will be of the form `https://{yourTenant}.auth0.com`. Providing a [Custom Domain](/docs/customize/custom-domains) (also known as a vanity URL), for your Auth0 tenant is not only an important factor for supporting your Branding requirements, but more importantly will also provide you with security benefits too:
* Some browsers will, by default, make it difficult to communicate in an iFrame if you don't have a shared domain. For example, [Safari's ITP causes Auth0 token renewal issues](https://support.auth0.com/center/s/article/troubleshoot-auth0-token-renewal-issues-in-safari-with-itp-enabled).
* It's [harder to phish your domain if you have a vanity URL](https://auth0.com/blog/introducing-custom-domains-preview-with-auth0/), as the phisher must also create a vanity URL to mimic yours. For example, with a custom domain you can use your own certificate to get an "Extended Validation", making phishing even harder.
You are allowed only one custom domain per Auth0 tenant. This is because a tenant in Auth0 is intended to represent a “domain” of users. If you need more than one vanity URL, then you likely have more than one domain of users and should be using multiple tenants.
Your custom domain name should also give the user confidence that this is the appropriate place to enter their credentials, and we recommend that you create your custom domain in all environments early on to ensure that you are testing consistently between environments. **It's extremely important to train your users to to look for suspicious URLs when entering their credentials!**
Create a custom domain (a.k.a. `CNAME`) for your Auth0 tenant, and also create one in development too so you can ensure you have managed the `CNAME` correctly. For example, you could create a `CNAME` which maps `login.mycompany.com` to `mycompany-prod.auth0.com`.
In almost all cases, customers have been most successful when adopting a strategy of a centralised domain for authentication across multiple product or service brands. This strategy provides users with a consistent UX, and also mitigates the complexity of deploying and maintaining multiple Auth0 tenants in a production environment. If you are considering having multiple domains for different brands, please refer to the [Branding](/docs/get-started/architecture-scenarios/business-to-business/branding) guidance before you begin implementing.
## SDLC support
Every company has some form of Software Development Life Cycle (SDLC), and throughout the development process you will want to align with that strategy. For instance, you need to be able to test your integration with Auth0 in a similar fashion as you test the applications themselves. It is therefore important to [structure Auth0 tenants to support your SDLC](/docs/get-started/auth0-overview/create-tenants/set-up-multiple-environments), and there is a consistent pattern which our customers typically follow when it comes to the best practices associated with tenant layout for doing so:
| Environment | Sample Tenant Name | Description |
| - | - | - |
| Development | **company-dev** | A shared environment where most of your development work occurs |
| QA/Testing | **company-qa** or **company-uat** | An environment for formal testing of the changes you've made |
| Production | **company-prod** | The production tenant |
In some cases you may also want to create one or more sandboxes (e.g., **company-sandbox1**, **company-sandbox2**) so that you can test changes without compromising your development environment. This might be where you test deployment scripts and the like.
You can also take advantage of our [Implementation Checklists](/docs/get-started/architecture-scenarios/checklists) that you can download and customize to meet your implementation project needs.
Customers with an Enterprise subscription should ensure tenants set up to support their SDLC are properly [linked to their subscription](/docs/get-started/auth0-overview/create-tenants/child-tenants). This will ensure each tenant has a consistent set of features enabled.
## Project Planning Guide
We provide planning guidance in PDF format that you can download and refer to for details about our recommended strategies.
[B2B IAM Project Planning Guide](https://assets.ctfassets.net/cdy7uua7fh8z/63F0WOPJdVzsPMxV1Xvp8x/7a329487c5e890d8e820f6a48983b46a/B2B_Project_Planning.pdf)
## Multiple Organization Architecture (Multitenancy)
Many B2B platforms implement some form of isolation and/or branding for their customers' organization, and this can add complexity to any Identity and Access Management (IAM) system. If this applies to you, then we recommend you take some time to read through our guidance and best practice advice for this type of environment.
[Multiple Organization Architecture](/docs/get-started/architecture-scenarios/multiple-organization-architecture)
# Business-to-Business Authentication
Source: https://auth0.com/docs/get-started/architecture-scenarios/business-to-business/authentication
Design authentication for your Auth0 B2B SaaS application, using Universal Login, home realm discovery across Organizations, enterprise connections, and MFA to securely identify users from multiple customer tenants.
In order to provide services to your users, you must be able to identify who those users are. This process is called User Authentication. There are a number of ways to perform authentication of a user - via social media accounts, username and password, passwordless - and it's often recommended that you go beyond a first factor for authenticating the user by enabling multi-factor authentication (MFA).
It's important to consider both security and user experience when designing how you will authenticate your users. Providing for multiple primary factors, and/or enforcing more than one factor during authentication, are ways that you can provide both.
There are a number of things you will want to consider when looking at functionality and workflow:
* Where will users enter their credentials?
* How will you keep user credentials safe?
* How will you maintain your authentication system?
* How can you provide password authentication for your users?
* How can you prevent hackers from trying to log in as your users?
* How will you implement authentication in different kinds of applications?
* How can you make login easy for your users when they come from different language backgrounds?
* How will you provide a good user experience as you migrate away from any legacy authentication system?
* What should you consider when integrating applications with Auth0?
* Do you need to provide multi-factor authentication?
* What do you do if you have a service that doesn't have a way for the user to log in ahead of time?
* Can you pass the same user access token from one API to another?
* What do you do if you need to isolate users by organization?
* How will you handle identifying which organization users belong to?
* What’s the benefit of providing enterprise connections for your organizations?
Auth0 [Universal Login](#universal-login) provides users with a safe and secure experience - no matter whether you choose to provide for user ID/password credentials sign in, or allow the so-called Bring Your Own Identity scenarios provided via [Social Login](https://auth0.com/learn/social-login/). There are also brand recognition benefits to centralizing the login experience with Universal Login, even if you feel you will also have product-specific [branding](/docs/get-started/architecture-scenarios/business-to-consumer/branding) requirements. The Auth0 UI widgets typically used with Universal Login also provide out-of-the-box support with regards to [internationalization](/docs/customize/internationalization-and-localization/universal-login-internationalization) for users with different language requirements, and out-of-the-box support for Auth0 features such as [MFA](#multi-factor-authentication-mfa-) and [attack protection](#anomaly-detection) allow you to put barriers in place in order to prevent hackers attempting to access users' accounts.
Allowing users to sign in via user ID/password credentials means that you're not reliant on the status of third-party identity providers for your users to access your system. You also have the means to require the credentials used to align with your corporate policies. Auth0 assists with this by providing you with multiple options in support of user ID/password logins, and the [guidance provided](#username-and-password-authentication) will help you understand you can leverage these options. Adding [social](#social-authentication) support at some stage, as an additional primary authentication factor, gives you added flexibility and can help you better understand your users without the need to question them further by leveraging the information already stored by the various social login [providers](/docs/authenticate/identity-providers/social-identity-providers).
If you have an existing legacy identity store, you’ll also want to see [User Migration](/docs/get-started/architecture-scenarios/business-to-consumer/provisioning). This section discusses the advantages of migrating to Auth0’s managed identity storage in terms of safety and security.
For customer facing applications, OpenID Connect ([OIDC](/docs/authenticate/protocols/openid-connect-protocol)) is the most frequently used industry standard protocol, and OIDC has first-class citizen support in Auth0. Auth0 provides support for various different approaches for integrating various different applications, so you'll want to see the section on [application integration](#application-integration) for the information you'll need to make an informed choice.
When calling one API from another API, or from any situation where there is no authenticated user context - such as one or more cron jobs, report generators, or continuous integration/delivery systems - you will need a way to authorize the application instead of a user. This is a one step process where the application is authenticated (using a client ID and secret) and then authorized in one call. You can learn more about this in our authorization work stream under [machine-to-machine (m2m) authorization](/docs/get-started/architecture-scenarios/business-to-business/authorization).
Often companies need to segregate their users by organization and sometimes users can have access to more than one organization. Knowing which of these scenarios is relevant to your company will help define how to determine in which connection a user exists: whether you need to do it, when you need to do it, and how to accomplish it. See [Home Realm Discovery](#home-realm-discovery) to determine if this is something relevant to your company.
## Universal Login
Do you have, or will you have, more than one application in your system? If the answer to this question is yes, then you will want a centralized sign in experience. To achieve a seamless Single Sign-on (SSO) experience between multiple applications, it is critical to have a centralized location to redirect your users for authentication. This allows you a way to provide your users with a consistent experience if you add social authentication in the future, add third party applications to your system, or add multi-factor authentication as an option (or requirement) for your users - and also allow you to take advantage of new features for improving your users’ experience with little, if any, added development effort.
If you have more than one application, the best practice is to redirect to a [centralized location](/docs/authenticate/login/auth0-universal-login) to authenticate the user. With Auth0, this means taking advantage of [Universal Login](/docs/authenticate/login/auth0-universal-login), which provides many security and user experience benefits out-of-the-box, including [SSO](/docs/authenticate/single-sign-on).
Auth0 Universal Login makes authenticating users a short, easy process which can be accomplished in three easy steps (all of our Quickstarts demonstrate this and our SDKs hide the complexity for you too):
1. Determine how and when you want to [redirect from your application](#application-integration).
2. Set up the appropriate [branding](/docs/get-started/architecture-scenarios/business-to-consumer/branding) and/or customized HTML in your Auth0 configuration.
3. Set up your application to [receive and handle the response](#application-integration) from the Authorization Server.
## Home realm discovery
Home realm discovery (HRD) is the process of identifying which identity provider (or which connection in Auth0) the user belongs to before authenticating them. There are two ways HRD can occur:
* Provide a way for the decision to be made at the application
* Have Home Realm Discovery happen on the Universal Login page
Your system may need to do either or both methods so it is important to understand all approaches to HRD so that you can apply the one(s) that make the most sense to your applications.
### Application driven HRD
A common way of determining which realm a user belongs to is when an application is branded for each organization. As part of this, an organization will typically have its own instance of the application, typically accessed via a different URL. This copy or instance can be physically isolated (running on a separate set of servers) or virtually isolated (running on shared servers) and is generally denoted through either a custom hostname (`companyA.application1.yourcompany.com`) or path (`application1.yourcompany.com/companyA`).
If your application already knows the specific connection (IdP) required then you can also pass that along when you redirect the user to `/authorize`, via use of the `connection` query parameter.
If this is the case for your application(s), then home realm discovery is a simple matter of storing the `org_id` with the organization-specific application configuration and sending that as the organization parameter when redirecting the user to Universal Login. Doing so will limit the user to that specific organization and its set of configured connections.
If an organization needs more than one IdP, then you may have to do a second round of Home Realm Discovery (once the organization has been identified). Auth0 will typically manage this for you if you are using the Organizations Feature.
If the user is shared between multiple organizations using a single identity, you must support [Home Realm Discovery on the Universal Login Page](#hrd-through-universal-login). This will allow Universal Login to identify the user first and then present the realms appropriate for that user leading to a better user experience.
Sending the organization and/or connection parameters can be achieved by adding them as a query parameter when you redirect the user to the `/authorize` endpoint. For more information, see the [Authentication API docs](https://auth0.com/docs/api/authentication#authorization-code-flow). However, you will generally accomplish this using the SDK for whichever language your application is written in.
### HRD through Universal Login
There are three main approaches to Home Realm Discovery:
* Discover the realm through the user’s email subdomain.
* Discover the realm by looking up a user identifier in some sort of map of an identifier to realm map.
* Allow the user to choose or enter their realm (or organization).
In both of the first two approaches, you may consider doing “Identifier First Login”. This means that you present only the ability to enter an identifier first. After which, you collect the user’s identifier, and then, based on the identifier, you either automatically redirect the user or present a way for the user to enter their password if redirection is unnecessary. Auth0 provides implementation out of the box to take care of all of this, via the use of [Universal Login](/docs/authenticate/login/auth0-universal-login/identifier-first).
Though it is possible to implement Identifier First Login or allow a user to select their organization at the application instead of on the Universal Login Page, this can add complexity with respect to single sign on as well as complexity associated with replicating that behavior in all of your applications. Instead Auth0 recommends implementing some form of HRD through Universal Login.
#### HRD through Universal Login using the email subdomain
The simplest way to implement home realm discovery on the universal login page is to utilize the email subdomain of the user’s identifier to map that to their Identity Provider. This, of course, only works in situations where the email subdomain will be a 1:1 mapping to an organization or at least to an Identity Provider.
Auth0’s [Lock](/docs/libraries/lock) widget or [Universal Login](/docs/authenticate/login/auth0-universal-login/universal-login-vs-classic-login/universal-experience) can do this for you if you are using the domain map in an enterprise connection; however, if you want to build this yourself, you can, but it requires you to build a mapping of email subdomain to connection.
Additionally, when using the Universal Login experience, the [Organizations Feature](/docs/manage-users/organizations/organizations-overview) will help you in two ways:
1. If you have not passed an org\_id to `/authorize` when you initiated the login request, Auth0 will present the user with a prompt to enter the organization they belong to.
2. If the Organization has more than one IdP associated with it, Auth0 will present the user with buttons to choose the organization or a form to enter a username and password.
#### HRD through Universal Login using the Identifier to Realm Map
A second, more complex alternative is to store a map of identifiers to IdP and provide a public endpoint to access that information. Then on the Universal Login page, you can find the connection and redirect back to /authorize with the connection. The main drawbacks to this approach are latency and, more importantly, security when it comes to identifier discovery: if you’re using email addresses, this makes it much easier for someone to discover whether a particular email address is a user of yours.
Any public endpoint should have rate limiting applied to it to prevent hackers from using it to discover information and to prevent denial of service attacks.
#### HRD through Universal Login using user choice
The other option is to allow your users to choose from a list, if you don’t mind making public the list of organizations who use your product, or by allowing the user to enter their organization name explicitly. This would typically be done before redirecting the user to Universal Login. Once the user tells you which organization they belong to, you can redirect to Auth0 with the connection for that organization specified or have Auth0 simply prompt the user for their username and password if the connection is a database connection.
## Username and password authentication
Nearly every B2C application provides the ability for its customers to create a new set of credentials. This is a common form of authentication that all users are familiar with.
Username password authentication comes in multiple flavors at Auth0. If your application is a green-field application with no existing user base, then a simple Auth0 out-of-the-box [Database Connection](/docs/authenticate/database-connections) will give you everything you need to start authenticating your users. However, if you have a legacy user store (such as your own database of users or an existing LDAP system) you have a couple of different options for migrating your users as discussed in our guidance on [User migration](/docs/get-started/architecture-scenarios/business-to-business/provisioning).
However you end up provisioning the users for your database connection, the authentication of those users is quite similar. It requires you to present users with a form to enter their username and password. As mentioned in the guidance concerning [Universal Login](#universal-login), the simplest and safest way to authenticate users with a username and password is to redirect them to a centralized login page and collect their username and password there. This allows Auth0 to determine whether they have already authenticated and skip the login form entirely when it's not needed.
Collecting credentials only at the centralized login page will reduce the surface area for potential leak of user secrets. It will also reduce the need to collect credentials unnecessarily. See [Universal Login](#universal-login) for more information.
## Application integration
Once you've figured out how you want to authenticate your users, the next step is to determine how you will initiate that authentication. Each application will typically have its own starting point.
Native mobile applications (and desktop applications) should use the system browser for authentication, or they open themselves up to additional security risks. See [Native Login](/docs/authenticate/login/native-login) for more information.
As discussed, we've found that most of our customers use [OpenID Connect (OIDC)](/docs/authenticate/protocols/openid-connect-protocol) as the industry-standard protocol when it comes to their customer-facing applications. Figuring out which OIDC flow to use is your first task, and you will want to start by reviewing the our [grant mapping](/docs/get-started/applications/application-grant-types) guidance in the first instance.
If you want to allow anonymous users access to any part of our application then you need to determine if you will be redirecting right away or prompting your users to redirect only when required (or perhaps some combination of both; see [Redirect Users After Login](/docs/authenticate/login/redirect-users-after-login) for further discussion). If users can [deep link](#deep-linking-to-protected-endpoints) to a protected version (or area) of your site then you will need to determine the links to your application that will result in an automatic redirect to Auth0.
### Anonymous access
It is important to consider the user experience when someone first comes to your application. If your application supports anonymous user access (quite common for eCommerce applications) there are different scenarios to consider:
* Are they returning to the application after having already logged in, or
* If this is the first time they are accessing the application:
* Have they already accessed a different application that uses the same Auth0 tenant,
* Have they ever (or perhaps not in a long time) authenticated on this device or browser.
When an anonymous user accesses your application, it can often be desirable for the application to discover if the user has already logged into a different application in the same family, or to remember this user even if the application is a [SPA](/docs/quickstart/spa) with no state. For example, if you can determine that the user is already logged in, you might decide to have the UI header in the application skip displaying a login button and instead have an account or profile menu for the user. To accomplish this you will want to utilize "[silent authentication](/docs/authenticate/login/configure-silent-authentication)". Silent authentication will allow you to check to see if the user is logged in without prompting them to log in if they are not. Then the application can present a login button if necessary. If the user is logged in already, however, then you will receive tokens and will not have to present the user with a login button again.
Checking for a login session by redirecting to Auth0 can be helpful for your application, but if this will result in a lot of requests, you should employ a throttling mechanism to avoid latency and/or rate limiting.
Calls to the Management API are subject to [Auth0 Rate Limiting policy](/docs/troubleshoot/customer-support/operational-policies/rate-limit-policy). You must take this into consideration, and to assist, Auth0 generally recommends use of the appropriate [Auth0 SDK](/docs/libraries) for your development environment rather than calling our APIs directly.
### Deep linking to protected endpoints
There are a variety of reasons why someone might link directly to a particular page within your application that is only accessible by authenticated users. If this is possible for your application you should automatically redirect your user to Auth0 if they are not authenticated. Once they authenticate and the authorization server returns them to your application, you can [redirect them](/docs/authenticate/login/redirect-users-after-login) to where they intended to go in the first place.
### Best Practice
Most modern authentication frameworks support middleware for redirecting to an authorization server such as Auth0. When selecting one, here are some key considerations:
* Support for confidential clients, non-confidential clients, or both
* Support for configuration via [discovery endpoint](/docs/get-started/applications/configure-applications-with-oidc-discovery "Configure Applications with OIDC Discovery") or explicitly inline
* Support for token validation including expirations, signatures, claims and scopes
* Support for Refresh Tokens if needed
### Authenticating the user
Authentication is the process of determining user identity. The result of authentication in an OIDC context is an ID Token. This token contains information about the user and should only be able to be obtained if the user authenticates using one or more factors as defined by the authorization server (the most common form being [user ID and password](#username-and-password-authentication)). There are a few things you may also need to consider in addition to obtaining an ID Token:
* Do we also need an [Access Token](/docs/secure/tokens/access-tokens) in order to call a shared API?
* Is your application a single-page application and only requires an [ID Token](/docs/secure/tokens/id-tokens)? See [Authorization Code Grant with PKCE](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow-with-pkce/call-your-api-using-the-authorization-code-flow-with-pkce) for more information.
* Is your application a native application (mobile or desktop) and/or do you need a [Refresh Token](/docs/secure/tokens/refresh-tokens)? See [Authorization Code Grant with PKCE](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow-with-pkce/call-your-api-using-the-authorization-code-flow-with-pkce) for more information.
Before you go live, you should ensure that **only** the grants that you are using for each application are enabled in your [configuration for your Application](/docs/get-started/applications/update-grant-types).
### Authorization code grant (with or without PKCE)
If your SDK only supports the Authorization Code grant, or you need an Access Token or Refresh Token, then Authorization Code grant (with or without [PKCE](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow-with-pkce)) can also be used to retrieve an ID Token. The Authorization Code grant includes an additional API call to exchange the code for a token which can result in additional unnecessary latency if all you need is the ID Token. In many cases the [hybrid flow](/docs/get-started/authentication-and-authorization-flow/hybrid-flow) is implemented to provide optimum access to the ID Token while still leveraging Authorization Code grant workflow for the secure and safe retrieval of Access and Refresh Tokens.
While Auth0 supports the use of implicit grant for browser-based applications requiring only an ID Token, it is recommended to use authorization code grant with [PKCE](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow-with-pkce). For detailed information, see [OAuth2 Implicit Grant and SPA](https://auth0.com/blog/oauth2-implicit-grant-and-spa/) on the Auth0 Blog.
If you need a [Refresh Token](/docs/secure/tokens/refresh-tokens) so that you can obtain a new Access Token or ID Token without having to re-authenticate the user, then you must use the [authorization code grant](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow/call-your-api-using-the-authorization-code-flow).
## Attack protection
The reason that authentication systems are important is to prevent bad actors from accessing applications and user data that they should not. We want to place as many barriers as possible between those bad actors and access to our systems. One of the easiest ways to do this is to ensure that your [attack protection](/docs/secure/attack-protection) with Auth0 is configured correctly, so take a moment to read the guidance on this subject and ensure that it's working correctly for you.
Anomaly detection is handled behind the scenes by Auth0 and provides a great security feature for your product. If you're going to utilize it, ensure that you have set up your [Email Provider](/docs/get-started/architecture-scenarios/business-to-business/operations#email-provider-setup) and configured your [Email Templates](/docs/get-started/architecture-scenarios/business-to-business/branding#email-template-customization) before turning on email delivery to your users.
## SSO with legacy systems
In a large scale re-structure it's not always possible—or practical—to update all your applications at once. In fact, our recommended best practice is to plan for an iterative-style approach when it comes to integrating with Auth0. If your applications already participate in Single Sign-on (SSO), and your legacy identity system supports protocols such as OIDC or SAML, then you have a couple of options available if you want to continue to provide SSO as you integrate with Auth0:
* Update your existing identity provider in your legacy SSO system to redirect to Auth0 for login (e.g., using [SAML](/docs/authenticate/single-sign-on/outbound-single-sign-on/configure-auth0-saml-identity-provider)), or
* Have Auth0 redirect to your legacy SSO system to login. This requires configuring your legacy system as an IdP in Auth0 (i.e., either using [SAML](/docs/authenticate/protocols/saml/saml-sso-integrations/configure-auth0-saml-service-provider) or [OIDC](/docs/authenticate/identity-providers/social-identity-providers)).
Supporting an SSO experience with your legacy system can add complexity, but may be worth it to generate a more seamless user experience as you integrate with Auth0. If you intend to go down this path, planning for it early can help ensure that it is possible to achieve. If you don't already have SSO at a centralized service, then the complexity to add it will unlikely be worth the benefits.
This is a complex topic that will likely need some additional investigation depending on your current legacy architecture, and we recommend you only look into this if you currently have SSO support in your legacy system. Note: if you are currently redirecting from your applications to a centralized system to authenticate your users and that system only asks for credentials if you don’t already have a session with the centralized system, then you have a legacy SSO implementation.
## Enterprise Login
The “bring your own identity” scenario has become a must-have for almost all B2B applications. Most enterprise companies expect to be able to integrate their IdP into your application so their employees don't need to store another set of credentials. This is a valuable way of simplifying the user authentication experience without compromising security, and using [Universal Login](#universal-login) makes it easy to start adding support for [Enterprise Connections](/docs/authenticate/identity-providers/enterprise-identity-providers) with minimal disruption.
Once you start supporting enterprise connections for users, you must do some form of [Home Realm Discovery](#home-realm-discovery) so that you can determine which connection to send the user to for authentication.
With enterprise connection support, user identities and credentials are managed by the identity provider of your customers' organization, as well as certain identity claims - which Auth0 will use to populate the user [profile](/docs/get-started/architecture-scenarios/business-to-business/profile-management).
"Bring your own identity" is a great feature to provide, but if you don't support this from day one, and sometimes even if you do, you may have an organization that wants to switch to their own IdP after already having used the application for a while. You will need a way to [link user accounts](/docs/manage-users/user-accounts/user-account-linking) to provide an effective way of associating the new identity with the old database identity.
## Multi-factor authentication (MFA)
In an era where misuse of user credentials is at an all-time high, protecting your systems when it’s so common for hackers to steal users identity information in general is a challenge. One of the most effective ways though is to provide users with the ability to configure a second factor for protecting their account. More commonly referred to as [Multi-Factor Authentication](/docs/secure/multi-factor-authentication). This will ensure that only a valid user can access their account, even if they use a username and password that may have been compromised from a different application.
It's quite common for customer facing applications to provide users with an *option* for adding a second factor rather than *forcing* them to use a second factor. For more information regarding this, see [providing your users with an option to add MFA](https://auth0.com/learn/multifactor-authentication-customers/).
Auth0 supports a number of different options when it comes to enabling MFA for protecting user account access, and there are several practices to ensure that you will truly be providing a flexible second factor barrier to access:
* Auth0 [Guardian](https://auth0.com/multifactor-authentication): a service that provides both Push notification generation and an application for allowing or denying requests. Push sends notification to a user’s pre-registered device - typically a mobile or tablet - from which a user can immediately allow or deny account access via the simple press of a button.
* Time-based One-Time Password ([TOTP](https://auth0.com/blog/from-theory-to-practice-adding-two-factor-to-node-dot-js/)): allows you to register a device - such as Google Authenticator - that will generate a one-time password which changes over time and which can be entered as the second factor to validate a user’s account.
* SMS: for sending a one-time code over SMS which the user is then prompted to enter before they can finish authenticating.
* Voice: for delivering a one-time code through a phone call which the user is then prompted to enter before they can finish authenticating.
* Duo: allows you to use your Duo account for multi-factor authentication.
* Email: allows you to use your email account for multi-factor authentication.
Whilst MFA workflow using technologies such as Guardian or Google Authenticator is typically provided via a separate application that runs on a mobile or tablet device, if you don’t want your customers to have to download a separate application Auth0 also provides you with an [SDK](https://auth0.com/blog/announcing-guardian-whitelabel-sdk/) that you can use to build second factor workflow right in your existing mobile device application(s).
## Project Planning Guide
We provide planning guidance in PDF format that you can download and refer to for details about our recommended strategies.
[B2B IAM Project Planning Guide](https://assets.ctfassets.net/cdy7uua7fh8z/63F0WOPJdVzsPMxV1Xvp8x/7a329487c5e890d8e820f6a48983b46a/B2B_Project_Planning.pdf)
## Multiple Organization Architecture (Multitenancy)
Many B2B platforms implement some form of isolation and/or branding for their customers' organization, and this can add complexity to any Identity and Access Management (IAM) system. If this applies to you, then we recommend you take some time to read through our guidance and best practice advice for this type of environment.
[Multiple Organization Architecture](/docs/get-started/architecture-scenarios/multiple-organization-architecture)
# Business-to-Business Authorization
Source: https://auth0.com/docs/get-started/architecture-scenarios/business-to-business/authorization
User authorization and related planning considerations for your B2B IAM implementation.
Let's start by taking a step back and talking about Access Control. There isn't one clear cut definition of Access Control in the industry, but if you spend some time searching and reading, you'll see that most authoritative sources agree that it is the umbrella concept that puts all of Authentication, Authorization, Consent, and Policy Enforcement together to ensure that only the right people and services have access to your applications and APIs.
Next, let's look more closely into the distinctions between Authentication, Authorization, Consent, and Policy Enforcement. Your Auth0 tenant (your Authorization Server) is typically responsible for Authentication and Consent, and some or all of Authorization and Policy Enforcement. Additionally, an Application or API itself almost always is the primary enforcer of policies, especially where contextual access is required:
* **Authentication**: the process of determining if a principal (a user or application) is who or what they say they are.
* **Authorization**: the process of determining what is allowed, based on the principal, what permissions they have been given, and/or the set of contextually-specific access criteria.
* **Consent**: what permissions the user (Resource Owner) has given permission to an application to do on its behalf. This is generally a requirement of delegated authorization. The user has to give permission to the Client to access the user's data in a different system.
* **Policy Enforcement**: The act of enforcing the policies of the application or API, rejecting or allowing access based on a user's authentication and/or authorization information.
In general, we typically group different types of access control into three distinct categories so that it's easier to understand a) which actor is responsible for storing the information, b) which actor is responsible for making decisions, and c) which is responsible for enforcing the restrictions.
* The first category is where access is either granted or denied to an application or an API in its entirety. Both the data required to enforce this and the enforcement process is typically defined in the context of the Authorization Server For example, by using [`app_metadata`](/docs/manage-users/user-accounts/metadata) associated with a user and an [Action](/docs/customize/actions) defined in your Auth0 tenant.
* The second category is where access is either granted or denied to a specific subset of application or API functionality. The data required to enforce this is typically stored in the Authorization Server For example, by using `app_metadata` on a user in your Auth0 tenant with the enforcement process performed in the application or API itself. In this scenario, the data is typically communicated as one or more custom claims in an [`id`](/docs/secure/tokens/id-tokens) or [`access`](/docs/secure/tokens/access-tokens) token.
* The third category is where access is either granted or denied depending on what the principal (subject) can operate on within the context of an application or API. Both the data required to enforce this, and the enforcement process is typically defined in the context of the application or API. In this scenario, the data communicated as one or more custom claims in an `id` or `access` token may be consumed with or without data from an external source that is not Auth0.
In addition, Role-based Access Control (RBAC) and Attribute-based Access Control (ABAC) mechanisms can be applied in any of the Access Control categories described above. Whatever your use case then, there are a number of things you will want to consider when looking at the functionality and workflow you require:
* Are there scenarios where access to an entire application or API should be rejected?
* Will you be providing APIs that can be accessed by third-party applications?
* Will your APIs also be accessed by your own (first-party) applications?
* Will your application be calling a third-party API?
* Should your applications and/or APIs be enforcing access control based on user claims?
* What if I need to know which organization an access token or ID token is associated with?
Auth0 supports access restriction for either applications or APIs based on certain conditions. In certain scenarios, you may want to create an Action that returns an `UnauthorizedError` when, for example, a user attempts access to an application or an API at an incorrect time (as described in this [example](/docs/manage-users/access-control/sample-use-cases-rules-with-authorization#allow-access-only-on-weekdays-for-a-specific-application))—or if the user doesn’t have the right claim(s) contained in their `app_metadata`. For an application using [OpenID Connect (OIDC)](/docs/authenticate/protocols/openid-connect-protocol), this would prevent the allocation of the [ID Token](/docs/secure/tokens/id-tokens) used to authorize access. Similarly, for an API, allocation of any OAuth2 [Access Token](/docs/secure/tokens/access-tokens) (used when calling the API), could be prevented as described in this [example](/docs/manage-users/access-control/sample-use-cases-rules-with-authorization#deny-access-to-anyone-calling-an-api).
In the main, we have found that [OIDC](/docs/authenticate/protocols/openid-connect-protocol) is the most commonly used industry-standard protocol used by Auth0 customers when it comes to authentication in their applications. We have also found that, even though [OAuth2](/docs/authenticate/protocols/oauth) was created as a delegation protocol, it is commonly used within first party applications when there is an API that does not have a shared session with the application.
Auth0 also can provide the information needed so that an application can enforce restrictions. For [application level integration](#application-integration), Auth0 allows you to add [custom claims](#id-token-claims) to an ID Token, which your application can then verify and subsequently use to perform policy enforcement. In this case you will need to decide what information you require for your application to make enforcement decisions. If you need to make decisions at an API instead of in your application, you will likely need to use an Access Token instead of an ID token. Continue reading for more information.
When deciding what data to include in your ID token and/or access token, consider token size, especially if you are passing the token in the URL. Even if you are not passing tokens in the URL, you will also need to consider the potential of exposing sensitive PII (Personally Identifiable Information). Token information is not encrypted, so although it isn't generally a security issue for an ID token to be leaked, it can become a privacy issue depending on the data that is included in the token.
For [API level integration](#api-integration), Auth0 supports both [custom claims](#access-token-claims) as well as [scope](#access-token-scopes) re-configuration, both within the context of an Access Token. Again, you will need to decide what information will be required in order for your API to make access decisions, and your API will need to enforce that by validating the contents of the Access Token.
When deciding whether you should use permissions through custom claims or scopes, you should make sure you understand the nature and purpose of scopes. There is a nice [blog post](https://auth0.com/blog/on-the-nature-of-oauth2-scopes/) on that which is easy to read and helps clear up the topic.
For multi-organization scenarios, it can often be important to know which organization an access token (or even an ID token) applies to. Taking care to follow the [best practices](#organization-data-in-an-access-token) can save you time and effort.
## Application integration
In this scenario, your Auth0 tenant provides a token as an indicator of authorized access to an application. For applications utilizing [OpenID Connect (OIDC)](/docs/authenticate/protocols/openid-connect-protocol), the industry-standard protocol we typically find most utilized when it comes to customer facing applications, this would be an ID Token expressed as a [JWT](/docs/secure/tokens/json-web-tokens).
### ID Token claims
Using Actions extensibility, Auth0 allows you to easily [add custom claims to an ID Token](/docs/get-started/apis/scopes/sample-use-cases-scopes-and-claims#add-custom-claims-to-a-token) based on, for example, a user’s [metadata](/docs/manage-users/user-accounts/metadata) content. Your application can then verify the ID Token for the necessary claims, and either allow or prevent access to certain functionality as required. Note that though the process of adding custom claims via Actions is streamlined, Actions are flexible and allow you to write custom code that may have negative effects.
When you are considering adding custom claims, we recommend that you store any access control data you may need to include within claims as part of the user's [`app_metadata`](/docs/manage-users/user-accounts/metadata). Firstly, this prevents you from needing to call an external API to fetch the data, which can negatively impact the performance and scalability of the login sequence. Secondly `app_metadata` **cannot** be modified by a user - so the user cannot directly circumvent any access control restrictions by modifying their own metadata. Also remember to check out our [metadata best practices](/docs/get-started/architecture-scenarios/business-to-business/profile-management#metadata) guidance too.
If you are creating different instances of your application for your customer organizations, a common practice is to create a custom claim in your ID token to represent the user's organization. For example:
```js wrap theme={null}
context.idToken["http://yourdomain.com/claims/organization"] = "organization A";
```
### ID Token scopes
[OIDC Scopes](/docs/get-started/apis/scopes/openid-connect-scopes) are typically used by an application to obtain consent for authorized access to a user's details during authentication. Each of the pre-defined scopes returns the set of standard claims where defined, and as described in the [OIDC specification](https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims). The scopes an application requests depend on which user attributes the application needs. Once the requested scopes are authorized by the user, the claims are returned in the ID Token and are also made available via the [/userinfo](https://auth0.com/docs/api/authentication/user-profile/get-user-info) endpoint.
## API integration
In this scenario your Auth0 tenant can provide an OAuth2 [Access Token](/docs/secure/tokens/access-tokens), typically expressed as a [JWT](/docs/secure/tokens/json-web-tokens), which can be used by your API to restrict access to certain parties. In addition, Auth0 provides support for what is notionally described as both [First-Party and Third-Party Applications](/docs/get-started/applications/first-party-and-third-party-applications).
Acting as the authorization server, and with the consent of the user (the resource owner), your Auth0 tenant can be used to provide an Access Token—typically expressed as a [JWT](/docs/secure/tokens/json-web-tokens)—to an application (client) so that it can access a protected resources hosted by a resource server on behalf of the resource owner. The issued Access Token is typically passed as the Bearer token in the HTTP Authorization header sent to an API.
Whether you have a single API, or perhaps a suite of logically related [microservice APIs](/docs/get-started/apis/set-logical-api), you can leverage the Access Tokens that Auth0 provides in order to secure access to your service(s). Though relatively easy to set this up in the [Auth0 Dashboard](https://manage.auth0.com/) or through the [Auth0 Management API](https://auth0.com/docs/api/management/v2#!/Resource_Servers/post_resource_servers), it's important to review the different application scenarios and API layouts to determine the best architecture for your system.
OAuth2 Access Tokens are primarily designed for use in securing public facing APIs; when expressed as a JWT, an Access Token is a self contained entity which can be verfied without the need to make any additional 3rd party API call. If your APIs do not fall into this category - i.e they are part of an application itself (as in only called by that application) or are sat behing your firewall - then protecting them with tokens may well be overkill, and your existing cookie based (et al) workflow may well suffice.
OAuth2 was designed specifically with third-party access in mind, For example, a scenario might be that a user (resource owner) wants to use an application (a client) that does not belong to the same organization as the service that provides the user's data (the reseource server). In this case, when the application needs to access data that the user owns, it redirects to the organization where the user’s data resides, which in turn authenticates the user and then prompts the user to give the application permission to access their data. This prompting for permission is referred to as providing [consent](/docs/get-started/applications/third-party-applications/user-consent-and-third-party-applications) and is a large part of what providing support for [third party applications](/docs/get-started/apis/scopes/api-scopes#example-an-api-called-by-a-third-party-application) entails. If you are planning to integrate third-party applications, then it's important you mark them as third-party early on so that Auth0 will handle prompting for user consent.
On the other hand, if your organization owns the application(s), the user data itself and the API(s) through which that data is accessed, then consent is not typically required as the interactions are all [first-party](/docs/get-started/apis/scopes/api-scopes#example-an-api-called-by-a-first-party-application). If you're only creating first-party applications, then you can ensure that you are not presenting your users with any unnecessary consent screen(s) by [allowing user consent to be skipped](/docs/get-started/apis) as part of any resource service definition.
Though you can configure your applications to be first-party and subsequently configure your APIs to allow first-party clients to ignore consent, if you are using `localhost` then Auth0 cannot verify that the application is truly a first-party app so your users will be prompted for consent anyway. To work around this constraint, when testing on your local machine during development, create a [fake local hostname and use that instead](https://community.auth0.com/t/how-do-i-skip-the-consent-page-for-my-api-authorization-flow/6035).
Alternatively, you may have data relating to a user for which additional [functionality is provided](/docs/get-started/apis/scopes/api-scopes#example-an-api-called-by-a-back-end-service) and for which explicit user consent cannot be obtained (i.e. there is no authenticated user who can provide it). In this scenario, a [list of applications for which Client Credentials grant is enabled](/docs/get-started/authentication-and-authorization-flow/client-credentials-flow) can be defined.
### Access Token claims
As is the case with ID Tokens, you can [add custom claims to Access Tokens](/docs/get-started/apis/scopes/sample-use-cases-scopes-and-claims#add-custom-claims-to-a-token) using Auth0 Actions extensibility. Once added, your API can then verify an Access Token for the necessary claims and either allow or prevent access to certain functionality as required.
When you are considering adding custom claims, we recommend that you store any access control data you may need to include within claims as part of the user's [`app_metadata`](/docs/manage-users/user-accounts/metadata). Firstly, this prevents you from needing to call an external API to fetch the data, which can negatively impact performance and scalability. Secondly `app_metadata` **cannot** be modified by a user - so the user cannot directly circumvent any access control restrictions by modifying their own metadata. Also remember to check out our [metadata best practices](/docs/get-started/architecture-scenarios/business-to-business/profile-management#metadata) guidance too.
### Access Token scopes
[OAuth2 Scopes](/docs/get-started/apis/scopes/api-scopes) are typically used as the mechanism by which an API can determine what actions can be performed on behalf of a user. Scopes can be added on a per API basis to [define specific access permissions](/docs/get-started/apis/add-api-permissions) in the Auth0 Dashboard or through the Auth0 Management API). Scopes can also be manipulated via Auth0 extensibility (e.g. via an Action, as in this [example](/docs/get-started/architecture-scenarios/spa-api/part-2#create-a-rule-to-validate-token-scopes)). The scopes an application requests for accessing an API should depend on what functionality the application needs the user to give permission for the application to use. Once the requested scopes are authorized, they will be returned in the Access Token which can be subsequently [verified by said API](/docs/secure/tokens/access-tokens/validate-access-tokens). A good example of this is when you log in to an application that is using a social provider for login: the social provider API requires that the application specifies whether the user will want the application to post items on your behalf. This allows the user to accept or deny this request. This example demonstrates how the user is delegating permission to the application—which is different than the API restricting access based on a user's role, and should be handled differently.
Even though you have the ability to fully manipulate Access Token Scopes via Auth0 extensibility, as a security best practice you should only remove scopes which are not authorized and refrain from adding scopes that were not requested.
Though scopes are often used as a way to enforce access permissions for a user, there are situations where it can become [tricky when you use them in this manner](https://auth0.com/blog/on-the-nature-of-oauth2-scopes/). We therefore recommend that you use scopes for their intended purpose (i.e. delegating permission to an application) and use [custom claims](#access-token-claims) for your role-based or other access control scenarios.
## Fine Grained Authorization (FGA)
[Fine Grained Authorization](https://docs.fga.dev/fga-concepts) allows you to grant individual users access to a specific resource or object based on:
* A user's role within an organization, such as `editor` or `admin`
* An attribute of the user or object, such as `manager` for a user or `marketing` for an object
* A relationship between a user and an object, such as a user with view access to a parent folder also has view access to the child folder
With FGA, you can create an authorization model to determine what relationship you want to determine user access.
## Role Based Access Control (RBAC)
Auth0 has out-of-box support for Role Based Access Control ([RBAC](/docs/manage-users/access-control/rbac)). RBAC refers to assigning permissions to users based on their role within an organization, and provides for simpler access control by offering a more manageable approach that is less prone to error.
The core RBAC feature can be used in many multi-organization scenarios. See [Organization Data in an Access Tokens](#organization-data-in-an-access-token) for more information on how to ensure your setup can support your RBAC needs.
## Machine-to-Machine (M2M) Authorization
There are many scenarios that require an application without any user-interactive session to obtain an access token in order to call an API. In such scenarios you must authenticate the client instead of the user, and OAuth 2 provides the [client credentials](/docs/get-started/authentication-and-authorization-flow/client-credentials-flow) grant type to make this easy to achieve. Some common examples of where this is required include:
* A cron job or other service that needs to communicate with your API (e.g. where a daily report needs to be generated and emailed it to an administrator).
* A separate API the supports privileged access (e.g. the API is not exposed to users directly, but instead to a backend only).
* In certain microservice architectures, where some API layers need to communicate to other API layers without a user involvement, or after a user token has expired.
* A privileged API that may need to be called before a user has authenticated (i.e. from an Action or custom DB script in your Auth0 tenant)
Traditionally, a special "service account" would have been created in order to cater for these scenarios: a user with a username and password that was configured for services which supported non-interactive use cases. That is no longer a recommended approach for many reasons, and the current best practice is to use [OAuth 2.0 Client Credentials Grant](/docs/get-started/authentication-and-authorization-flow/client-credentials-flow) in these situations.
## Organization Data in an Access Token
If you have a separate API from your application in your system that supports your multi-organization application, it is important to restrict operations to only the organization that the token was generated for. This requires that there is some sort of information in the access token to tell the API which organization the access token was issued for. This can be done in a couple of different ways depending on the answers to a couple of simple questions:
1. Will the End Users in this organization potentially have more than one organization, or is each End User isolated to a specific organization?
2. Will you be allowing any Machine-to-Machine (M2M) access to your API?
3. If you are allowing Machine-to-Machine (M2M) access to your API, Will you have any developers who need a single client ID and secret to access multiple organizations (but not all organizations)?
4. Will you be allowing the creating of third-party apps that require consent?
If End Users are isolated to a single organization **and** you will either not be allowing M2M access to your API or you will have a separate client ID/secret for each organization that needs access **and** you will not be allowing third-party apps that require consent, then the simplest approach is to just create a custom claim in the access token [using Actions for the user based tokens](#access-token-claims) and [using the client credentials hook for M2M calls](#machine-to-machine-m2m-authorization). You can store organization name in client metadata and extract it from Actions or hooks to include in access\_token as a custom claim. RBAC will work out of the box for this approach as well as long as each End User can only belong to one organization.
If End Users have more than one organization they can belong to or you might give a single developer a client ID and secret for M2M calls to more than one organization, the best approach is to create a separate audience (a separate API instance in your Auth0 tenant) for each organization. This gives you a few nice abilities:
1. First, it allows you to pass the audience as a first-class parameter to Auth0 without having to create a custom parameter. The benefit of this is that Auth0 will help enforce the existence of the audience, and it will pass it to your Actions. It will also ensure that an issued refresh token will only work for the specific audience it was originally issued to.
2. It allows you to restrict client grants to only specific organizations out of the box. The alternative is to create a more complicated client credentials hook to attempt to retrieve the restrictions from somewhere else and also require a much more complex and potentially troublesome way to tell the client credentials call which organization to issue the access token for.
3. This also allows you to use the core RBAC feature with Auth0 and ensure that the End Users who have access to more than one organization can have a potentially different role for each organization.
## Project Planning Guide
We provide planning guidance in PDF format that you can download and refer to for details about our recommended strategies.
[B2B IAM Project Planning Guide](https://assets.ctfassets.net/cdy7uua7fh8z/63F0WOPJdVzsPMxV1Xvp8x/7a329487c5e890d8e820f6a48983b46a/B2B_Project_Planning.pdf)
## Multiple Organization Architecture (Multitenancy)
Many B2B platforms implement some form of isolation and/or branding for their customers' organization, and this can add complexity to any Identity and Access Management (IAM) system. If this applies to you, then we recommend you take some time to read through our guidance and best practice advice for this type of environment.
[Multiple Organization Architecture](/docs/get-started/architecture-scenarios/multiple-organization-architecture)
# Business-to-Business Branding
Source: https://auth0.com/docs/get-started/architecture-scenarios/business-to-business/branding
How to configure Auth0 items to reflect your brand and desired user experience.
Auth0 can be customized with a look and feel that aligns with your organization's brand requirements and user expectations. Branding Auth0 collateral provides a consistent user experience for your customers, and gives them peace of mind that they’re using a product from a trusted and secure provider.
Auth0 provides support for [internationalization (I18N)](/docs/customize/internationalization-and-localization) and localization (L10N), both of which are important if you work on branding for an international clientele. Out-of-box collateral, such as the Auth0 Lock UI widget and Universal Login, comes ready enabled for multiple language support, with built-in extensibility for adding more languages if what you require [doesn’t already exist](/docs/customize/internationalization-and-localization/lock-internationalization).
Almost all applications need Internationalization and/or Localization in one form or another. Auth0 makes it easy to add, but you need to account for it up front: retro-fitting localization, for example, can be a painful process if left too late.
When considering the items you want to brand, as well as how best to brand them, there are a number of things you'll want to review:
* Do you need to brand your login page?
* Do you need to localize your login page?
* If you are sharing an Auth0 tenant across customer organizations, should you add organization-specific branding to their login experience?
* How can you customize emails so that they're not just branded, but vary based on user preference?
* How will users know that they're still on your domain when they see your login page?
* What do you need to do to provide additional browser security (e.g., implement Extended Validation)?
* Where do you want to direct users in the event of errors?
Auth0 provides tremendous flexibility when it comes to customizing and configuring Auth0 pages such as [Universal Login](#universal-login-and-login-pages) and [Password Reset](#password-reset-page-customization). So you can pretty much set up whatever UX look and feel you require. For many, the out-of-the-box experience - with perhaps a little alteration - is all that's required. However, for others the value of their brand and brand awareness requires more extensive customization. This flexibility extends to not only Auth0 pages, but via extensibility can also be applied to the [email templates](#email-template-customization). Auth0 [Custom Domain](#custom-domain-naming) functionality further enhances consumer awareness by providing users with the confidence and peace of mind when it comes to safety and security.
If you are sharing an Auth0 tenant across multiple customer organizations, providing each organization with their own domain of users and managing their credentials, you will need to consider how each user will know which credentials they should use and how they will trust that they are entering them somewhere safe and secure. See [Branding login by organization](#branding-login-by-organization) for details.
While Auth0 provides for default information when it comes to error situations, out-of-the-box information can be somewhat cryptic as the context that can only be provided by you is missing. Auth0 [error page customization](#error-page-customization) guidance can however help mitigate that by allowing you to provide information of a more context-specific nature via your own support organization.
To provide helpful resources for users who experience problems, you should also configure a friendly name and a logo, as well as provide the support email address and URL for your organization. To learn how, see [Dashboard Tenant Settings](/docs/get-started/tenant-settings#settings).
## Universal login and login pages
[Universal Login](/docs/authenticate/login/auth0-universal-login) is the recommended method for authenticating users, and it centers around use of the Login page. You can customize the Login page to support your organization's branding requirements.
To customize Universal Login pages, you can modify your [page themes](/docs/customize/login-pages/universal-login/customize-themes) as well as create dynamic [page templates](/docs/customize/login-pages/universal-login/customize-templates).
If you choose to implement [Classic Login](/docs/authenticate/login/auth0-universal-login/universal-login-vs-classic-login/classic-experience) and customize the Login page script, we strongly recommend that you make use of version control. To do this, you should deploy the script to your Auth0 tenant via [deployment automation](/docs/get-started/architecture-scenarios/business-to-business/deployment) or via one of the [alternative strategies](/docs/customize/login-pages/classic-login/version-control).
## Branding login by organization
Whether or not you need to do special customization on the Universal Login page is determined by how you plan to manage your customers’ organization. Before reading through this section, make sure you have read through the [Universal Login section](#universal-login-and-login-pages) and know how you are approaching organizations by reviewing [Multiple Organization Architecture](/docs/get-started/architecture-scenarios/multiple-organization-architecture).
If your organization users will all be isolated from each other, it’s important to make it clear on the Universal Login page which organization the login page is for. The easiest way to do this is to use the [Organizations Feature](/docs/manage-users/organizations/create-first-organization) which provides you a way to store logo, primary color, and background color which will be used to customize the branding on the Universal Login Page once the organization has been identified either by passing org\_id from the application or the user entering their organization at the organization prompt.
## Custom domain naming
By default, the URL associated with your tenant will include its name and possibly a region-specific identifier. For example, tenants based in the US have the a URL similar to `https://example.us.auth0.com` while those based in Europe have something that is of the fashion `https://example.eu.auth0.com`. A [Custom Domain](/docs/customize/custom-domains) offers a way of providing your users with a consistent experience by using a name that’s consistent with your organization's brand.
Only one custom Domain Name can be applied per Auth0 Tenant, so if you absolutely must have independent domain name branding then you will require an [architecture](/docs/get-started/architecture-scenarios/business-to-consumer/architecture) where multiple Auth0 Tenants are deployed to production.
In addition, Custom Domain functionality offers you complete control over the certificate management process. By default, Auth0 provides standard SSL certificates, but if you configure a custom domain, you can use Extended Validation (EV) SSL certificates or similar to provide the visual, browser-based cues that offer your visitors additional peace of mind.
In general, we see customers having the most success when they use a centralized domain for authentication - this is especially the case if the company offers multiple products or service brands. By using a centralized domain, you can provide end users with a consistent user experience while also minimizing the need to maintain multiple production tenants in Auth0.
If your customer organizations will be isolated from each other, and you require that users are presented a login page for each organization via a custom domain URL, then your only option is to create a separate tenant for each organization.
## Email template customization
Auth0 makes extensive use of email to provide both user notifications and to drive the functionality needed for secure identity management (for example, email verification, account recovery, and brute force protections), and Auth0 provides a number of templates for these.
Before customizing email templates, please set up your [Email Provider](/docs/get-started/architecture-scenarios/business-to-business/operations#email-provider-setup).
Out of the box, the email templates used contain standard verbiage and Auth0 branding. However, you can configure almost every aspect of these templates to reflect the verbiage and user experience you want and make changes to things like the preferred language, accessibility options, and so forth.
Email templates are customized using [Liquid syntax](/docs/customize/email/email-templates/use-liquid-syntax-in-email-templates). If you are interested in customizing your templates based on user preferences, you will also have access to the [metadata](/docs/manage-users/user-accounts/metadata) located in users' profiles, as well as any specific application metadata too.
## Password reset page customization
The [Password Reset](/docs/customize/login-pages/classic-login/customize-password-reset-page) page is used whenever a user takes advantage of password change functionality and, as with the login page, you can customize it to reflect your organization's particular branding requirements.
If your organization users will all be isolated from each other (i.e, each organization gets its own Auth0 [database connection](/docs/authenticate/database-connections)), and you are branding the [Universal Login](#universal-login-and-login-pages) pages by organization, then it's also important to brand things like the password reset page so users know for which organization the password change is occurring. This can be done in a couple of ways:
* Create JavaScript on the Password Reset page that can pull resources from a CDN based on the connection parameter that indicates from which organization the user is coming.
* Create a separate tenant for an organization and use Universal Login to customize what is required for that organization.
## Error page customization
If there are issues encountered during user interactive workflow (e.g. user sign up or login), Auth0 provides error messages that indicate what the problem is under the hood. The default messages are somewhat cryptic, especially to the end user, since they will likely be missing context that only you can supply. As such, we recommend [customizing your error pages](/docs/customize/login-pages/custom-error-pages) to provide the missing context-specific information directly to your users. Furthermore, customizing your error pages allows you to display your branding, not Auth0's, as well as provide useful information to your users as to what should be done next. This information might include a link to a FAQ or how to get in touch with your company's support team or help desk.
Out-of-the-box there is no user interface for customizing Auth0 provided error pages, but you can use the [Tenant Settings endpoint of the Management API](https://auth0.com/docs/api/management/v2#!/Tenants/patch_settings) to configure them. Alternatively, if you can create and host your own error page, then you can have Auth0 direct users to that page instead of using the Auth0-hosted option.
## Guardian multi-factor page customization
The Multi-factor Authentication pages can be customized by adjusting the Universal Login branding options in the [Universal Login Settings](https://manage.auth0.com/#/login_settings) section.
If you need further customization, you can also customize [the full HTML content](/docs/secure/multi-factor-authentication/customize-mfa/customize-mfa-classic-login) to reflect your organization's particular UX requirements.
## Project Planning Guide
We provide planning guidance in PDF format that you can download and refer to for details about our recommended strategies.
[B2B IAM Project Planning Guide](https://assets.ctfassets.net/cdy7uua7fh8z/63F0WOPJdVzsPMxV1Xvp8x/7a329487c5e890d8e820f6a48983b46a/B2B_Project_Planning.pdf)
# Business-to-Business Deployment Automation
Source: https://auth0.com/docs/get-started/architecture-scenarios/business-to-business/deployment
Automate deployment of Auth0 tenant configuration across your development, test, and production tenants using the Deploy CLI or source control extensions, keeping B2B environments consistent while managing environment-specific values safely.
In addition to adopting best practices for change management and [QA](/docs/get-started/architecture-scenarios/business-to-business/quality-assurance), successful customers will also integrate Auth0 collateral management as part of some automated deployment process. As discussed in the Architecture section under [SDLC support](/docs/get-started/architecture-scenarios/business-to-business/architecture#sdlc-support), you will want to ensure you configure separate Auth0 tenants for development, testing, and production environments, and you will want that configuration to be almost identical for the tenant in each environment. Using deployment automation helps ensure this, so that each environment tenant is configured the same, and you will be less likely to see bugs show up as a result of mismatched configurations between environments.
However you configure deployment automation, we’d recommend you unit test your rules, custom DB scripts, and hooks prior to deployment, and run some integration tests against your tenant post-deployment too. For more details regarding this, see the [Quality Assurance](/docs/get-started/architecture-scenarios/business-to-business/quality-assurance) guidance provided.
Auth0 provides support for a couple of different options when it comes to the deployment automation approaches you can use, and each can be used in conjunction with the other if desired:
* The [Auth0 Deploy CLI tooling](/docs/deploy-monitor/deploy-cli-tool) provides you with an easy-to-use script that can help you integrate with your existing Continuous Integration/Continuous Deployment (CI/CD) pipeline.
* If you can’t integrate directly with, or for some reason you don’t have a CI/CD pipeline, then the Auth0 [Source Control Extensions](/docs/customize/extensions) can provide an easy-to-set-up basic automation process with very low maintenance.
Both the Deploy CLI Tool and source control extensions can cause destructive changes; manual changes made directly in the dashboard between automated deployments could be lost! For this reason, if either is used, then **all** changes should be deployed from the source control subsystem referenced via the tooling and not made manually.
Each environment may also need some environment-specific configuration--Application Client ID’s and Client Secrets will be different between the Auth0 tenants, for example--so you’re going to want some way of being able to dynamically reference this rather than having hard-coded values. Auth0 provides support for handling environment-specific configuration information through one of the following two approaches:
* Use [Tenant-specific variables](#tenant-specific-variables)
* Use keyword replacement if using the Auth0 Deploy CLI tool
## Tenant-specific variables
Auth0 allows you to configure variables that are available from within custom [extensibility](/docs/customize/extensions); these can be thought of as environment variables for your Auth0 tenant. Rather than hard code references that change when moving code between development, test, and production environments, you can use a variable name that is configured in the tenant and referenced by the custom extensibility code. This makes it easier for the same custom code to function, without changes, in different tenants because the code can reference variables that will be populated with tenant-specific values at execution time:
* For use of variables in Actions, read [Write Your First Action](/docs/customize/actions/write-your-first-action) to learn how to configure secrets in the editor
* For use of variables in Rules, see how to [configure values](/docs/customize/rules/configuration)
* For use of variables in Hooks, see how to [configure secrets](/docs/customize/hooks/hook-secrets) in the editor
* For use of variables in Custom DB Scripts, see the [configuration parameters](/docs/authenticate/database-connections/custom-db/create-db-connection#step-3-add-configuration-parametersn#step-3-add-configuration-parameters)
We recommend using variables to contain tenant-specific values as well as any sensitive secrets that should not be exposed in your custom code. If your custom code is deployed in GitHub/Gitlab/Bitbucket/VSTS, then using a tenant-specific variable avoids exposure of sensitive values via your repository.
## Project Planning Guide
We provide planning guidance in PDF format that you can download and refer to for details about our recommended strategies.
[B2B IAM Project Planning Guide](https://assets.ctfassets.net/cdy7uua7fh8z/63F0WOPJdVzsPMxV1Xvp8x/7a329487c5e890d8e820f6a48983b46a/B2B_Project_Planning.pdf)
## Multiple Organization Architecture (Multitenancy)
Many B2B platforms implement some form of isolation and/or branding for their customers' organization, and this can add complexity to any Identity and Access Management (IAM) system. If this applies to you, then we recommend you take some time to read through our guidance and best practice advice for this type of environment.
[Multiple Organization Architecture](/docs/get-started/architecture-scenarios/multiple-organization-architecture)
# Business-to-Business Launch Preparation
Source: https://auth0.com/docs/get-started/architecture-scenarios/business-to-business/launch
Prepare your Auth0 B2B implementation for launch by working through tenant checks, testing, operations, compliance, and support readiness so your team can assign owners and confirm everything is production-ready before going live.
Use this guide as you prepare for the launch of your application. We’ve included reminders about some content you may have viewed earlier during your planning or development phases as well as some new content unique to the launch phase. The sections below are useful to developers and project owners to ensure that you have everything lined up for a smooth launch. There are several things to check so it may help to assign ownership of different sections to different members of your team.
# Compliance Readiness (B2B)
Source: https://auth0.com/docs/get-started/architecture-scenarios/business-to-business/launch/compliance-readiness
Compliance checks to perform before launch of your B2B IAM implementation.
There are several requirements related to privacy and compliance. Auth0 cannot provide legal guidance on your privacy or other regulatory obligations, but we can provide a curated list of privacy requirements below for which Auth0 offers features that may help you meet your obligations. Prior to launch, you should check that you’ve met all your privacy obligations and review the features outlined below to ensure you’re leveraging all the available Auth0 features to help you meet your privacy and compliance requirements.
## Publish privacy policy and obtain user consent
If you collect or process personal data about users, you should have published a privacy policy and have established procedures to ensure your operations abide by the contents of the policy. You also need to obtain a user’s consent for the collection and processing of information. Auth0 provides options for [displaying a link to your privacy policy storing user consent](/docs/secure/data-privacy-and-compliance/gdpr).
## Provide access to view, correct and erase data
Privacy legislation often requires that users have the right to view and correct any data held about them. If you are a data controller, you should provide a mechanism for this. Auth0 customers can build a self-service feature to access and correct data via the management API.
## Provide access to data portability
If you are a data controller, you may be obligated to provide users a means to export their data from your system in a transportable format. Auth0 provides user data portability mechanisms to help you satisfy this obligation via both manual export capabilities and the Management API which enables you to implement a self-service feature for users.
## Take steps to minimize personal data
You should have reviewed the personal data you collect about users to ensure it is legitimately required for the purposes of the processing covered in the privacy policy and consent. You should also confirm you have minimized the data you collect, and established a data retention policy. You can optionally elect to encrypt data you store in user metadata for additional protection.
## Data retention policy enforcement automated
You should have a published data retention policy and automate the enforcement of it. The Auth0 management API or the Auth0 dashboard can be used to facilitate [erasure of user accounts](/docs/secure/data-privacy-and-compliance/gdpr/gdpr-right-to-access-correct-and-erase-data).
## Protect personal data
Regardless of whether you are a data controller or a data processor, you have obligations to protect the personal data you hold about users. This includes use of encryption where possible, and implementing reasonable security measures to protect user accounts. Prior to launch, you should check if you are using all the security features available from Auth0 to help with this such as Brute Force Detection, Multi-Factor Authentication (for both users and administrators), and a strong password policy if using passwords. You should also ensure you have a process ready to respond to Brute Force attacks.
## Supplier evaluation
Another common compliance obligation is to perform due diligence review of the security of any third-party suppliers to which you expose personal data. For Auth0, you will find information to facilitate this task on the Auth0 [security and certifications](https://auth0.com/security/) page where you can view the security certifications Auth0 has obtained.
## Additional resources
Additional resources that may be useful for your compliance requirements include:
* [Auth0 Privacy Policy](https://auth0.com/privacy)
* [Security and Compliance](https://auth0.com/security/)
* [Auth0 Compliance and Certifications](/docs/secure/data-privacy-and-compliance)
* [Auth0 General Data Protection Regulation Compliance](/docs/secure/data-privacy-and-compliance/gdpr)
## Project Planning Guide
We provide planning guidance in PDF format that you can download and refer to for details about our recommended strategies.
[B2B IAM Project Planning Guide](https://assets.ctfassets.net/cdy7uua7fh8z/63F0WOPJdVzsPMxV1Xvp8x/7a329487c5e890d8e820f6a48983b46a/B2B_Project_Planning.pdf)
# Launch Day Preparation (B2B)
Source: https://auth0.com/docs/get-started/architecture-scenarios/business-to-business/launch/launch-day
Coordinate launch day for your Auth0 B2B rollout with a plan covering stakeholder notifications, cutover and rollback steps, go/no-go critera, standby contacts, and success metrics to keep go-live smooth and reversible.
## Notifications / announcements
It helps a launch go smoothly if all stakeholders are aware of the impending launch and understand the launch plan as well as their role and responsibilities. In addition to notifying teams that will be actively involved, it can help to notify teams that might be needed if anything goes wrong. Having someone on standby during a launch can help expedite response. Be sure to identify and notify any team that might need to answer questions from customers, including on social media.
### Parties to notify
* Customers
* Business parters, if applicable
* Application team(s) impacted by launch
* Support teams
* Network teams (network changes, on standby, in case of issues)
* Security teams (on standby, in case of issues)
* Marketing teams (ready for announcements, response to issues)
* Social media teams (ready to monitor social media, respond)
* Sales teams (prepared to answer questions from customers)
* Customer success teams (prepared to answer questions from customers)
## Notification plan
Your notification plan should include elements such as the target audience, the key takeaways for the audience, the message content, the plans for distributing the notification and how to test the messaging.
A list of elements to include in the plan are:
* Target audience (consider both internal & external audiences)
* Message
* Timing
* Dependencies
* Responsible parties (who will send it)
* Mechanism (how it will be communicated)
* Test message and delivery (if applicable - test to ensure notifications sent)
## Notification distribution
A common tactic is to release notifications in batches to spread out the initial onslaught of load and reduce the scope of confusion if there are any unforeseen glitches. It’s easier to correct issues with a small group than during a big-bang launch.
* One approach is to start with a relatively small batch of notifications, and if no issues are identified, increase the size of the batches over time.
* You can also send out batches on a rolling schedule around the globe to spread out load hitting the system at once and have notifications arrive at an optimal time within each timezone to increase the likelihood of the messages being read.
* You can do a soft-launch to a portion of users, such as individual customers, regions or some other grouping that makes sense for your application.
## Outage windows (if needed)
Some organizations require a formal request for an outage window if any outages or downtime is required for a launch. If your organization requires this, be sure to identify if any downtime is required for the cutover or launch (or other dependent systems) and file the necessary outage or change requests in advance of any lead-time requirements.
## Cutover plan (if needed)
Some launches involve cutover from a previous solution to a new solution. If your project fits this scenario, you should be sure to identify everything that needs to happen as well as any dependencies, the responsible party for each task, and necessary timing. You may wish to plan alternates for all important roles or in each region in case anyone is unexpectedly sick or otherwise unavailable. A checklist of items to consider for the cutover plan is:
* Have you documented the cutover plan and rollback plan if needed?
* Are backups needed of anything prior to change?
* Are any preparatory data changes required?
* Any DNS records to be changed?
* Any Firewall changes?
* Any new monitoring targets?
* Any software to be deployed?
## Go / no-go criteria
In your overall launch plan, it is helpful to have go/no-go criteria and to have discussed in advance the types of issues which could occur and which could be worked through vs would require reverting. A launch plan can specify periodic check-in timeframes with criteria of what to assess at each checkpoint and how long to allow an issue to continue unresolved.
For each stage of the launch, it helps to have success criteria defined, that indicate the launch is proceeding as planned and can continue. Some example criteria could be:
* User signups growing with minimal errors
* User logins at expected rate, minimal errors
* Reported support issues below a certain threshold
* No issues identified that could lead to corrupted data
It’s also helpful to have identified criteria which could trigger a “no-go” decision to halt the launch. The risk tolerance for each environment varies, but a few example criteria might include:
* High percent of user signup or login resulting in errors that cannot be resolved quickly
* High number of support issues that cannot be resolved quickly
* Condition identified that could lead to data corruption
* High severity security issue discovered
## Rollback
It is always wise to have a plan for how to rollback or revert a launch, just in case something unforeseeable occurs which cannot be resolved. Reviewing the launch plan for every step which involves a change can help identify the tasks or changes requires to revert a launch or cutover.
The rollback plan should include the steps to take, the sequence, how long each is likely to take and the responsible party. Understanding the cumulative time required to roll back can help to determine the timing of the final go/no-go decision to fit within any required outage window.
If any data is migrated or changed for the launch, the plan should include how to revert it, if needed. Reverting may require running scripts to undo operational changes or restoring a data store from a backup taken before the launch process began.
It is also necessary to plan for the case where some data is entered into a new system before it has to be reverted. Will such data / transactions need to be abandoned with the rollback or will you have a way to capture and apply them elsewhere so they aren’t lost?
If the resolution of issues or process to revert could potentially take longer than one shift, you’ll want to ensure you have a primary and perhaps a secondary person available and prepared to handle things during each work shift. If an issue results in the need for prolonged response, significantly beyond one shift, there are limits for how long people can realistically function without a break. It can help to be prepared with resources for a follow-the-sun issue response effort if needed.
## Standby contacts
As the launch day approaches, it’s a good idea to identify all contacts who might be needed for troubleshooting or resolving issues and request them to be on standby and ready to help if needed. The launch leader should have contact information for each person on the standby list to expedite communications.
If there is a physical or virtual "launch room", the people on standby should know where it is and be ready to join if needed. Having a central room or video conference prepared can expedite communications and troubleshooting across all parties if an issue occurs.
## Success Criteria
A lot of planning goes into a launch in order to be successful, but will you know how to evaluate the launch? If you define success criteria before the launch, you can determine what to monitor and if any additional monitoring or checks need to be in place to evaluate the launch. For example - if one element of the success criteria is the number of sign-ups or logins - do you have a way of monitoring that and has it been tested to ensure it is accurate?
You’ll want statistics to be able to trumpet the success of your launch. You don’t want to find out after the launch that you didn’t capture any data to quantify all the hard work your team put into the launch.
## Risks & mitigations plan
It’s no fun to think of things that could go wrong, but if anything happens, you’ll be glad you did as having a plan can expedite response. A few examples to plan for include:
* Software application bug
* Application incompatibility with user browser settings
* Network failure/outage
* DoS attack
* Hosting environment failure
* Load / capacity issues
* Data / corruption issues
* Security vulnerability discovered
If you had a beta period, it may help to review the results of the beta to identify additional possible failure scenarios.
## Project Planning Guide
We provide planning guidance in PDF format that you can download and refer to for details about our recommended strategies.
[B2B IAM Project Planning Guide](https://assets.ctfassets.net/cdy7uua7fh8z/63F0WOPJdVzsPMxV1Xvp8x/7a329487c5e890d8e820f6a48983b46a/B2B_Project_Planning.pdf)
# Operations Readiness (B2B)
Source: https://auth0.com/docs/get-started/architecture-scenarios/business-to-business/launch/operations-readiness
Operations checks to perform before launch of your B2B IAM implementation.
## Status
You should ensure your operations staff knows how to monitor Auth0 service status and has set up a means to subscribe to updates on Auth0 status.
The Auth0 [status dashboard](https://status.auth0.com/) together with the Auth0 [uptime dashboard](http://uptime.auth0.com/) shows current and past status of the Auth0 service in a human-readable format. If any monitoring alerts are triggered, and as a first step in troubleshooting, your operations staff should check the status dashboard to see if there is a current outage. The public cloud status page also provides a facility for subscribing to outage notifications, and we also recommend that you check the status of any third-party [external services](/docs/deploy-monitor/monitor/check-external-services-status) you depend on, such as Social Providers. Having this information handy can help quickly eliminate possible causes when troubleshooting an issue and should be at the top of a troubleshooting checklist for developers as well as the help desk staff.
### Best Practice
Information on how to check the status of Auth0 as well as any dependent services (such as Social Providers) should be at the top of a troubleshooting checklist for both developers and helpdesk staff, and we recommend you subscribe via the Auth0 status page to set up notification of any status updates.
In the event of an outage to the public cloud service, Auth0 performs a Root Cause Analysis (RCA) and publishes the results on the Auth0 status page. Auth0 performs a thorough investigation after an outage—including a determination of root cause, as well as contributing factors and how to prevent the issue from occurring again—and as a result, an RCA document can take a few weeks to be published.
## Email provider setup
You should double check that you have set up your own email provider to support production volumes of emails that might be sent to customers for signup, email validation, account recovery and the like.
Auth0 sends [emails](/docs/customize/email) to users for events such as signup welcome, email validation, breached password, and password reset events. You can customize the email templates for each type of event, and advanced customization of email handling is also possible. Auth0 provides a test email provider with limited capacity for basic testing, but you must set up your own email provider for production use, and customization of email templates will not work until you have established your own provider.
### Best Practice
The default Auth0 email provider does not support sending production volumes of email or customization of email templates. You should therefore configure your own email provider before deploying to production.
## Infrastructure
### Firewalls
If custom code executing in Auth0 (such as in an Action, Rule, Hook, or custom database scripts) will call a service inside your network, or if you configure an on-premise SMTP provider in Auth0, then you may need to configure your firewall to allow [inbound traffic from Auth0](/docs/secure/security-guidance/data-security/allowlist). The IP addresses to allow through the firewall are specific to each region and are listed on the Rules, Hooks, custom database scripts, and email provider configuration screens in your Auth0 dashboard.
## NTP
If this is not handled automatically by your hosting environment, you should have scripts which will automatically restart NTP (Network Time Protocol) if it fails and alerts that will notify someone if NTP is not running. Authentication transactions rely on accurate system time because security tokens may be evaluated as expired when received if there are time discrepancies between sending and receiving systems.
## LoadBalancer timeouts checked
If you use the AD/LDAP connector, you should check the load balancer settings in your environment to see if they terminate long running connections that are inactive. If they do, you can modify the [Auth0 AD/LDAP Connection settings](/docs/authenticate/identity-providers/enterprise-identity-providers/active-directory-ldap/ad-ldap-connector/ad-ldap-connector-to-auth0) to use the `LDAP_HEARTBEAT_SECONDS` setting to send periodic heartbeat messages to keep the connection open.
## LoadBalancer configuration
If your application maintains server state such that it depends on sticky load balancing to route users to a particular server, it can be beneficial to double check that all load balancer configurations are correct. One load balancer in a pool that is out of sync can cause intermittent errors that are hard to troubleshoot. A quick check of load balancer configuration can avoid such issues in the first place.
## Logs
You should check that you have set up the ability to capture log data, that logs are covered by your data retention policy and you have mechanisms to enforce logs data retention limits. You should also make sure that your development, support, and security teams know how to access logs data for troubleshooting and forensics purposes. Exporting log files to services that provide comprehensive analytics can help you identify patterns such as usage trends and errors.
Auth0 provides extensive capability when it comes to the logging of events, and also in the scanning of logs in order to identify event anomalies (see [logs documentation](/docs/deploy-monitor/logs) for further details). Standard log retention period for Auth0 logs is determined by subscription level with the shortest period being 2 days and the longest period being only 30 days. Leveraging Auth0 support for integrating with external logging services will allow you to retain logs outside of this, and will also provide for log aggregation across your organization.
### Best Practice
You should leverage one of the log streaming solutions to send log data to an external log analytics service. This will enable keeping data for longer periods of time and provide advanced analytics on the log data.
You should review the log data [retention period](/docs/deploy-monitor/logs/log-data-retention) for your subscription level, and implement a log data export extension to send log data to an external log analytics service. You can use one of our [log streaming solutions](https://marketplace.auth0.com/features/log-streaming) in Auth0 Marketplace.
Development teams can use log files for troubleshooting and detecting intermittent errors that may be hard to find via QA tests. Security teams will probably want log data in case forensic data is ever needed. Exporting log files to services that provide comprehensive analytics can help you see patterns such as usage trends and attack protection triggers.
### Rate limits and other errors
Auth0 provides a unique error code for errors reported when the [rate limit is exceeded](/docs/troubleshoot/customer-support/operational-policies/rate-limit-policy). You should set up automatic scanning of logs to check for rate limit errors so you can proactively address activity that hits rate limits before it causes too much trouble for your users. Auth0 also publishes error codes for other types of errors, and you will find it helpful to scan logs for [authentication errors](/docs/libraries/common-auth0-library-authentication-errors) as well as errors from Auth0 Management API calls (Management API error codes are shown below each call in the [Management API Explorer](https://auth0.com/docs/api/management/v2)).
### Best Practice
Calling the Management API to retrieve user profile information from within a Rule is a common cause of rate limit errors because such API calls can execute for every login as well as periodic session checks.
## Monitoring
Be sure to set up proactive monitoring of the Auth0 service as well as end-to-end authentication through your application.
You should establish mechanisms for [monitoring Auth0 implementations](/docs/deploy-monitor/monitor), so your support or operations team receives the timely information needed to proactively handle service outages. Auth0 provides monitoring endpoints that can be incorporated into your monitoring infrastructure. These endpoints are designed to provide a response suitable for consumption by monitoring services. It should be noted that they only provide data on Auth0. For complete end-to-end monitoring, which is essential for checking the ability of users to log in, we recommend that you set up [synthetic transaction monitoring](/docs/deploy-monitor/monitor/monitor-applications). This will provide greater granularity for your monitoring and enable you to detect outages unrelated to Auth0 as well as degradation of performance, so you can respond more proactively.
### Best Practice
You should set up the ability to send synthetic login transactions to facilitate end-to-end monitoring of authentication. You can do this with a simple application that uses the [Resource Owner Password Grant](/docs/get-started/authentication-and-authorization-flow/resource-owner-password-flow/call-your-api-using-resource-owner-password-flow) in combination with a test user that has no privileges, and don’t forget about [Auth0 rate limiting policies](/docs/troubleshoot/customer-support/operational-policies/rate-limit-policy) too.
## Auth0 Notifications
You should ensure your team is monitoring all of the following communication channels from Auth0 to stay abreast of important announcements and changes.
There are several different types of notifications from Auth0 that you should watch for as they contain important information that could impact your tenant(s) and project.
Proactive security notifications and other operational announcements are sent by Auth0 to dashboard administrators. You should ensure that the people who need to receive such messages are dashboard administrators.
### Dashboard notifications
From time to time, Auth0 may send an important announcement related to your tenant. These announcements about your service will be sent to your Auth0 dashboard and depending on the severity of the announcement, via email to the registered Auth0 dashboard administrators. You should make a regular practice of logging in to the dashboard and checking the bell icon at the top for any important notices. In addition, you should review emails from Auth0 in a timely fashion as they may convey important information about changes or actions you need to take.
### Change log
Auth0 provides information on changes to the service in the Auth0 [change log](https://auth0.com/changelog). You should make a regular practice of reviewing Auth0 change logs to be aware of changes. Support teams researching an issue may find it useful to review the change log to determine if recent changes might be related, especially if these are breaking changes. Development teams will also want to review the change logs to identify new features that may be beneficial.
In addition, you should periodically check the [Auth0 migrations page](/docs/troubleshoot/product-lifecycle/deprecations-and-migrations) for news about upcoming deprecations that might require your team to make changes.
## Automated deployment, version control
While not required, we recommend you set up automated deployment with version control. Using automation to deploy or revert changes to the dev, test, and production environments enables you to respond more efficiently to issues post-launch.
In addition to adopting best practices for change management and [QA](/docs/get-started/architecture-scenarios/business-to-consumer/quality-assurance), successful customers also integrate Auth0 collateral management as part of an automated deployment process. As discussed in the Architecture section under [SDLC support](/docs/get-started/architecture-scenarios/business-to-consumer/architecture#sdlc-support), you should configure separate Auth0 tenants for development, testing, and production environments, where the tenant configuration is the same in each environment. Using deployment automation helps ensure that tenant configuration is consistent across environments, which reduces bugs and other issues.
### Best Practice
However you configure deployment automation, we’d recommend you unit test your rules, custom DB scripts, and hooks prior to deployment, and run some integration tests against your tenant post-deployment too. For more details regarding this, see the [Quality Assurance](/docs/get-started/architecture-scenarios/business-to-consumer/quality-assurance) guidance provided.
Auth0 provides support for the following deployment automation approaches, which can be used in conjunction if desired:
* The [Auth0 Deploy CLI tooling](/docs/deploy-monitor/deploy-cli-tool) provides an easy-to-use script that integrates with your existing Continuous Integration/Continuous Deployment (CI/CD) pipeline.
* Auth0 [Source Control Extensions](/docs/customize/extensions) provides an easy-to-set-up basic automation process with very low maintenance if you don't have a CI/CD pipeline, or in cases where you cannot directly integrate with a CI/CD pipeline.
* If your development workflow leverages [Terraform](https://www.terraform.io/), [Auth0 Terraform Provider](/docs/deploy-monitor/auth0-terraform-provider) helps you manage your Auth0 tenant configurations.
Note that both the Deploy CLI Tool and source control extensions can cause destructive changes; manual changes made directly in the dashboard between automated deployments could be lost! For this reason, if either is used, then **all** changes should be deployed from the source control subsystem referenced via the tooling and not made manually.
Each environment may also need some environment-specific configuration—Application Client ID’s and Client Secrets will be different between the Auth0 tenants, for example—so you’re going to want some way of being able to dynamically reference this rather than having hard-coded values. Auth0 provides support for handling environment-specific configuration information through one of the following two approaches:
* Use [Tenant Specific Variables](#tenant-specific-variables)
* Use [keyword replacement](/docs/deploy-monitor/deploy-cli-tool/configure-the-deploy-cli) if using the Auth0 Deploy CLI tool
## Tenant-specific variables
Auth0 allows you to configure variables that are available from within custom [extensibility](/docs/customize/extensions); these can be thought of as environment variables for your Auth0 tenant. Rather than hard code references that change when moving code between development, test, and production environments, you can use a variable name that is configured in the tenant and referenced by the custom extensibility code. This makes it easier for the same custom code to function, without changes, in different tenants as the code can reference variables which will be populated with tenant-specific values at execution time:
* For use of variables in Actions, see [Write Your First Action](/docs/customize/actions/write-your-first-action) to learn how to configure secrets in the editor
* For use of variables in Rules, see how to [configure values](/docs/customize/rules/configuration)
* For use of variables in Hooks, see how to configure [secrets](/docs/customize/hooks/hook-secrets) in the editor
* For use of variables in Custom DB Scripts, see the [configuration parameters](/docs/authenticate/database-connections/custom-db/create-db-connection#step-3-add-configuration-parametersn#step-3-add-configuration-parameters)
### Best Practice
It’s a recommended best practice to use variables to contain tenant-specific values as well as any sensitive secrets that should not be exposed in your custom code. If your custom code is deployed in GitHub/Gitlab/Bitbucket/VSTS, then using a tenant-specific variable avoids exposure of sensitive values via your repository.
## Backup / Restore
You should have a plan and mechanism in place to support any backup/restore capability needed for your project. This can be done using the Auth0 Management API for data as well as the Automated Deployment capabilities described in the automated deployment section for Auth0 configuration.
As noted in the Auth0 [Data Tenant Restore policy](/docs/troubleshoot/customer-support/operational-policies) and [Data Transfer policy](/docs/troubleshoot/customer-support/operational-policies/data-export-and-transfer-policy), Auth0 does not restore deleted tenants or move data between tenants. Auth0 provides the Auth0 Management API to provide customers a completely flexible capability to backup, restore and move data as needed. Customers can write scripts to retrieve data from Auth0 for backup purposes, and similarly write scripts for use with the Automated Deployment capability to restore any aspect of their Auth0 configuration.
## Versions Up to Date
You should double check that all technologies in your application stack, as well as browser versions used by your users are on current, up-to-date versions as this will impact Auth0’s ability to provide support if issues arise.
* Check you are using the latest supported version of node.js in [Auth0 dashboard settings](/docs/get-started/tenant-settings).
* Check you are using a version of SDK/Libraries supported by Auth0 per the [Auth0 Support Matrix](/docs/troubleshoot/customer-support/product-support-matrix).
## Certificate rollover plan
Certificates may be used in identity deployments. To ensure a certificate expiration does not catch you by surprise, you should have a list of certificates in your environment along with the expiration dates, how you will be notified when expiration draws near and how the certificate rollover process works.
### SAML connections
For SAML connections, you obtain a certificate from the IdP and upload it to a SAML connection for the IdP in your Auth0 dashboard. When one of these certificates is about to expire, Auth0 will send email to dashboard administrators warning of the upcoming expiration. You can obtain the new certificate and upload it using the connection configuration screen.
### WS-Fed connections
For Web Service Federation (WS-Fed) connections, if you configure them by specifying an ADFS URL, any changes will be picked up by a daily update. You can trigger an update manually by visiting the connection configuration page in the Auth0 dashboard and doing a Save. If a certificate is changed at the remote IdP, Auth0 can be updated by those mechanisms or by uploading a new metadata file in the same connection configuration screen.
## Disaster Recovery / Business Continuity Plan in place
While not an absolute requirement prior to launch, it is useful to have a disaster recovery plan in place to ensure business continuity in the face of different types of disasters, including system outages and natural disasters hitting a region where critical staff is located.
## Processes documented
Another item which is not an absolute requirement, but also recommended is to ensure all processes related to Auth0 are documented. This can include the following:
* Change management for configuration
* Deployment of new changes and any automatic deployment mechanisms used, how to revert to previous version if issues found
* Certificate rollover processes, if any
* Adding or removing new Identity Providers, if applicable
* Changes to user profile structure in Auth0 or in directories Auth0 pulls from
* Adding or removing applications or APIs
* Capturing and exporting logs
* Backup/restore process you have implemented
* User management (forgotten password, lost phone)
* Root cause analysis after an incident
## Project Planning Guide
We provide planning guidance in PDF format that you can download and refer to for details about our recommended strategies.
[B2B IAM Project Planning Guide](https://assets.ctfassets.net/cdy7uua7fh8z/63F0WOPJdVzsPMxV1Xvp8x/7a329487c5e890d8e820f6a48983b46a/B2B_Project_Planning.pdf)
# Support Readiness (B2B)
Source: https://auth0.com/docs/get-started/architecture-scenarios/business-to-business/launch/support-readiness
Prepare your support team for an Auth0 B2B launch by reviewing necessary operational policied before customers go-live.
## Review Auth0 Policies
When starting to prepare for your launch, be sure to read through [Auth0 Policies](/docs/troubleshoot/customer-support/operational-policies) and prepare your production operations accordingly for any required lead times or responsibilities on your part, according to the policies.
## Review your Support plan, SLAs, Severity definitions and Support center documentation
You should review the specifics of the [support plan](/docs/troubleshoot/customer-support) you’ve purchased and the Service Level Agreements associated with it, to ensure it is adequate for your needs. If you haven’t already done so, explore the [support center](https://support.auth0.com/) and familiarize yourself with support features such as viewing suggested solutions to common issues and [filing tickets](/docs/troubleshoot/customer-support/open-and-manage-support-tickets) and viewing your quota usage. It will be helpful to review the severity level definitions for support tickets so that you file tickets with the correct severity. One important note is that it is not possible today in the Support Center to increase the severity of a support ticket. If you file a ticket for a medium-grade issue which later becomes a high severity issue, you should file a new urgent, high severity ticket that explains anything new that triggers the urgency and references the original ticket for details.
You should also ensure your development and support teams are familiar with the [Auth0 community forum](https://community.auth0.com/), discussed further below. Customers can often find answers there right away to common issues, avoiding the need to file a ticket, so it should be your first stop for technical questions.
## Review the Auth0 community forum
The [Auth0 community forum](https://community.auth0.com/) contains a wealth of information. If you have a question, chances are someone else has already asked the question on the forum. Answers are contributed by both Auth0 staff and the larger community of Auth0 users.
Important notices are posted to the community forum to help you stay abreast of important news. Be sure to check out the “Community” and “FAQ” categories. The Community category contains pro-active posts on product announcements, roadmap information, How-To videos as well as important information about any upcoming feature deprecations.
It’s a good idea to check out the Auth0 Community on a regular basis, not just when you have questions. While you are there, if you see a question you’ve already solved, please contribute your wisdom to help others!
## Gather Auth0 troubleshooting information needed for support tickets
We recommend your support team become familiar with our [troubleshooting guides](https://support.auth0.com/center/s/) specific to identity protocols and Auth0. This includes the questions to research and information to collect before posting a question on the Auth0 forum or filing a support ticket. Authentication transactions often span multiple systems so there are some specialized troubleshooting techniques that are helpful to learn.
## Have troubleshooting tools ready
Your team will doubtless have already done some troubleshooting during the development of your application, but we recommend making sure your support team is also familiar with any tools below relevant to your project. If you need to file a ticket, the Auth0 support team may ask for a HAR (HTTP Archive) file to help analyze the issue so it’s helpful for your support staff to be familiar with how to do this.
Before sharing a HAR file with anyone (including Auth0), ensure that you remove or obfuscate all sensitive data, such as:
* Confidential user information
* Personal identifiable information (PII)
* Confidential application information
To learn more, read the following articles on [Auth0 Community](https://community.auth0.com):
* [Sanitizing HTTP Traces](https://community.auth0.com/t/sanitizing-http-traces/119488)
* [How to Sanitize an HTTP Trace File Automatically](https://community.auth0.com/t/how-to-sanitize-a-http-trace-file-automatically/120583)
* [How to Manually Redact Sensitive Information](https://community.auth0.com/t/how-to-manually-redact-sensitive-information/122554)
* [HAR File is Too Large to Upload to the Support Case](https://community.auth0.com/t/har-file-is-too-large-to-upload-to-the-support-case/122488)
### Capture HAR file
A [HAR file](https://support.auth0.com/center/s/article/generate-and-analyze-har-files-to-troubleshoot-auth0-issues) captures a sequence of browser interactions and is a commonly used tool when debugging authentication issues. The process of authenticating a user often involves redirecting the user’s browser from an application to Auth0, and possibly to another remote Identity Provider, depending on the type of connection used. You can capture the redirection and the responses and analyze it to find clues about the cause of an issue.
### Analyze HAR file
Analyze the HAR file to obtain valuable troubleshooting information. It shows the sequence of browser redirects involved in an authentication transaction, along with the parameters used. The HAR file also shows if the authentication process stopped mid-stream and if so where, which helps to pinpoint the location of the issue. The HAR file contains tokens returned to the application front-end, and these can be pasted into appropriate viewers to see if they contain the expected contents.
### View JWT
The [jwt.io](https://jwt.io/) tool was written by Auth0 and allows you to view the contents of a JWT-formatted token. Applications that delegate authentication to Auth0 via OIDC will receive an ID Token from Auth0. Depending on your type of application, the ID Token may be captured in a HAR file. The ID Token is in JWT format and can be pasted into jwt.io to view the contents of the ID Token.
### View SAML request/response
There are many SAML decoders available. The [samltool.io](https://samltool.io/) decoder was written by Auth0 and allows you to view the contents of a SAML Request or Response. Applications that delegate authentication to Auth0 via SAML or use a SAML type of connection in Auth0 will use SAML Requests and Responses. These SAML Requests and Responses may be captured in a HAR file. The requests and responses can be pasted into samltool.io or other SAML decoders to view the contents of the SAML Request or Response.
## Review Auth0 support matrix
One potential cause of issues is using out of date versions of SDKs or libraries. We strongly recommend your team check your software stack, browsers, SDKs and libraries against the [Auth0 support matrix](/docs/troubleshoot/customer-support/product-support-matrix) to ensure you are running on up-to-date, supported versions. In the event of an issue, the Auth0 support team may ask you to upgrade to a supported version. To avoid slowing down progress on issue resolution, be sure you are on up-to-date versions.
## Use Auth0 feedback portal
Auth0 welcomes feedback and ideas from Auth0 customers. If you have a suggestion for our product team, you can submit product feedback directly on the [Product Feedback portal](https://auth0.com/feedback).
## Actions Real-time Logs
For debugging and supporting custom code in Auth0, including Actions, Rules, Hooks, custom database scripts, and custom OAuth connections, knowledge of the [Actions Real-time Logs](/docs/customize/actions/actions-real-time-logs) is essential. This enables you to view output from your custom code, including output from console.log statements.
We recommend using Actions Real-time Logs and getting familiar with using it to view log output from your custom code as a debugging and support tool.
## Project Planning Guide
We provide planning guidance in PDF format that you can download and refer to for details about our recommended strategies.
[B2B IAM Project Planning Guide](https://assets.ctfassets.net/cdy7uua7fh8z/63F0WOPJdVzsPMxV1Xvp8x/7a329487c5e890d8e820f6a48983b46a/B2B_Project_Planning.pdf)
# Tenant Check (B2B)
Source: https://auth0.com/docs/get-started/architecture-scenarios/business-to-business/launch/tenant-check
Tenant Checks to perform before launch of your B2B IAM implementation.
This section covers a list of configurations to check in your tenant. This should be done periodically during development and sufficiently before launch so you have time to fix anything amiss.
## General tenant check
### Tenant preparation check
Check to ensure you have set up tenant environments to support your SDLC lifecycle and that Dev, Test and Prod tenants are cleanly separated so that ongoing development work after launch doesn’t negatively impact your production environment.
Every company has some form of Software Development Life Cycle (SDLC), and throughout the development process you will want to align with that strategy. For instance, you need to be able to test your integration with Auth0 in a similar fashion as you test the applications themselves. It is therefore important to [structure Auth0 tenants to support your SDLC](/docs/get-started/auth0-overview/create-tenants/set-up-multiple-environments), and there is a consistent pattern which our customers typically follow when it comes to the best practices associated with tenant layout for doing so:
| Environment | Sample Tenant Name | Description |
| - | - | - |
| Development | **company-dev** | A shared environment where most of your development work occurs |
| QA/Testing | **company-qa** or **company-uat** | An environment for formal testing of the changes you've made |
| Production | **company-prod** | The production tenant |
In some cases you may also want to create one or more sandboxes (e.g., **company-sandbox1**, **company-sandbox2**) so that you can test changes without compromising your development environment. This might be where you test deployment scripts and the like.
### Best Practice
You can also take advantage of our [Implementation Checklists](/docs/get-started/architecture-scenarios/checklists) that you can download and customize to meet your implementation project needs.
### Tenant association check
To ensure that your [tenants are all associated with your Auth0 contractual agreement](/docs/get-started/auth0-overview/create-tenants/child-tenants) and have the same features, ensure all your tenants are associated with your company account. If you have individual developers that want to create their own sandboxes for testing, make sure they get associated with your account so they have the same permissions too. To do this you should contact your Auth0 representative or the [Auth0 Support Center](https://support.auth0.com/center/s/).
### Specify production tenant
To ensure Auth0 recognizes your production tenant, be sure to [set your production tenant](/docs/get-started/auth0-overview/create-tenants/set-up-multiple-environments#set-the-environment) with the “production” flag in the Support Center.
### Tenant production check
Auth0 provides a [Production Check](/docs/deploy-monitor/pre-deployment-checks) facility to detect many common errors. You should ensure this has been run and any findings from the report mitigated before launch.
In addition, you should check the [best practice configurations advice](/docs/deploy-monitor/pre-deployment-checks/production-checks-best-practices), for which checking cannot be automated.
### Tenant settings check
#### Tenant settings
Make sure to follow the Auth0 [tenant settings](/docs/get-started/tenant-settings) recommendations in configuring your logo as well as your support email and support URL so users know how to get help if an issue occurs. You'll want to check your SSO Session Timeout settings and the list of dashboard admins with access to your production tenant as well.
#### Error page customization
If there are issues encountered during user interactive workflow (e.g. user sign up or login), Auth0 provides error messages that indicate what the problem is under the hood. The default messages are somewhat cryptic, especially to the end user, since they will likely be missing context that only you can supply. As such, we recommend [customizing your error pages](/docs/customize/login-pages/custom-error-pages) to provide the missing context-specific information directly to your users. Furthermore, customizing your error pages allows you to display your branding, not Auth0's, as well as provide useful information to your users as to what should be done next. This information might include a link to a FAQ or how to get in touch with your company's support team or help desk.
### Best Practice
Out-of-the-box there is no user interface for customizing Auth0 provided error pages, but you can use the [Tenant Settings endpoint of the Management API](https://auth0.com/docs/api/management/v2#!/Tenants/patch_settings) to configure them. Alternatively, if you can create and host your own error page, then you can have Auth0 direct users to that page instead of using the Auth0-hosted option.
#### Legacy feature flags off
If you have an older tenant, you may have various legacy feature flags enabled in your [tenant settings advanced tab](/docs/get-started/tenant-settings). If you have any toggles on in the “Migrations” section of this tab, you should review your usage and make plans to migrate off the legacy feature.
#### Delegated admin extension
While you are checking the list of users with access to your production tenant, don't forget to check any users specified in the [Delegated Admin Extension](/docs/customize/extensions/delegated-administration-extension).
### Custom Domain Naming set up
By default, the URL associated with your tenant will include its name and possibly a region-specific identifier. For example, tenants based in the US have the a URL similar to `https://example.auth0.com` while those based in Europe have something that is of the fashion `https://example.eu.auth0.com`. A [Custom Domain](/docs/customize/custom-domains) offers a way of providing your users with a consistent experience by using a name that’s consistent with your organization's brand.
Only one custom Domain Name can be applied per Auth0 Tenant, so if you absolutely must have independent domain name branding then you will require an [architecture](/docs/get-started/architecture-scenarios/business-to-business/architecture) where multiple Auth0 Tenants are deployed to production.
In addition, Custom Domain functionality offers you complete control over the certificate management process. By default, Auth0 provides standard SSL certificates, but if you configure a custom domain, you can use Extended Validation (EV) SSL certificates or similar to provide the visual, browser-based cues that offer your visitors additional peace of mind.
In general, we see customers having the most success when they use a centralized domain for authentication - this is especially the case if the company offers multiple products or service brands. By using a centralized domain, you can provide end users with a consistent user experience while also minimizing the need to maintain multiple production tenants in Auth0.
## Application and Connection settings check
Each of your connection settings should be reviewed against the [connection configuration best practices](/docs/authenticate/connection-settings-best-practices).
In addition, you should review that all connections are appropriate and that no experimental connections are left in your production tenant as they could enable unauthorized access.
If you use SAML connections, it is a best practice to configure the connections to sign SAML requests.
## Page customization check
If you use the Auth0 universal login page, password reset page, or Guardian multi-factor authentication, you should check that you have adequately customized the pages displayed to the end user.
### Universal Login Page
[Universal Login](/docs/authenticate/login/auth0-universal-login) is the recommended method for authenticating users, and it centers around use of the Login page. You can customize the Login page to support your organization's branding requirements.
### Best Practice
To customize Universal Login pages, you can modify your [page themes](/docs/customize/login-pages/universal-login/customize-themes) as well as create dynamic [page templates](/docs/customize/login-pages/universal-login/customize-templates).
If you choose to implement [Classic Login](/docs/authenticate/login/auth0-universal-login/universal-login-vs-classic-login/classic-experience) and customize the Login page script, we strongly recommend that you make use of version control. To do this, you should deploy the script to your Auth0 tenant via [deployment automation](/docs/get-started/architecture-scenarios/business-to-business/deployment) or via one of the [alternative strategies](/docs/customize/login-pages/classic-login/version-control).
### Password reset page
The [Password Reset](/docs/customize/login-pages/classic-login/customize-password-reset-page) page is used whenever a user takes advantage of password change functionality and, as with the login page, you can customize it to reflect your organization's particular branding requirements.
### Guardian
The Multi-factor Authentication pages can be customized by adjusting the Universal Login branding options in the [Universal Login Settings](https://manage.auth0.com/#/login_settings) section.
If you need further customization, you can also customize [the full HTML content](/docs/secure/multi-factor-authentication/customize-mfa/customize-mfa-classic-login) to reflect your organization's particular UX requirements.
## Authorization check
If you are using Auth0’s authorization feature, be sure to double check all privileges granted to ensure authorizations are appropriate for your production environment.
## API configuration check
### Access token expiration
You should double check the [API access token expiration settings](/docs/get-started/apis/api-settings) to ensure they are appropriate for each API in your production environment.
### API offline access
If your application does not request refresh tokens, this should be off.
### Access token signing algorithm
It is recommended that the [API access token signing algorithm](/docs/get-started/applications/signing-algorithms) be set to RS256 rather than HS256 to minimize exposure of the signing key.
### API Access token validation
If you have any custom APIs, be sure to check that they are adequately [validating the access tokens](/docs/secure/tokens/access-tokens/validate-access-tokens) they receive before using the information in them.
## API Scopes
If you have applications making machine-to-machine calls to any of your APIs, you should review the scopes specified for the API to ensure they are all appropriate for your production environment. For further information see the documentation on [client credentials grant](/docs/get-started/applications/update-grant-types).
## Email templates customized
Auth0 makes extensive use of email to provide both user notifications and to drive the functionality needed for secure identity management (for example, email verification, account recovery, and brute force protections), and Auth0 provides a number of templates for these.
Before customizing email templates, please set up your [Email Provider](/docs/get-started/architecture-scenarios/business-to-business/operations#email-provider-setup).
Out of the box, the email templates used contain standard verbiage and Auth0 branding. However, you can configure almost every aspect of these templates to reflect the verbiage and user experience you want and make changes to things like the preferred language, accessibility options, and so forth.
Email templates are customized using [Liquid syntax](/docs/customize/email/email-templates/use-liquid-syntax-in-email-templates). If you are interested in customizing your templates based on user preferences, you will also have access to the [metadata](/docs/manage-users/user-accounts/metadata) located in users' profiles, as well as any specific application metadata too.
## Attack protection configured
The reason that authentication systems are important is to prevent bad actors from accessing applications and user data that they should not. We want to place as many barriers as possible between those bad actors and access to our systems. One of the easiest ways to do this is to ensure that your [attack protection](/docs/secure/attack-protection) with Auth0 is configured correctly, so take a moment to read the guidance on this subject and ensure that it's working correctly for you.
### Best Practice
Anomaly detection is handled behind the scenes by Auth0 and provides a great security feature for your product. If you're going to utilize it, ensure that you have set up your [Email Provider](/docs/get-started/architecture-scenarios/business-to-business/operations#email-provider-setup) and configured your [Email Templates](/docs/get-started/architecture-scenarios/business-to-business/branding#email-template-customization) before turning on email delivery to your users.
## Project Planning Guide
We provide planning guidance in PDF format that you can download and refer to for details about our recommended strategies.
[B2B IAM Project Planning Guide](https://assets.ctfassets.net/cdy7uua7fh8z/63F0WOPJdVzsPMxV1Xvp8x/7a329487c5e890d8e820f6a48983b46a/B2B_Project_Planning.pdf)
# Testing Complete (B2B)
Source: https://auth0.com/docs/get-started/architecture-scenarios/business-to-business/launch/testing
Confirm your Auth0 B2B implementation is launch-ready by completing unit, integration, mock, penetration, and load testing across your tenants in line with Auth0 testing policied before customers depend on it.
Prior to launch, you should have completed all the testing that applies to your environment.
Quality Assurance is important in identifying issues before they impact your customers and, depending on the nature of your project, there are several different types of quality assurance testing that you’re going to want to consider as part of your integration with Auth0:
* Is your application easy to understand and use, even by those with a disability?
* Does your application need to work across various different browsers and devices?
* Does your application need to work in multinational and/or international environments?
* How will your application perform when subjected to unexpected production loads?
* How can you ensure your application is safe from security-related vulnerabilities?
Auth0 [Universal Login](/docs/authenticate/login/auth0-universal-login) and associated UI widgets (such as [Lock](/docs/libraries/lock)) have already been designed and built following usability and accessibility best practices, and provide tested out-of-box support for a whole host of [browsers and devices](/docs/troubleshoot/customer-support/product-support-matrix). Support for [internationalization](/docs/customize/internationalization-and-localization) (I18N) is also provided out-of-box, with built-in extensibility designed for custom multi-language and localization (L10N) situations.
To ensure functional requirements are met and unexpected events are handled correctly, guidance is provided for testing the [integration](#integration-testing) between your application(s) and Auth0, and for [unit testing](#unit-testing) individual extensibility modules (such as [Rules](/docs/customize/rules/debug-rules), [Hooks](/docs/customize/hooks/update-hooks), and Custom Database scripts). Guidance is also provided regarding Auth0's [penetration testing policy](/docs/troubleshoot/customer-support/operational-policies/penetration-testing-policy) to help when testing for security vulnerability, and also how [Mock](#mock-testing) testing can be leveraged in conjunction with our [load testing policy](/docs/troubleshoot/customer-support/operational-policies/load-testing-policy) to help ensure your application(s) perform under unexpected load.
## Unit testing
The objective of unit testing is to test individual units of code. If you create custom code within Auth0 in the form of Rules, Hooks, and/or Custom DB scripts, you should consider use a testing framework (such as [Mocha](https://mochajs.org/)) to test your code. Companies who have been most successful with Auth0 have found it useful to execute these unit tests prior to [automatically deploying](/docs/get-started/architecture-scenarios/business-to-business/deployment) Auth0 tenant configuration and collateral.
## Integration testing
It is a recommended best practice that you set up different tenants for development, testing, and production as discussed in Architecture guidance for [SDLC support](/docs/get-started/architecture-scenarios/business-to-business/architecture#sdlc-support). Auth0 allows you to configure variables that are available from within custom [extensibility](/docs/customize/extensions); these can be thought of as environment variables for your Auth0 tenant. Rather than hard code references that change when moving code between development, test, and production environments, you can use a variable name that is configured in the tenant and referenced by the custom extensibility code. This makes it easier for the same custom code to function, without changes, in different tenants as the code can reference variables which will be populated with tenant-specific values at execution time:
* For use of variables in Rules, see how to [configure values](/docs/customize/rules/configuration)
* For use of variables in Hooks, see how to configure [secrets](/docs/customize/hooks/hook-secrets) in the editor
* For use of variables in Actions, see Explore Flows and Triggers
* For use of variables in Custom DB Scripts, see the [configuration parameters](/docs/authenticate/database-connections/custom-db/create-db-connection#step-3-add-configuration-parameters)
### Best Practice
It’s a recommended best practice to use variables to contain tenant-specific values as well as any sensitive secrets that should not be exposed in your custom code. If your custom code is deployed in GitHub, then using a tenant-specific variable avoids exposure of sensitive values via your GitHub repository.
### Test automation
You can automate your overall build process by incorporating deployment automation as well as test automation. This can be used to deploy new versions of configuration and/or custom code to Auth0 and execute automated tests. If the tests uncover any failures, the deployment automation capabilities can be used to revert to the last working version. For further information, see the [deployment automation guidance](/docs/get-started/architecture-scenarios/business-to-business/deployment) provided.
## Mock testing
In a balance between Auth0’s [load testing policy](/docs/troubleshoot/customer-support/operational-policies/load-testing-policy) and the desire to load test, it is common practice among Auth0’s customers to mock out Auth0’s endpoints. This is a valuable practice in order to ensure that your application works with your expected interfaces without having to restrict your testing, and tools such as [MockServer](http://www.mock-server.com/), [JSON Server](https://github.com/typicode/json-server) or even [Postman](https://learning.getpostman.com/docs/postman/mock_servers/setting_up_mock/) can be used to assist.
## Pen testing (optional)
If you will be conducting penetration tests, you should be aware of Auth0’s [penetration testing policy](/docs/troubleshoot/customer-support/operational-policies/penetration-testing-policy) and abide by it. Penetration tests require advance notice to Auth0 so that your tests are not mistaken for malicious activity and shut down.
## Load testing (optional)
If you will be conducting load tests, you should be aware of Auth0’s [load testing policy](/docs/troubleshoot/customer-support/operational-policies/load-testing-policy) and abide by it. Load tests require advance notice to Auth0. In planning your load testing, you will also need to be aware of Auth0’s [API rate limits](/docs/troubleshoot/customer-support/operational-policies/rate-limit-policy).
Load tests require prior approval from Auth0, as explained in the Auth0 load test policy. Be sure to note the lead time for a request to be reviewed and allow enough time for review as well as conducting the tests. If your load test request has been approved, the following guidance can help avoid errors and faulty test results.
* Run an HTTP trace on a test execution of your application to identify all the calls your application or intended test needs to make, and make sure your test includes them so it is representative of what will happen in production.
* Design your test to be mindful of Auth0 API rate limits.
* Use of any custom code in Auth0 (Actions, Rules, Hooks, custom database scripts, custom OAuth connections) will invoke the Auth0 custom code sandbox and this may cost more in terms of performance. Turn off Rules unless they are essential to the test. If they are off you will have higher throughput than if they are on.
* Estimate the expected overall load for your production environment and percent of calls to each endpoint and structure your performance test accordingly so it gives you a realistic test result. Different endpoints have different performance costs. Failure to design a representative test will result in misleading results.
* Don’t make calls that depend on the results of earlier calls without checking that pre-requisite calls or responses have completed. Simply building in a delay may not be adequate.
* Be sure to implement adequate error handling. A frequent cause of issues during tests is errors in custom code (Actions, Rules, Hooks, custom database scripts, custom OAuth connection scripts) caused by unhandled exceptions in the custom code.
* Load tests should be written to start at a low level and increase the load gradually, capturing data at each level, to get the most useful results. Starting at a high level and immediately failing gives less information about what the system can sustain.
* It is normal to need to run a performance test multiple times, possibly adjusting the code under test or the test harness/configuration. Be sure to start your testing early to allow enough time for more than one iteration.
* Use your own mail provider account and make sure to arrange ahead of time for enough mail-sending quota or you may be rate-limited by the mail provider. Turn off mail sending if you do not use it.
* Be sure to use your own account credentials for all social connections rather than Auth0 dev keys. In the Auth0 dashboard, go to Connections -> Social -> \{name of connection}—to see instructions for how to add your own social provider account credentials into the connection. Note: some social providers do not allow load testing. Check your provider(s) for their policy
* In order to avoid rate limiting, and more accurately simulate real load, your tests will need to send requests for different users, not all requests for the same user. If you use only one or a few users, caching may reduce the effective load and not provide realistic results.
* Be sure to stay within the agreed-upon parameters for the test and the Auth0 load test policy. Auth0 reserves the right to terminate any performance/load testing which does not stay within the bounds of agreed-upon parameters or which extends beyond the scheduled test window.
## Project Planning Guide
We provide planning guidance in PDF format that you can download and refer to for details about our recommended strategies.
[B2B IAM Project Planning Guide](https://assets.ctfassets.net/cdy7uua7fh8z/63F0WOPJdVzsPMxV1Xvp8x/7a329487c5e890d8e820f6a48983b46a/B2B_Project_Planning.pdf)
# Business-to-Business Logout
Source: https://auth0.com/docs/get-started/architecture-scenarios/business-to-business/logout
Design logout for your Auth0 B2B application, deciding which local, Auth0, and Organization IdP sessions to terminate and how to implement single logout, federated logout, and post-logout redirects across multiple applications.
[Logout](/docs/authenticate/login/logout) is the act of terminating an authenticated session when it's no longer needed, thus minimizing the likelihood that unauthorized parties can "take over" the session. This is typically achieved by provisioning a logout option on the user interface you provide to your users. Multiple types of sessions can be created when a user logs in (e.g., local application sessions, Auth0 session, third-party Identity Provider sessions), and you will need to determine which of these sessions need to be terminated when the user clicks any **Logout** option.
Your logout behavior should make it clear to a user which session(s) are being terminated, and ideally, will display a visual confirmation of logout afterward.
When configuring logout behavior, you'll need to consider:
* Which sessions should be terminated when the user initiates logout?
* What information should you provide to users as confirmation of the sessions terminated?
* Where should users be redirected to after logout completes?
* How long do you want sessions to last in the event that users do not trigger the logout process?
* Should the End User be logged out of all of their application sessions when they log out of one?
* Should the session with an organization's IDP also be terminated at logout?
Given the varying types of sessions that can be created whenever a user logs in, there are several types of logout possible. Local application logout ends the session with the application, whereas Auth0 logout [terminates the Auth0 session](/docs/authenticate/login/logout/log-users-out-of-auth0). If you have organizations that are using their own IDP, you may want to consider a [Federated Logout](#federated-logout) strategy and implement accordingly. Global, or [Single Logout](/docs/authenticate/login/logout/log-users-out-of-applications) (SLO), ends the Auth0 session and also sends a logout request/notice to applications relying on the Auth0 session.
The functionality provided by your application, as well as your use of features like [Single Sign-on (SSO)](/docs/authenticate/single-sign-on), will inform your decision as to what type of logout is required and what visual confirmation you'll need to provide to your users. Regardless of which option you choose, the logout process you implement should make it clear to the user which sessions are being terminated, and also when the logout process has completed.
If the logout feature in one application terminates an Auth0 SSO session that is used by other applications, the user may lose work if they have uncommitted transactions. Be sure to add the functionality needed to handle such conditions to minimize the likelihood of lost work.
In some situations, a user may be expected to logout of all associated applications when they log out of any one of the applications you provide. This is something that can add complexity. However if you have concerns that users could leave themselves vulnerable (perhaps due to data sensitivity or the like), then you will likely need to review [Single Logout](#single-logout) and implement accordingly.
## Where to send users after logout
Once your user logs out, they will be redirected to a specific location of your choosing. This location is specified as the **logout redirect URL**, and you can [define this as a parameter](/docs/authenticate/login/logout/redirect-users-after-logout) via the Auth0 Dashboard.
The URL(s) you use to redirect users after logging out must be [allowlisted in the Dashboard](/docs/authenticate/login/logout#redirect-users-after-logout) to mitigate open-redirect security vulnerabilities. You can allowlist them at the tenant or application levels.
If the user logs out and you redirect them back to the application, and the application redirects to an Identity Provider that still has a valid session for the user, the user will be logged in silently to the application. This may appear to the user as if the logout process didn't function properly.
## Automatic termination of sessions
Not all users will trigger the logout process manually, so Auth0 also provides **session timeout** to prevent overly long-lived sessions. This setting is [available and configurable via the Auth0 Dashboard](/docs/get-started/tenant-settings#login-session-management).
## Single Logout
If you are doing [Federated Logout](#federated-logout) you will likely also want to do Single Logout (SLO), and there are two main approaches you can take.
SLO can add complexity to your system, so you need to ensure that you really need it before adding the extra development and maintenance time to your system.
### Short-lived tokens
You want to avoid making too many calls to your Auth0 tenant to avoid rate limiting and poor performance. A best practice is to only request new tokens if tokens have expired and a user takes an action. This will avoid applications that are simply open, but not in use, from continually polling for new tokens.
This is by far the simplest approach to Single Logout. Each application enforces a short time within which a user can use the system, say, 5-10 minutes. On each action a user performs, if the time has expired then either a redirect to Auth0 (for regular web apps), or [Silent Authentication](/docs/authenticate/login/configure-silent-authentication) for client side Single Page Applications will be used to obtain new tokens. Ordinarily new tokens will be issued silently due to the Single Sign On (SSO) session. However, after logout, all applications will fail to get new tokens silently because the SSO session will have been removed, and the user will need to re-enter their credentials.
If you are automatically forwarding the user directly to their own IdP as part of an enterprise connection using the connection parameter, this can break this technique unless you are also doing [Federated Logout](#federated-logout)
### Build a logout service
Another technique you can use is to build a logout service that can track and destroy application sessions. Each application would notify the logout service when it creates and removes a session. The (logout) service would either have direct access to all application's server side sessions and destroy them directly, or it will have the ability to make a back-channel call to each application to tell the application that it must remove its session.
This technique can be quite effective as there is low-latency between when a user calls logout, and when they are then logged out of all applications. However it can add complexity and also additional development time for implementation. It will also require some way to ensure that new applications added to the system are added to this service.
## Federated Logout
[Federated User Logout](/docs/authenticate/login/logout/log-users-out-of-idps) may be something that you need to consider for your application. If you or your customers will be using a third-party IdP (i.e., something other than a [Database Identity Provider](/docs/authenticate/database-connections)) then the question of whether you need to log the user out of the IdP when they log out of your application is something you will need to answer. The answer depends on what your users would expect. If the application and/or IdP you use is tied closely to a customer organization and a central part of day-to-day operations, then it may be frustrating for users to get logged out of their IdP when they log out of your application. If not, then being logged out of the IdP may be expected, or in some cases even desired. In most B2B scenarios, our customers find that it is preferable \*not\* to perform federated logout for a user.
## Project Planning Guide
We provide planning guidance in PDF format that you can download and refer to for details about our recommended strategies.
[B2B IAM Project Planning Guide](https://assets.ctfassets.net/cdy7uua7fh8z/63F0WOPJdVzsPMxV1Xvp8x/7a329487c5e890d8e820f6a48983b46a/B2B_Project_Planning.pdf)
# Business-to-Business Operations
Source: https://auth0.com/docs/get-started/architecture-scenarios/business-to-business/operations
Operationalize your Auth0 B2B tenants for production by configuring email providers, monitoring, log streaming, and Auth0 notifications, and by provisioning new customer Organizations and self-service IdP protals for business continuity.
Operationalization requires configuring or setting up infrastructure to support the scalable, measurable, and quantifiable operation that’s necessary for business continuity. In Auth0, this includes configuring supporting services (such as email providers), monitoring services for your deployment, detecting anomalous situations, and making preparations to recover quickly and smoothly when something goes wrong in a production environment.
Establishing effective operational behaviors is something that successful customers have found pays dividends, and there are a number of things you will want to consider when looking at your workflow:
* What should you do to proactively detect failures?
* How can you obtain data on Auth0’s operational status?
* Does Auth0 provide information regarding impending changes in the Auth0 service?
* How can you check for important notices from Auth0?
* What should you do with Auth0 log data so that you can analyze it and keep it for longer than Auth0’s limited data retention period?
* How can you scan Auth0 logs to determine if peak loads in your application trigger any rate limits or other errors?
* What email services should you use to support production volumes of email messages to users? Can I use Auth0's out-of-box email provider in my production environment?
* Do you need to configure your firewall and what firewall ports will you need to open for internal services that need to receive communications from Auth0 (such as custom databases, web services, and email servers)?
* How will you provision new organizations?
* Do you need to provide self-service provisioning for your customer so that they can configure their own organizational IdPs?
Auth0 supports functionality for [monitoring](#monitoring) Auth0 service operation as well as providing information regarding Auth0 [service status](#service-status). In addition, Auth0 makes information regarding upcoming changes to the Auth0 service available via various [notifications](#notifications). Auth0 [logging](#logging) services also provide extensive functionality for tracing and identifying operational anomalies, including restrictions encountered due to rate limiting and/or excessive loading.
Out-of-box, Auth0 provides email delivery services to help you accelerate your integration. These services, however, are not meant for scale-of-use in production environments, and do not provide for any specific service level or guarantee when it comes to email delivery. Our best practice recommendation, which customers typically follow, involves configuring your own [email service provider](#email-provider-setup).
You may also need to make changes to [infrastructure](#infrastructure) configuration in order to support integration with Auth0 and to support use of Auth0 extensibility. For example, if you need to provide callbacks to your internal or even external infrastructure (e.g., if you need to make external API calls in Actions, Rules, or Hooks, or via custom database scripts if you need to leverage existing legacy identity storage), then you may need to configure your Firewall settings.
Once you know how you want organizations to be represented in your system, you will want too consider how you are going to provision the organization itself. See [Provisioning organizations](#provisioning-organizations) for more information.
In addition, many of our customers have developed one or more self-service portals for use by their customers' organization admins to provide self-service capabilities for configuring their own [IdPs](#self-service-idp-provisioning).
## Service status
The Auth0 [status dashboard](https://status.auth0.com/) together with the Auth0 [uptime dashboard](http://uptime.auth0.com/) shows current and past status of the Auth0 service in a human-readable format. If any monitoring alerts are triggered, and as a first step in troubleshooting, your operations staff should check the status dashboard to see if there is a current outage. The public cloud status page also provides a facility for subscribing to outage notifications, and we also recommend that you check the status of any third-party [external services](/docs/deploy-monitor/monitor/check-external-services-status) you depend on, such as Social Providers. Having this information handy can help quickly eliminate possible causes when troubleshooting an issue and should be at the top of a troubleshooting checklist for developers as well as the help desk staff.
Information on how to check the status of Auth0 as well as any dependent services (such as Social Providers) should be at the top of a troubleshooting checklist for both developers and helpdesk staff, and we recommend you subscribe via the Auth0 status page to set up notification of any status updates.
In the event of an outage to the public cloud service, Auth0 performs a Root Cause Analysis (RCA) and publishes the results on the Auth0 status page. Auth0 performs a thorough investigation after an outage—including a determination of root cause, as well as contributing factors and how to prevent the issue from occurring again—and as a result, an RCA document can take a few weeks to be published.
## Email provider setup
Auth0 sends [emails](/docs/customize/email) to users for events such as signup welcome, email validation, breached password, and password reset events. You can customize the email templates for each type of event, and advanced customization of email handling is also possible. Auth0 provides a test email provider with limited capacity for basic testing, but you must set up your own email provider for production use, and customization of email templates will not work until you have established your own provider.
The default Auth0 email provider does not support sending production volumes of email or customization of email templates. You should therefore configure your own email provider before deploying to production.
## Infrastructure
### Firewalls
If custom code executing in Auth0 (such as in an Action, Rule, Hook, or custom database scripts) will call a service inside your network, or if you configure an on-premise SMTP provider in Auth0, then you may need to configure your firewall to allow [inbound traffic from Auth0](/docs/secure/security-guidance/data-security/allowlist). The IP addresses to allow through the firewall are specific to each region and are listed on the Rules, Hooks, custom database scripts, and email provider configuration screens in your Auth0 dashboard.
## Logging
Auth0 provides extensive capability when it comes to the logging of events, and also in the scanning of logs in order to identify event anomalies (see [logs documentation](/docs/deploy-monitor/logs) for further details). Standard log retention period for Auth0 logs is determined by subscription level with the shortest period being 2 days and the longest period being only 30 days. Leveraging Auth0 support for integrating with external logging services will allow you to retain logs outside of this, and will also provide for log aggregation across your organization.
You should leverage one of the log streaming solutions to send log data to an external log analytics service. This will enable keeping data for longer periods of time and provide advanced analytics on the log data.
You should review the log data [retention period](/docs/deploy-monitor/logs/log-data-retention) for your subscription level, and implement a log data export extension to send log data to an external log analytics service. You can use one of our [log streaming solutions](https://marketplace.auth0.com/features/log-streaming) in Auth0 Marketplace.
Development teams can use log files for troubleshooting and detecting intermittent errors that may be hard to find via QA tests. Security teams will probably want log data in case forensic data is ever needed. Exporting log files to services that provide comprehensive analytics can help you see patterns such as usage trends and attack protection triggers.
### Rate limits and other errors
Auth0 provides a unique error code for errors reported when the [rate limit is exceeded](/docs/troubleshoot/customer-support/operational-policies/rate-limit-policy). You should set up automatic scanning of logs to check for rate limit errors so you can proactively address activity that hits rate limits before it causes too much trouble for your users. Auth0 also publishes error codes for other types of errors, and you will find it helpful to scan logs for [authentication errors](/docs/libraries/common-auth0-library-authentication-errors) as well as errors from Auth0 Management API calls (Management API error codes are shown below each call in the [Management API Explorer](https://auth0.com/docs/api/management/v2)).
Calling the Management API to retrieve user profile information from within a Rule is a common cause of rate limit errors because such API calls can execute for every login as well as periodic session checks.
## Monitoring
You should establish mechanisms for [monitoring Auth0 implementations](/docs/deploy-monitor/monitor), so your support or operations team receives the timely information needed to proactively handle service outages. Auth0 provides monitoring endpoints that can be incorporated into your monitoring infrastructure. These endpoints are designed to provide a response suitable for consumption by monitoring services. It should be noted that they only provide data on Auth0. For complete end-to-end monitoring, which is essential for checking the ability of users to log in, we recommend that you set up synthetic transaction monitoring. This will provide greater granularity for your monitoring and enable you to detect outages unrelated to Auth0 as well as degradation of performance, so you can respond more proactively.
You should set up the ability to send synthetic login transactions to facilitate end-to-end monitoring of authentication. You can do this with a simple application that uses the [Resource Owner Password Grant](/docs/get-started/authentication-and-authorization-flow/resource-owner-password-flow/call-your-api-using-resource-owner-password-flow) in combination with a test user that has no privileges, and don’t forget about [Auth0 rate limiting policies](/docs/troubleshoot/customer-support/operational-policies/rate-limit-policy) too.
## Notifications
There are several different types of notifications from Auth0 that you should watch for as they contain important information that could impact your tenant(s) and project.
Proactive security notifications and other operational announcements are sent by Auth0 to dashboard administrators. You should ensure that the people who need to receive such messages are dashboard administrators.
### Dashboard notifications
From time to time, Auth0 may send an important announcement related to your tenant. These announcements about your service will be sent to your Auth0 dashboard and depending on the severity of the announcement, via email to the registered Auth0 dashboard administrators. You should make a regular practice of logging in to the dashboard and checking the bell icon at the top for any important notices. In addition, you should review emails from Auth0 in a timely fashion as they may convey important information about changes or actions you need to take.
### Change log
Auth0 provides information on changes to the service in the Auth0 [change log](https://auth0.com/changelog). You should make a regular practice of reviewing Auth0 change logs to be aware of changes. Support teams researching an issue may find it useful to review the change log to determine if recent changes might be related, especially if these are [breaking changes](/docs/troubleshoot/product-lifecycle/deprecations-and-migrations). Development teams will also want to review the change logs to identify new features that may be beneficial.
## Provisioning organizations
What you need to do when provisioning an organization will depend on how organizations are represented in your system. This can take some time to step back and consider how users of those organizations will be interacting with your applications. See [Multiple Organization Architecture](https://cdn2.auth0.com/docs/1.14516.0/media/articles/architecture-scenarios/planning/Multiple-Organization-Architecture-Multitenancy-Overview.pdf) to determine how to configure organizations for your IAM system.
When provisioning organizations you need to consider the following:
* You will need to add the organization to your own application configuration and/or database
* You will need to make changes to your Auth0 configuration. This will include doing some or all of the following:
* Create a unique tenant
* Add a database connection (if you have isolated users per organization)
* Add an enterprise connection for this organization
* This will include working with the organization to either update their existing configuration or add configuration for your Auth0 tenant if they are not a legacy organization.
* Provision an administrator for the organization
* To avoid mistakes, you may want to create an [Organization Admin Portal](#organization-admin-portal) to make it easier to provision new organizations.
### Organization Admin Portal
An organization admin portal is a portal that allows your administrators to create, modify, and remove organizations. There are multiple activities that need to be done both in your own system and your Auth0 tenant. This portal will likely need to exist in your own system so it has access to your datastores and configuration. However, Auth0 provides the [Auth0 Management API](https://auth0.com/docs/api/management/v2) so that you can incorporate changes to your Auth0 tenant at the same time that you create the changes in your own system.
There are two main approaches that can be taken for creating a new organization. The one you choose depends highly on your tolerance for how long it would take to deploy a new organization.
* **Live Updates to your Auth0 Tenant**: If you want to be able to create new organizations in real-time, then you will likely want to make the changes directly to your Auth0 tenant using the Auth0 Management API. This allows the changes to take place in real-time and allow the addition of a new organization to take effect immediately.
Live Updates do come with some things to consider. There are certain operations that must be done in serial to avoid issues. Enabling clients on a connection, adding callback URL's to an Application are two examples. Any operation in the Management API where you must retrieve an entire list and re-submit the entire list with the new value added to it are operations that must be done in serial to avoid two parallel operations overwriting one of the values.
* **Change the Repository and Re-deploy**: If you are taking advantage of the Deploy CLI (or a custom CLI) as part of your [CI/CD pipeline](/docs/get-started/architecture-scenarios/business-to-business/deployment), you may prefer to push your changes directly to your repository and then kickoff a new deployment instead. This can take a little more time, but it has benefits associated with version history and the ability to backout a change by re-deploying the previous version.
You may want to have a separate repository just for the items that the organizations need so that you don't have to re-deploy other common components and risk making an error.
## Self-Service IdP provisioning
While Auth0 [connections](/docs/authenticate/identity-providers) make it easy to configure IdPs, it can be a time-consuming process to onboard customer organization IdPs especially if you are selling to new customer organizations on a regular basis or existing organizations have changing IdP requirements. As a result, many of our customers have found it worthwhile to build a self-service portal for their customers' organization admins so that they can configure their own IdPs. This cuts down on your IT department's workload. The [Auth0 Management API](https://auth0.com/docs/api/management/v2) provides all necessary [connection management functionality](https://auth0.com/docs/api/management/v2#!/Connections/get_connections) to achieve this.
## Project Planning Guide
We provide planning guidance in PDF format that you can download and refer to for details about our recommended strategies.
[B2B IAM Project Planning Guide](https://assets.ctfassets.net/cdy7uua7fh8z/63F0WOPJdVzsPMxV1Xvp8x/7a329487c5e890d8e820f6a48983b46a/B2B_Project_Planning.pdf)
## Multiple Organization Architecture (Multitenancy)
Many B2B platforms implement some form of isolation and/or branding for their customers' organization, and this can add complexity to any Identity and Access Management (IAM) system. If this applies to you, then we recommend you take some time to read through our guidance and best practice advice for this type of environment.
[Multiple Organization Architecture](/docs/get-started/architecture-scenarios/multiple-organization-architecture)
# Business-to-Business Profile Management
Source: https://auth0.com/docs/get-started/architecture-scenarios/business-to-business/profile-management
User profile management planning considerations for your B2B IAM implementation.
At some point, you may need to change the information stored in a user’s profile. A user’s profile (also known as the user’s account) is stored in Auth0, and changes to the information it contains may need to happen for a number of different reasons:
* Self-served information updates
* Mandatory updates concerning your organizations T's & C’s
* Changes due to regulatory compliance
You cannot directly access a user profile across multiple Auth0 tenants. If you’re deploying multiple Auth0 tenants to production then this is something you need to be aware of.
An [Identity Provider](/docs/authenticate/identity-providers) populates a user’s profile using data supplied during the login process, and this is referred to as the [Normalized User Profile](/docs/manage-users/user-accounts/user-profiles/normalized-user-profiles).
The Normalized User Profile is updated from the identity provider during login, and you can change the limited set of the information it contains through the Auth0 Management API. You can also use Auth0 extensibility, such as [Actions](/docs/customize/actions), as an alternative to override information in the Normalized User Profile. See [User Profile Data Modification](/docs/manage-users/user-accounts/user-profiles#user-profile-data-modification) for more information.
By default, there is one user profile created for each user identity, and there are a number of things to consider:
* What should you do if you need to store information to help customize a user’s experience?
* What if you need to store user information that didn’t originate from an identity provider?
* Why would you need to store user-related information that a user cannot modify?
* What do you do if you need to store user-related information that a user cannot modify?
* What happens if a user forgets their password?
* What should a user do if they want to change their password?
* How do you provide an administrator from a third-party organization with the ability to manage their users?
Auth0 provides for the storage of metadata against a user’s profile, which allows for the capture of additional information, such as preference for language and/or accessibility in order to enhance the user experience. Metadata can be used to store both information that a user can change, and also information they can’t; the latter giving you the capability of associating, for example, a user profile with records in your existing systems without modifying existing implementation.
For users who forget their passwords or who are allowed to change their password via some existing self-service mechanism (or self-service mechanism you have planned), you can leverage Auth0-provided [Password Reset](#password-reset) functionality. This can be integrated with your existing implementation and comes already incorporated with any out-of-box Auth0 UI widgets including [Universal Login](/docs/authenticate/login/auth0-universal-login).
You’ll also want to make sure that you are working with a [verified user account](#account-verification) at all times. Auth0 provides out-of-box mechanisms for doing that too. You should also consider [regulatory compliance](/docs/secure/data-privacy-and-compliance) such as ([GDPR](https://gdpr-info.eu/) which has very specific requirements when it comes to protecting EU citizens from privacy and data breaches.
Though Auth0 doesn’t currently provide a centralized profile management portal out-of-the-box, for the purpose of self-serviced profile management, you can use the Auth0 Management API to build your own or utilize an already built UI. See our Auth0 [community guidance](https://community.auth0.com/t/how-to-allow-the-end-user-to-update-their-own-profile-information/6228) which describes the Management API endpoint. All calls to the Management API will require use of an [Access Token](/docs/secure/tokens/access-tokens).
Self-service profile management can raise security as well as data privacy concerns. For example, you may want to allow a user to change their email address, however, doing so without following best practice security guidance could result in a user locking themselves out of their account, leaking Personally Identifiable Information (PII), or worse, opening up a potential breach in security.
Alternatively, you can use the Auth0 Dashboard to [manage aspects of a user’s profile](/docs/manage-users/user-accounts/manage-users-using-the-dashboard). Managing a user’s profile via the Auth0 Dashboard is more of an administrative provision and **should not** be used for self-serviced profile management in a production environment. However, the interface provided by the Dashboard can be extremely useful during development as it provides a quick and simple way of manipulating a user’s profile information.
If you need to provide a way for your customers to have an administrator manage their own users when they are storing those credentials in your system, you can either build something yourself or use an Auth0 Extension. See [Admin Portal](#admin-portal) for more information.
## Metadata
In addition to the Normalized User Profile information, [Metadata](/docs/manage-users/user-accounts/metadata) can be stored in an Auth0 user profile. Metadata provides a way to store information that did not originate from an identity provider, or a way to store information that overrides what an identity provider supplies.
Use of Metadata should follow Auth0 [user data storage best practices](/docs/secure/security-guidance/data-security/user-data-storage#metadata). Metadata storage is not designed to be a general purpose data store, and you should still use your own external storage facility when possible. Metadata size and complexity should also be kept to a minimum, and the Auth0 Management API has a strict set of guidance when it comes to updating and/or deleting metadata associated with a user.
You can manipulate metadata via both the Auth0 Management API and the Auth0 Authentication API. As is the case when managing the Normalized User Profile, calls to the Management API for manipulating Metadata requires use of an [Access Token](https://auth0.com/docs/api/management/v2/tokens).
Calls to the Management API are subject to [Auth0 Rate Limiting policy](/docs/troubleshoot/customer-support/operational-policies/rate-limit-policy). You must take this into consideration, and to assist, Auth0 generally recommends use of the appropriate [Auth0 SDK](/docs/libraries) for your development environment rather than calling our APIs directly.
### User metadata
User metadata (also referred to as `user_metadata`) is information that can be stored against a user profile and that a user can read and update as part of any self-service profile management. Metadata of this nature may be something like salutation for a user, or a user’s preferred language which could be used to [customize the emails](/docs/customize/email/email-templates) sent by Auth0.
Store any information that you want use to customize Auth0 emails in metadata and preferably `user_metadata` if the user is allowed to change it, such as information used to determine the language for an email.
### App metadata
App metadata (also referred to as `app_metadata`) is, on the other hand, information that can be stored with a user profile but can **only be read or updated with appropriate authorization**; `app_metadata` is not directly accessible to a user. This type of metadata could be something like a flag to indicate that the last set of valid terms and conditions was accepted by the user, and a date to indicate when the user accepted them.
## Password reset
For users who forget their passwords or who are allowed to change their password via some existing self-service mechanism, Auth0 provides [Password Reset](/docs/authenticate/database-connections/password-change) functionality. You can integrate this with your existing implementation and comes already incorporated with out-of-the-box Auth0 UI widgets included as part of [Universal Login](/docs/authenticate/login/auth0-universal-login).
Password change and password reset is only supported for Auth0 [Database Connection](/docs/authenticate/database-connections/password-change) types.
Auth0 Universal Login provides built-in UX support for password reset using Auth0 Authentication API functionality. Alternatively, you can use the [Auth0 Authentication API](/docs/authenticate/database-connections/password-change#use-the-authentication-api), through one of the Auth0 SDKs appropriate to your development environment. Email templates used during password reset workflow can also be fully customized, whether you use Auth0 out-of-box UI widgets or customized Universal Login.
You can use the Auth0 Management API, on the other hand, to [directly change the password](/docs/authenticate/database-connections/password-change#directly-set-the-new-password) for a user identity defined using a Database Connection type. You can use the Auth0 Management API as part of any self-service profile management implementation, and also as part of any [Change Password page customization](/docs/get-started/architecture-scenarios/business-to-business/branding).
## Account verification
You’ll also need to work with a verified user account at all times and make use of the mechanisms Auth0 provides. You should also consider regulatory compliance like [GDPR](https://gdpr-info.eu/) which has very specific requirements for protecting EU citizens from privacy and data breaches.
Auth0 provides out-of-box functionality for sending a [verification email](/docs/customize/email/manage-email-flow) to a user's email address to verify their account. By default, Auth0 automatically sends verification emails for any [Database Connection](/docs/authenticate/database-connections/password-change) identity created as part of [self sign-up](/docs/get-started/architecture-scenarios/business-to-business/provisioning#self-sign-up). However, Auth0 also provides a [Management API endpoint](https://auth0.com/docs/api/management/v2/tickets/post-email-verification) that you can use to send verification emails in cases where email address validation is not performed by a Social Provider upon user registration.
## Blocking users
[Blocking user access](/docs/manage-users/user-accounts/block-and-unblock-users) in Auth0 provides a way to prevent user login to applications under certain conditions. By default, the Auth0 Dashboard provides an out-of-the-box mechanism to give administrators the ability to both block and unblock user access to all applications, and you can implement this functionality via use of the [Auth0 Management API](https://auth0.com/docs/api/management/v2#!/Users/patch_users_by_id). You can also use Auth0 extensibility to [disable user access to certain applications](/docs/manage-users/user-accounts/manage-user-access-to-applications) as well as provide more fine-grained [access control](/docs/get-started/architecture-scenarios/business-to-business/authorization).
In addition, the Auth0 Management API provides you with the ability to [unblock](https://auth0.com/docs/api/management/v2#!/User_Blocks/delete_user_blocks_by_id) users disabled due to excessive use of incorrect credentials.
## Admin portal
An admin portal is an application where you can create new users, edit a user’s profile, see activity about a user, etc. This application should be accessible by administrators only. Though Auth0 provides its management dashboard, it is not advised to give access to the management dashboard to many people as there are a lot of ways someone can unintentionally break your Auth0 tenant. Instead, Auth0 provides two other options:
* [**Auth0 Management API**](https://auth0.com/docs/api/management/v2): With the Management API you can easily construct an application that provides administrators the ability to manage users. You can either incorporate this into an existing application that already exists for your administrators, or create a new one with a UI that matches your current applications.
* [**Auth0 Delegated Administration Extension**](/docs/customize/extensions/delegated-administration-extension): This powerful and flexible extension allows you to customize a user administration experience. You can tailor this extension so that you can allow your customer admins to log in and allow them to only see and manage users within their organization.
If you are providing your own way for an administrator to manage users, you should only allow administrators to send users a change password link through email rather than allowing administrators to set passwords directly. If you must go against this recommendation and allow your administrators to set someone’s password, you should force the user to change their password at their next login so that only they know the password (and not an administrator as well).
## Project Planning Guide
We provide planning guidance in PDF format that you can download and refer to for details about our recommended strategies.
[B2B IAM Project Planning Guide](https://assets.ctfassets.net/cdy7uua7fh8z/63F0WOPJdVzsPMxV1Xvp8x/7a329487c5e890d8e820f6a48983b46a/B2B_Project_Planning.pdf)
## Multiple Organization Architecture (Multitenancy)
Many B2B platforms implement some form of isolation and/or branding for their customers' organization, and this can add complexity to any Identity and Access Management (IAM) system. If this applies to you, then we recommend you take some time to read through our guidance and best practice advice for this type of environment.
[Multiple Organization Architecture](/docs/get-started/architecture-scenarios/multiple-organization-architecture)
# Business-to-Business Provisioning
Source: https://auth0.com/docs/get-started/architecture-scenarios/business-to-business/provisioning
User provisioning functionality and considerations for your B2B IAM implementation.
Determining how users get signed up is important to address early, and the decisions you make here will influence many of the decisions you will need to make going forward. We’ve found there are a typical set of patterns for how users will get added to your system, and things to take note of when considering workflow design too.
While Auth0 supports numerous workflows, web based workflows using Auth0 [Universal Login](/docs/authenticate/login/auth0-universal-login) for sign up are considered both industry and Auth0 best practice as they provide for optimal functionality and the best security.
Auth0 supports user sign up via a number of different [identity providers](/docs/authenticate/identity-providers). During sign up, Auth0 provisions the user profile so that it contains the user’s account information. There are a number of things to consider when looking at functionality and workflow:
* Does a user get added to your company's domain or do they belong to or remain in their organization's domain?
* If the user stays in their own domain, do they belong to a single organization or can they belong to multiple organizations?
* How do you provision the organization itself in your system?
* Should you use Auth0 as an identity store?
* Can you use your own (legacy) identity store with Auth0?
* How do you migrate user identities from your identity store to Auth0?
* Can your users sign up using their organization's identity provider?
* Can your users be invited or self register?
One of the first determinations to make when providing your service(s) to other businesses is identifying to which domain users belong. Based on the answer to that question, there are a couple of different approaches you can take to provision those users. See [Provisioning organization users](#provisioning-organization-users) for more information. Once you know how you want organizations to be represented in your system, you will want to consider how you are going to provision the organization itself. See [Provisioning organizations](#provisioning-organizations) for more information.
Auth0 provides out-of-the-box identity storage that can be leveraged to store user credentials safely and securely. If you already have a legacy identity store and you want to offload the management of it, then the [User Migration](#user-migration) capabilities provide you with a number of options to do so.
Alternatively, if you have to maintain your legacy identity store - perhaps because you’ve got applications which you aren’t ready to migrate or which can’t be migrated - then you can use the [identity store proxy](#identity-store-proxy) capability. Allowing your customers to use “bring their own identity” is also an attractive proposition and though we find our customers don’t initially do so, you can use the [Social Sign Up](#social-sign-up) capability to provide it.
## Provisioning organizations
What you need to do when provisioning an organization will depend on how organizations are represented in your system. This can take some time to step back and consider how users of those organizations will be interacting with your applications. See [Multiple Organization Architecture](/docs/get-started/architecture-scenarios/multiple-organization-architecture) to determine how to configure organizations for your IAM system.
When provisioning organizations you need to consider the following:
* You will need to add the organization to your own application configuration and/or database
* You will need to make changes to your Auth0 configuration. This will include doing some or all of the following:
* In rare cases: create a unique tenant for the organization
* Create a new Organization in your Auth0 Tenant
* Add a new a database connection for that Organization (if you have isolated users per organization)
* Enable the existing shared database connection for that Organization (if you are sharing users)
* Add an enterprise connection for this Organization and enable it on the Organization
* This will include working with the organization to either update their existing configuration or add configuration for your Auth0 tenant if they are not a legacy organization.
* Provision an administrator for the organization
* To avoid mistakes, you may want to create an [Organization Admin Portal](#organization-admin-portal) to make it easier to provision new organizations.
* You may also want to create a Self-Signup portal for your Organizations. This allows your customers to create the organization themselves. This can be part of the [Organization Admin Portal](#organization-admin-portal).
### Organization Admin Portal
An organization admin portal is a portal that allows your administrators to create, modify, and remove organizations. These administrators can either be employees of your company, or customer admins. There are multiple activities that need to be done both in your own system and your Auth0 tenant. This portal will likely need to exist in your own system so it has access to your datastores and configuration. However, Auth0 provides the [Auth0 Management API](https://auth0.com/docs/api/management/v2) so that you can incorporate changes to your Auth0 tenant at the same time that you create the changes in your own system.
There are two main approaches that can be taken for creating a new organization. The one you choose depends highly on your tolerance for how long it would take to deploy a new organization.
* **Live Updates to your Auth0 Tenant**: If you want to be able to create new organizations in real-time, then you will likely want to make the changes directly to your Auth0 tenant using the Auth0 Management API. This allows the changes to take place in real-time and allow the addition of a new organization to take effect immediately. Particulary if you are providing Self-Signup for organizations you may want to do this approach.
Live Updates do come with some things to consider. There are certain operations that must be done in serial to avoid issues. Enabling clients on a connection, adding callback URL's to an Application are two examples. Any operation in the Management API where you must retrieve an entire list and re-submit the entire list with the new value added to it are operations that must be done in serial to avoid two parallel operations overwriting one of the values.
* **Change the Repository and Re-deploy**: If you are taking advantage of the Deploy CLI (or a custom CLI) as part of your [CI/CD pipeline](/docs/get-started/architecture-scenarios/business-to-business/deployment), you may prefer to push your changes directly to your repository and then kickoff a new deployment instead. This can take a little more time, but it has benefits associated with version history and the ability to backout a change by re-deploying the previous version. You may want to have a separate repository just for the items that the organizations need so that you don't have to re-deploy other common components and risk making an error.
## User migration
In addition to hosting the [User Profile](/docs/get-started/architecture-scenarios/business-to-business/profile-management), Auth0 also has the capability to both [proxy](#identity-store-proxy) your own legacy identity store and provide a secure Auth0 hosted replacement. Both of these capabilities are supported via the use of Auth0 [Database Connections](/docs/authenticate/database-connections). If you decide to use Auth0 as a replacement for your legacy identity store then you can [migrate users](/docs/manage-users/user-migration) either all at once with bulk migration, or progressively with automatic migration.
Customers often opt for a two-stage approach to user migration, using Automatic Migration first to migrate as many users as possible, then using Bulk Migration for the users that remain. See [User Migration Scenarios](/docs/manage-users/user-migration/user-migration-scenarios) for more information.
Automatic Migration is preferred as it allows users to be migrated individually and also allows them to retain their existing passwords in almost all situations. For Bulk Migration, we recommend using the [Management API](https://auth0.com/docs/api/management/v2#!/Jobs/post_users_imports) over the [User Import/Export extension](/docs/manage-users/user-migration/user-import-export-extension) in all but the most simple cases, as the Management API provides for greater flexibility and control.
With Bulk Migration users typically need to **reset their password once the migration is complete** unless passwords are stored hashed in your legacy identity store using one of the supported algorithms. In this case, you may be able to use bulk migration and **preserve user passwords** as part of the process, depending on the algorithm and the number of salt rounds used. See [Bulk Import Database Schema Examples](/docs/manage-users/user-migration/bulk-user-import-database-schema-and-examples) for more information.
Importing hashed passwords relies on the source identity store using idiomatic implementations of one of the following algorithms: argon2, bcrypt, hmac, ldap, md4, md5, sha1, sha256, sha512, pbkdf2, and scrypt.
Calls to the Management API are subject to [Auth0 Rate Limiting policy](/docs/troubleshoot/customer-support/operational-policies/rate-limit-policy). You must take this into consideration, and to assist, Auth0 generally recommends use of the appropriate [Auth0 SDK](/docs/libraries) for your development environment rather than calling our APIs directly.
### Identity store proxy
Auth0 Database Connection types can also be configured to proxy an existing (legacy) identity store. If you need to keep user identities defined in your own legacy store - for example, if you have one or more business critical applications that you can’t migrate to Auth0, but which still need access to these identities - then you can easily integrate with Auth0. See [Authenticate Users Using Your Database](/docs/authenticate/database-connections/custom-db) for more information.
## Provisioning organization users
An organization should map directly to one of your business customers/partners. Each business/partner that you are working with has users who will be logging in. We call those end users "organization users". There are two different approaches to how to store your organization users:
* **Isolated to the organization**: Every user belongs to exactly one organization. It would not make sense for that user to be a part of more than one organization, and even if they were, it would make sense for them to have a separate “identity” for that other organization. For example, a retail employee that works part time at two different stores has two different logins for each of those stores even if the stores both use the SaaS application. To learn more, see [Provisioning users isolated to the organization](#provisioning-users-isolated-to-the-organization).
* **Shared between organizations**: In a case like this, users either create credentials in your company, or they can access other organizations instances of your application using credentials from their own organization. A simple way to look at this is that one user may be authorized to access more than one organization’s instance of the application. A user would understand that they can use the same credentials to access both instances of an application. For example, some doctors contract with multiple clinics and may need to be able to sign into each separate clinic with their same credentials. To learn more, see [Provisioning users shared between organizations](#provisioning-users-shared-between-organizations).
### Provisioning users isolated to the organization
Isolating users to the organization can provide a nice clean barrier between organizations. If no users ever need to access more than one organization (or you would rather force them to create multiple accounts), then this is an attractive approach.
You need to provision those users at the IdP level. Each of the organizations will have its own IdP for accomplishing this. This IdP will come in one of three flavors:
* **Your Auth0 Tenant is the IdP**: A Database Connection in your main tenant dedicated to this organization.
* **Organizations bring their own IdP**: You set up an Enterprise Connection for them.
* **Organizations with more than one IdP**: You enable more than one Enterprise Connection, Social Connection, and also may have a single Database Connection. When the user chooses their organization and attempts to log in, they will be able to choose from all of the connections that have been enabled for that organization.
We recommend using Auth0 as an IdP as a starting point because it’s simple to implement a [user invite workflow](/docs/manage-users/organizations/configure-organizations/invite-members). Compared to other invite flows, the only thing special about this is that the person who is creating the user will have to either select the organization ahead of time, or the system will force the organization to match that of the user doing the inviting (in situations where there is an organization administrator who belongs to that organization only).
If you can utilize the [Organizations Feature](/docs/manage-users/organizations), it will greatly simplify your login system, making it more maintainable and extendable for the future. See [Multiple Organization Architecture](/docs/get-started/architecture-scenarios/multiple-organization-architecture) for a more in-depth view.
### Provisioning users shared between organizations
When sharing users between organizations, you will need a way to authorize access. Because you won’t know where a user might belong when authenticating, we typically recommend storing your users in a single domain and then figuring out which organizations they can access by adding them as [members of the organization](/docs/manage-users/organizations/configure-organizations/assign-members). Because of this, provisioning will often be done by starting with a User Invite workflow for the single database connection, and then they will be added to the organization using the management API. You can then use the management API to retrieve which [organizations the user belongs to](/docs/manage-users/organizations/configure-organizations/retrieve-user-membership) if you need to provide a way for them to switch between organizations.
### Deprovisioning limitations
Auth0 will not communicate with the upstream IdP if there is an active SSO session with Auth0 unless you force it with a `prompt=login`. If one of your customer organizations can not manage logout for those users, they may still have access after they’ve been decommissioned. Depending on the IdP, if Auth0 gets a token for their API, you can request information about the user from the IdP in a [rule](/docs/customize/rules) to poll whether that user should still have access or not. If you don’t have this ability, you will have to provide your customer organizations with a way to trigger a block or decommission of users in your system either through an API call or a UI.
## User invite
In most B2B scenarios, only particular individuals are allowed access to the application. As a result, it is often simpler to have an administrator provision user accounts rather than having users sign up and then have an administrator approve them. Provisioning can often be done in an automated fashion when users are added to a centralized system as well.
There are three different personas who might be [inviting users](/docs/customize/email/send-email-invitations-for-application-signup):
* An administrator at your company may create the users for each organization.
* An administrator from each organization may be assigned to creating users.
* Another system responsible for creating users may exist, and that system may then create a user in Auth0. Regardless of the audience, the technique can be similar. The rest is a matter of using the right authorization model for the application.
The recommended approach for user invite is to use the [Organizations Feature](/docs/manage-users/organizations/configure-organizations/invite-members) to accomplish this. If you are **not** using the Organizations Feature to implement user invites and are building your own, it is important to create each user with the `user.email_verified` parameter set to `false` and a random temporary password. The generated password should only be known to Auth0 and **not** stored in any external system nor passed to the user! Then, use the [Management API](https://auth0.com/docs/api/management/v2#!/Tickets/post_password_change) to send an email to the user with a link to reset their password; you can even modify the email template in Auth0 to reflect that this is part of an invited sign-up workflow too. This ensures that the user's email address belongs to the user being created and the only person who knows the password is the user themselves.
One of the main principles of OIDC is that no one except the user themselves ever knows their password. If you are doing an invite flow, have your backend system randomly generate a password and then discard it and have your user reset their password before ever logging in. Do not create a temporary password and give it to them to log in the first time.
## Enterprise sign up
Enterprise sign up is synonymous with sign in via [enterprise login](/docs/get-started/architecture-scenarios/business-to-business/authentication)—there’s no distinction here per se, as user [profile](/docs/get-started/architecture-scenarios/business-to-business/profile-management) creation happens automatically upon first enterprise login.
A nice advantage of allowing your customers to use their own IdP is that they can administer their users and assign roles and access in their own IdP setup instead of forcing you to build administration for them. Working out the mapping for those customers will make this much easier.
If mapping isn't enough and you must put some metadata in your system, keep in mind that Auth0 will not create the user until they log in to the system the first time. Therefore, you will need to use rule extensibility to pull the initial information from somewhere else, or force users to log in the first time before you can add the metadata.
## Project Planning Guide
We provide planning guidance in PDF format that you can download and refer to for details about our recommended strategies.
[B2B IAM Project Planning Guide](https://assets.ctfassets.net/cdy7uua7fh8z/63F0WOPJdVzsPMxV1Xvp8x/7a329487c5e890d8e820f6a48983b46a/B2B_Project_Planning.pdf)
## Multiple Organization Architecture (Multitenancy)
Many B2B platforms implement some form of isolation and/or branding for their customers' organization, and this can add complexity to any Identity and Access Management (IAM) system. If this applies to you, then we recommend you take some time to read through our guidance and best practice advice for this type of environment.
[Multiple Organization Architecture](/docs/get-started/architecture-scenarios/multiple-organization-architecture)
# Business-to-Business Quality Assurance
Source: https://auth0.com/docs/get-started/architecture-scenarios/business-to-business/quality-assurance
Build quality assurance into your Auth0 B2B integration with unit, integration, and mock testing of custom code to catch issues before customers do.
Quality Assurance is important in identifying issues before they impact your customers and, depending on the nature of your project, there are several different types of quality assurance testing that you’re going to want to consider as part of your integration with Auth0:
* Is your application easy to understand and use, even by those with a disability?
* Does your application need to work across various different browsers and devices?
* Does your application need to work in multinational and/or international environments?
* How will your application perform when subjected to unexpected production loads?
* How can you ensure your application is safe from security-related vulnerabilities?
Auth0 [Universal Login](/docs/authenticate/login/auth0-universal-login) and associated UI widgets (such as [Lock](/docs/libraries/lock)) have already been designed and built following usability and accessibility best practices, and provide tested out-of-box support for a whole host of [browsers and devices](/docs/troubleshoot/customer-support/product-support-matrix). Support for [internationalization](/docs/customize/internationalization-and-localization) (I18N) is also provided out-of-box, with built-in extensibility designed for custom multi-language and localization (L10N) situations.
To ensure functional requirements are met and unexpected events are handled correctly, guidance is provided for testing the [integration](#integration-testing) between your application(s) and Auth0, and for [unit testing](#unit-testing) individual extensibility modules (such as [Rules](/docs/customize/rules/debug-rules), [Hooks](/docs/customize/hooks/update-hooks), and Custom Database scripts). Guidance is also provided regarding Auth0's [penetration testing policy](/docs/troubleshoot/customer-support/operational-policies/penetration-testing-policy) to help when testing for security vulnerability, and also how [Mock](#mock-testing) testing can be leveraged in conjunction with our [load testing policy](/docs/troubleshoot/customer-support/operational-policies/load-testing-policy) to help ensure your application(s) perform under unexpected load.
## Unit testing
The objective of unit testing is to test individual units of code. If you create custom code within Auth0 in the form of Rules, Hooks, and/or Custom DB scripts, you should consider use a testing framework (such as [Mocha](https://mochajs.org/)) to test your code. Companies who have been most successful with Auth0 have found it useful to execute these unit tests prior to [automatically deploying](/docs/get-started/architecture-scenarios/business-to-business/deployment) Auth0 tenant configuration and collateral.
## Integration testing
It is a recommended best practice that you set up different tenants for development, testing, and production as discussed in Architecture guidance for [SDLC support](/docs/get-started/architecture-scenarios/business-to-business/architecture#sdlc-support). Auth0 allows you to configure variables that are available from within custom [extensibility](/docs/customize/extensions); these can be thought of as environment variables for your Auth0 tenant. Rather than hard code references that change when moving code between development, test, and production environments, you can use a variable name that is configured in the tenant and referenced by the custom extensibility code. This makes it easier for the same custom code to function, without changes, in different tenants as the code can reference variables which will be populated with tenant-specific values at execution time:
* For use of variables in Rules, see how to [configure values](/docs/customize/rules/configuration)
* For use of variables in Hooks, see how to configure [secrets](/docs/customize/hooks/hook-secrets) in the editor
* For use of variables in Actions, see Explore Flows and Triggers
* For use of variables in Custom DB Scripts, see the [configuration parameters](/docs/authenticate/database-connections/custom-db/create-db-connection#step-3-add-configuration-parameters)
We recommend using variables to contain tenant-specific values as well as any sensitive secrets that should not be exposed in your custom code. If your custom code is deployed in GitHub, then using a tenant-specific variable avoids exposure of sensitive values via your GitHub repository.
### Test automation
You can automate your overall build process by incorporating deployment automation as well as test automation. This can be used to deploy new versions of configuration and/or custom code to Auth0 and execute automated tests. If the tests uncover any failures, the deployment automation capabilities can be used to revert to the last working version. For further information, see the [deployment automation guidance](/docs/get-started/architecture-scenarios/business-to-business/deployment) provided.
## Mock testing
In a balance between Auth0’s [load testing policy](/docs/troubleshoot/customer-support/operational-policies/load-testing-policy) and the desire to load test, it is common practice among Auth0’s customers to mock out Auth0’s endpoints. This is a valuable practice in order to ensure that your application works with your expected interfaces without having to restrict your testing, and tools such as [MockServer](http://www.mock-server.com/), [JSON Server](https://github.com/typicode/json-server) or even [Postman](https://learning.getpostman.com/docs/postman/mock_servers/setting_up_mock/) can be used to assist.
## Project Planning Guide
We provide planning guidance in PDF format that you can download and refer to for details about our recommended strategies.
[B2B IAM Project Planning Guide](https://assets.ctfassets.net/cdy7uua7fh8z/63F0WOPJdVzsPMxV1Xvp8x/7a329487c5e890d8e820f6a48983b46a/B2B_Project_Planning.pdf)
## Multiple Organization Architecture (Multitenancy)
Many B2B platforms implement some form of isolation and/or branding for their customers' organization, and this can add complexity to any Identity and Access Management (IAM) system. If this applies to you, then we recommend you take some time to read through our guidance and best practice advice for this type of environment.
[Multiple Organization Architecture](/docs/get-started/architecture-scenarios/multiple-organization-architecture)
# Business to Consumer Architecture Scenarios
Source: https://auth0.com/docs/get-started/architecture-scenarios/business-to-consumer
Explains the architecture scenario B2C IAM with an eCommerce or SAAS application.
This guidance is relevant to **all** project stakeholders. We recommend reading it in its entirety at least once, even if you've already started your journey with Auth0. We provide a [B2C IAM Project Planning Guide](https://assets.ctfassets.net/cdy7uua7fh8z/3er1aEQ7Ul0q3c9leJWczR/b1f18b4c16abb7e78b01e4eb2b52bb8e/B2C_Project_Planning.pdf) in PDF format, details about how to get started with each phase of the implementation process, and [checklists](/docs/get-started/architecture-scenarios/checklists) to help you manage the tasks in each phase.
There are many different ways Auth0 can be integrated into the CIAM project architecture. Auth0's flexibility comprehensively supports many different use cases however your project may not require all of the capabilities provided by Auth0. Knowing what, when, and how best to implement something will help you focus on completing the necessary tasks at the right time.
Customers using Auth0 for Business-to-Consumer (B2C) projects typically share a common set of goals and objectives, and in the sections that follow we'll focus on our real-world customer implementation experiences to help you deliver your solution efficiently.
# Business-to-Consumer Architecture
Source: https://auth0.com/docs/get-started/architecture-scenarios/business-to-consumer/architecture
Learn how to configure your Auth0 tenant architecture affects your Business to Consumer (B2C) Identity and Access Management (IAM) implementation.
Understanding your application is key to understanding how Auth0 can be leveraged to meet your needs. From experience, our most successful customers start with a visualization of their proposed - or in many cases existing - architecture and use this as a basis for reference as they progress. Understanding where your application fits within your organization is also important; Auth0 [Accounts and Tenants](/docs/get-started/auth0-overview/create-tenants) form the basis for the grouping and structuring of Auth0 assets, and it may be that you’ll need to leverage an existing Auth0 deployment in order to integrate with [Single Sign-on (SSO)](/docs/authenticate/single-sign-on), centralized user [Profile Management](/docs/get-started/architecture-scenarios/business-to-consumer/profile-management), consolidated billing, or the like.
If you do have multiple applications, and you need to leverage SSO, then we recommend you check out our [How to Implement Single Sign-On](https://auth0.com/learn/how-to-implement-single-sign-on/) training guidance before continuing.
The value of investing time on the landscape of the architecture up-front is something that we have found pays dividends in the long run, and there are a number of things you will want to consider when looking at functionality and workflow:
* What should the URL look like when Auth0 needs to present a web page to a user?
* How can Auth0 be structured to support your SDLC (Software Development Lifecycle)?
* How can you ensure that your Auth0 tenants are appropriately associated with your contract?
* What do you need to consider if there are other projects in your organization integrating with Auth0? Particularly projects that target their own, or a different domain of users (for example, applications that only employees will use)?
Organizations often service more than one domain of user - customers, employees, and affiliates being the most frequently encountered, with typically little to no cross-over: employees, say, don’t use the same applications as customers and vice-versa. In some cases there can also be a need to partition further within a domain - separate groups of customers, say, who use different and unconnected products. Auth0 provides a way to segregate your users and the associated collateral, and [tenant provision](#tenant-provision) covers this in more detail. If you need to provision an independent tenant then you’ll also want to [associate this with your existing Auth0 account](#tenant-association), so that you can take full advantage of the benefits provided at your organization’s contracted subscription level.
It’s not uncommon for companies to have identity requirements that address multiple user communities: customers, partners, employees, etc. So be sure to consider other projects or future requirements when designing your architecture.
In addition, you’ll undoubtedly have an established set of processes and procedures as part of your Software Development Lifecycle (SDLC). So you’ll want to check out our [SDLC support](#sdlc-support) guidance regarding Auth0 Tenant provision in support of that too.
For customer-facing applications, we typically see [OpenID Connect (OIDC)](/docs/authenticate/protocols/openid-connect-protocol) as being the most frequently used protocol. OIDC makes use of web based workflows with browser URLs that are presented to the user. Out-of-the-box, client facing URLs as part of Auth0 OIDC support are Auth0 branded, however we recommend using the Auth0 [custom domain](#custom-domains) capability to provide for consistent corporate identity and to also address potential user confidence concerns before they arise.
Other groups within your organization may also be working with Auth0; it’s not uncommon for our customers to have disparate departments that serve different user communities. Identifying these will potentially influence your design choices, and doing so early could mitigate decisions that might prove costly later on.
## Tenant provision
Everything starts with an Auth0 tenant. This is where you will be configuring your use of Auth0, and the where Auth0 assets - such as [Applications](/docs/get-started/applications), [Connections](/docs/authenticate/identity-providers) and [user profiles](/docs/get-started/architecture-scenarios/business-to-consumer/profile-management) are defined, managed and stored. Access to an Auth0 tenant is performed via the Auth0 [Dashboard](/docs/get-started/auth0-overview/dashboard), and via the Dashboard you can also create additional, associated tenants; you’re allowed to create more than one Auth0 tenant so that you can structure your tenants in a way that will isolate different domains of users and also support your [Software Development Life Cycle](#sdlc-support) (SDLC).
Tenant names cannot be changed, nor reused once deleted. So, make sure you're happy with your name(s) before you create your Auth0 tenants.
Determining the level of isolation you require when it comes to your user domains is an important step, and together with your branding requirements will subsequently help you determine the number of Auth0 tenants that will be required in your production environment. As we recommend you create a full suite of [SDLC supporting tenants](#sdlc-support) for every Auth0 tenant you will run in a production environment, the number of Auth0 tenants you will need to manage can quickly grow. Therefore you should consider carefully before creating multiple Auth0 tenants for production, and should consult our guidance on [Branding](/docs/get-started/architecture-scenarios/business-to-consumer/branding) before making your final decision.
## Tenant association
To ensure that your [tenants are all associated with your Auth0 contractual agreement](/docs/get-started/auth0-overview/create-tenants/child-tenants) and have the same features, ensure all your tenants are associated with your company account. If you have individual developers that want to create their own sandboxes for testing, make sure they get associated with your account so they have the same permissions too. To do this you should contact your Auth0 representative or the [Auth0 Support Center](https://support.auth0.com).
## Custom domains
When you setup your Auth0 tenant, the URL for accessing that tenant will be of the form `https://yourTenant.auth0.com`. Providing a [Custom Domain](/docs/customize/custom-domains) (also known as a vanity URL), for your Auth0 tenant is not only an important factor for supporting your Branding requirements, but more importantly will also provide you with security benefits too:
* Some browsers will, by default, make it difficult to communicate in an iFrame if you don't have a shared domain. For example, [Safari's ITP causes Auth0 token renewal issues](https://support.auth0.com/center/s/article/troubleshoot-auth0-token-renewal-issues-in-safari-with-itp-enabled).
* It's [harder to phish your domain if you have a vanity URL](https://auth0.com/blog/introducing-custom-domains-preview-with-auth0/), as the phisher must also create a vanity URL to mimic yours. For example, with a custom domain you can use your own certificate to get an "Extended Validation", making phishing even harder.
You are allowed only one custom domain per Auth0 Tenant. This is because a tenant in Auth0 is intended to represent a “domain” of users. If you need more than one vanity URL, then you likely have more than one domain of users and should be using multiple tenants.
Your custom domain name should also give the user confidence that this is the appropriate place to enter their credentials, and we recommend that you create your custom domain in all environments early on to ensure that you are testing consistently between environments. **It's extremely important to train your users to look for suspicious URLs when entering their credentials!**
Create a custom domain (a.k.a. `CNAME`) for your Auth0 tenant, and also create one in development too so you can ensure you have managed the `CNAME` correctly. For example, you could create a `CNAME` which maps `login.mycompany.com` to `mycompany-prod.auth0.com`.
In almost all cases, customers have been most successful when adopting a strategy of a centralised domain for authentication across multiple product or service brands. This strategy provides users with a consistent UX, and also mitigates the complexity of deploying and maintaining multiple Auth0 tenants in a production environment. If you are considering having multiple domains for different brands, please refer to the [Branding](/docs/get-started/architecture-scenarios/business-to-consumer/branding) guidance before you begin implementing.
## SDLC support
Every company has some form of Software Development Life Cycle (SDLC), and throughout the development process you will want to align with that strategy. For instance, you need to be able to test your integration with Auth0 in a similar fashion as you test the applications themselves. It is therefore important to [structure Auth0 tenants to support your SDLC](/docs/get-started/auth0-overview/create-tenants/set-up-multiple-environments), and there is a consistent pattern which our customers typically follow when it comes to the best practices associated with tenant layout for doing so:
| Environment | Sample Tenant Name | Description |
| - | - | - |
| Development | **company-dev** | A shared environment where most of your development work occurs |
| QA/Testing | **company-qa** or **company-uat** | An environment for formal testing of the changes you've made |
| Production | **company-prod** | The production tenant |
In some cases you may also want to create one or more sandboxes (e.g., **company-sandbox1**, **company-sandbox2**) so that you can test changes without compromising your development environment. This might be where you test deployment scripts and the like.
You can also take advantage of our [Implementation Checklists](/docs/get-started/architecture-scenarios/checklists) that you can download and customize to meet your implementation project needs.
## Project planning guide
We provide planning guidance in PDF format that you can download and refer to for details about our recommended strategies.
[B2C IAM Project Planning Guide](https://assets.ctfassets.net/cdy7uua7fh8z/3er1aEQ7Ul0q3c9leJWczR/b1f18b4c16abb7e78b01e4eb2b52bb8e/B2C_Project_Planning.pdf)
# Business-to-Consumer Authentication
Source: https://auth0.com/docs/get-started/architecture-scenarios/business-to-consumer/authentication
Design authentication for a B2C IAM Auth0 implementation using Universal Login and a mix of social and database connections to support consumer signup.
To provide services to your users, you must be able to identify who those users are. This process is called User Authentication. There are a number of ways to perform authentication of a user—via social media accounts, username and password, passwordless—and it's often recommended that you go beyond a first factor for authenticating the user by enabling multi-factor authentication (MFA).
Consider both security and user experience when designing how you will authenticate your users. Providing for multiple primary factors, and/or enforcing more than one factor during authentication, are ways that you can provide both.
There are a number of things you will want to consider when looking at functionality and workflow:
* Where will users enter their credentials?
* How will you keep user credentials safe?
* How will you maintain your authentication system?
* How can you provide password authentication for your users?
* How can you prevent hackers from trying to log in as your users?
* How will you implement authentication in different kinds of applications?
* How can you make login easy for your users when they come from different language backgrounds?
* How will you provide a good user experience as you migrate away from any legacy authentication system?
* What should you consider when integrating applications with Auth0?
* Can users log in using their existing social (e.g., Facebook or Google) accounts?
* Do you need to provide multi-factor authentication?
* What do you do if you have a service that doesn't have a way for the user to log in ahead of time?
* Can you pass the same user access token from one API to another?
Auth0 [Universal Login](#universal-login) provides users with a safe and secure experience—no matter whether you choose to provide for user ID/password credentials sign in, or allow the so-called Bring Your Own Identity scenarios provided via [Social Login](https://auth0.com/learn/social-login/). There are also brand recognition benefits to centralizing the login experience with Universal Login, even if you feel you will also have product-specific [branding](/docs/get-started/architecture-scenarios/business-to-consumer/branding) requirements. The Auth0 UI widgets typically used with Universal Login also provide out-of-the-box support with regards to [internationalization](/docs/customize/internationalization-and-localization/universal-login-internationalization) for users with different language requirements, and out-of-the-box support for Auth0 features such as [MFA](#multi-factor-authentication-mfa-) and [attack protection](#anomaly-detection) allow you to put barriers in place in order to prevent hackers attempting to access users' accounts.
Allowing users to sign in via user ID/password credentials means that you're not reliant on the status of third-party identity providers for your users to access your system. You also have the means to require the credentials used to align with your corporate policies. Auth0 assists with this by providing you with multiple options in support of user ID/password logins, and the [guidance provided](#username-and-password-authentication) will help you understand you can leverage these options. Adding [social](#social-authentication) support at some stage, as an additional primary authentication factor, gives you added flexibility and can help you better understand your users without the need to question them further by leveraging the information already stored by the various social login [providers](/docs/authenticate/identity-providers/social-identity-providers).
If you have an existing legacy identity store, you’ll also want to see [User Migration](/docs/get-started/architecture-scenarios/business-to-consumer/provisioning). This section discusses the advantages of migrating to Auth0’s managed identity storage in terms of safety and security.
For customer facing applications, OpenID Connect ([OIDC](/docs/authenticate/protocols/openid-connect-protocol)) is the most frequently used industry standard protocol, and OIDC has first-class citizen support in Auth0. Auth0 provides support for various different approaches for integrating various different applications, so you'll want to see the section on [application integration](#application-integration) for the information you'll need to make an informed choice.
When calling one API from another API, or from any situation where there is no authenticated user context—such as one or more cron jobs, report generators, or continuous integration/delivery systems—you will need a way to authorize the application instead of a user. This is a one step process where the application is authenticated (using a client ID and secret) and then authorized in one call. You can learn more about this in our authorization workstream under [machine-to-machine (m2m) authorization](/docs/get-started/architecture-scenarios/business-to-consumer/authorization).
## Universal Login
Do you have, or will you have, more than one application in your system? If the answer to this question is yes, then you will want a centralized sign in experience. To achieve a seamless Single Sign-on (SSO) experience between multiple applications, it is critical to have a centralized location to redirect your users for authentication. This allows you a way to provide your users with a consistent experience if you add social authentication in the future, add third party applications to your system, or add multi-factor authentication as an option (or requirement) for your users—and also allow you to take advantage of new features for improving your users’ experience with little, if any, added development effort.
If you have more than one application, the best practice is to redirect to a [centralized location](/docs/authenticate/login/auth0-universal-login) to authenticate the user. With Auth0, this means taking advantage of [Universal Login](/docs/authenticate/login/auth0-universal-login), which provides many security and user experience benefits out-of-the-box, including [SSO](/docs/authenticate/single-sign-on).
Auth0 Universal Login makes authenticating users a short, easy process which can be accomplished in three easy steps (all of our Quickstarts demonstrate this and our SDKs hide the complexity for you too):
1. Determine how and when you want to [redirect from your application](#application-integration).
2. Set up the appropriate [branding](/docs/get-started/architecture-scenarios/business-to-consumer/branding) and/or customized HTML in your Auth0 configuration.
3. Set up your application to [receive and handle the response](#application-integration) from the Authorization Server.
## Username and password authentication
Nearly every B2C application provides the ability for their customers to create a new set of credentials. This is a common form of authentication that all users are familiar with.
Username password authentication comes in multiple flavors at Auth0. If your application is a green-field application with no existing user base, then a simple Auth0 out-of-the-box [Database Connection](/docs/authenticate/database-connections) will give you everything you need to start authenticating your users. However, if you have a legacy user store—such as your own database of users or an existing LDAP system—you have a couple of different options for migrating your users as discussed in our guidance on [User migration](/docs/get-started/architecture-scenarios/business-to-consumer/provisioning).
However you end up provisioning the users for your database connection, the authentication of those users is quite similar. It requires you to present users with a form to enter their username and password. As mentioned in the guidance concerning [Universal Login](#universal-login), the simplest and safest way to authenticate users with a username and password is to redirect them to a centralized login page and collect their username and password there. This allows Auth0 to determine whether they have already authenticated and skip the login form entirely when it's not needed.
Collecting credentials only at the centralized login page will reduce the surface area for potential leak of user secrets. It will also reduce the need to collect credentials unnecessarily. See [Universal Login](#universal-login) for more information.
## Application integration
Once you've figured out how you want to authenticate your users, the next step is to determine how you will initiate that authentication. Each application will typically have its own starting point.
Native mobile applications (and desktop applications) should use the system browser for authentication, or they open themselves up to additional security risks. See [Native Login](/docs/authenticate/login/native-login) for more information.
As discussed, we've found that most of our customers use [OpenID Connect (OIDC)](/docs/authenticate/protocols/openid-connect-protocol) as the industry-standard protocol when it comes to their customer-facing applications. Figuring out which OIDC flow to use is your first task, and you will want to start by reviewing the our [grant mapping](/docs/get-started/applications/application-grant-types) guidance in the first instance.
If you want to allow anonymous users access to any part of our application then you need to determine if you will be redirecting right away or prompting your users to redirect only when required (or perhaps some combination of both; see [Redirect Users After Login](/docs/authenticate/login/redirect-users-after-login) for further discussion). If users can [deep link](#deep-linking-to-protected-endpoints) to a protected version (or area) of your site then you will need to determine the links to your application that will result in an automatic redirect to Auth0.
### Anonymous access
It is important to consider the user experience when someone first comes to your application. If your application supports anonymous user access (quite common for eCommerce applications) there are different scenarios to consider:
* Are they returning to the application after having already logged in, or
* If this is the first time they are accessing the application:
* Have they already accessed a different application that uses the same Auth0 tenant,
* Have they ever (or perhaps not in a long time) authenticated on this device or browser.
When an anonymous user accesses your application, it can often be desirable for the application to discover if the user has already logged into a different application in the same family, or to remember this user even if the application is a [SPA](/docs/quickstart/spa) with no state. For example, if you can determine that the user is already logged in, you might decide to have the UI header in the application skip displaying a login button and instead have an account or profile menu for the user. To accomplish this you will want to utilize "[silent authentication](/docs/authenticate/login/configure-silent-authentication)". Silent authentication will allow you to check to see if the user is logged in without prompting them to log in if they are not. Then the application can present a login button if necessary. If the user is logged in already, however, then you will receive tokens and will not have to present the user with a login button again.
Checking for a login session by redirecting to Auth0 can be helpful for your application, but if this will result in a lot of requests, you should employ a throttling mechanism to avoid latency and/or rate limiting.
Calls to the Management API are subject to [Auth0 Rate Limiting policy](/docs/troubleshoot/customer-support/operational-policies/rate-limit-policy). You must take this into consideration, and to assist, Auth0 generally recommends use of the appropriate [Auth0 SDK](/docs/libraries) for your development environment rather than calling our APIs directly.
### Deep linking to protected endpoints
There are a variety of reasons why someone might link directly to a particular page within your application that is only accessible by authenticated users. If this is possible for your application you should automatically redirect your user to Auth0 if they are not authenticated. Once they authenticate and the authorization server returns them to your application, you can [redirect them](/docs/authenticate/login/redirect-users-after-login) to where they intended to go in the first place.
### Best Practice
Most modern authentication frameworks support middleware for redirecting to an authorization server such as Auth0. When selecting one, here are some key considerations:
* Support for confidential clients, non-confidential clients, or both
* Support for configuration via [discovery endpoint](/docs/get-started/applications/configure-applications-with-oidc-discovery "Configure Applications with OIDC Discovery") or explicitly inline
* Support for token validation including expirations, signatures, claims and scopes
* Support for Refresh Tokens if needed
### Authenticating the user
Authentication is the process of determining user identity. The result of authentication in an OIDC context is an ID Token. This token contains information about the user and should only be able to be obtained if the user authenticates using one or more factors as defined by the authorization server (the most common form being [user ID and password](#username-and-password-authentication)). There are a few things you may also need to consider in addition to obtaining an ID Token:
* Do we also need an [Access Token](/docs/secure/tokens/access-tokens) in order to call a shared API?
* Is your application a single-page application and only requires an [ID Token](/docs/secure/tokens/id-tokens)? See [Authorization Code Grant with PKCE](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow-with-pkce/call-your-api-using-the-authorization-code-flow-with-pkce) for more information.
* Is your application a native application (mobile or desktop) and/or do you need a [Refresh Token](/docs/secure/tokens/refresh-tokens)? See [Authorization Code Grant with PKCE](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow-with-pkce/call-your-api-using-the-authorization-code-flow-with-pkce) for more information.
Before you go live, you should ensure that **only** the grants that you are using for each application are enabled in your [configuration for your Application](/docs/get-started/applications/update-grant-types).
### Authorization code grant (with or without PKCE)
If your SDK only supports the Authorization Code grant, or you need an Access Token or Refresh Token, then Authorization Code grant (with or without [PKCE](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow-with-pkce)) can also be used to retrieve an ID Token. The Authorization Code grant includes an additional API call to exchange the code for a token which can result in additional unnecessary latency if all you need is the ID Token. In many cases the [hybrid flow](/docs/get-started/authentication-and-authorization-flow/hybrid-flow) is implemented to provide optimum access to the ID Token while still leveraging Authorization Code grant workflow for the secure and safe retrieval of Access and Refresh Tokens.
While Auth0 supports the use of implicit grant for browser-based applications requiring only an ID Token, it is recommended to use authorization code grant with [PKCE](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow-with-pkce). For detailed information, see [OAuth2 Implicit Grant and SPA](https://auth0.com/blog/oauth2-implicit-grant-and-spa/) on the Auth0 Blog.
If you need a [Refresh Token](/docs/secure/tokens/refresh-tokens) so that you can obtain a new Access Token or ID Token without having to re-authenticate the user, then you must use the [authorization code grant](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow/call-your-api-using-the-authorization-code-flow).
## Attack protection
The reason that authentication systems are important is to prevent bad actors from accessing applications and user data that they should not. We want to place as many barriers as possible between those bad actors and access to our systems. One of the easiest ways to do this is to ensure that your [attack protection](/docs/secure/attack-protection) with Auth0 is configured correctly, so take a moment to read the guidance on this subject and ensure that it's working correctly for you.
Anomaly detection is handled behind the scenes by Auth0 and provides a great security feature for your product. If you're going to utilize it, ensure that you have set up your [Email Provider](/docs/get-started/architecture-scenarios/business-to-consumer/operations#email-provider-setup) and configured your [Email Templates](/docs/get-started/architecture-scenarios/business-to-consumer/branding#email-template-customization) before turning on email delivery to your users.
## SSO with legacy systems
In a large scale re-structure it's not always possible—or practical—to update all your applications at once. In fact, our recommended best practice is to plan for an iterative-style approach when it comes to integrating with Auth0. If your applications already participate in Single Sign-on (SSO), and your legacy identity system supports protocols such as OIDC or SAML, then you have a couple of options available if you want to continue to provide SSO as you integrate with Auth0:
* Update your existing identity provider in your legacy SSO system to redirect to Auth0 for login (e.g., using [SAML](/docs/authenticate/single-sign-on/outbound-single-sign-on/configure-auth0-saml-identity-provider)), or
* Have Auth0 redirect to your legacy SSO system to login. This requires configuring your legacy system as an IdP in Auth0 (i.e., either using [SAML](/docs/authenticate/protocols/saml/saml-sso-integrations/configure-auth0-saml-service-provider) or [OIDC](/docs/authenticate/identity-providers/social-identity-providers)).
Supporting an SSO experience with your legacy system can add complexity, but may be worth it to generate a more seamless user experience as you integrate with Auth0. If you intend to go down this path, planning for it early can help ensure that it is possible to achieve. If you don't already have SSO at a centralized service, then the complexity to add it will unlikely be worth the benefits.
This is a complex topic that will likely need some additional investigation depending on your current legacy architecture, and we recommend you only look into this if you currently have SSO support in your legacy system. Note: if you are currently redirecting from your applications to a centralized system to authenticate your users and that system only asks for credentials if you don’t already have a session with the centralized system, then you have a legacy SSO implementation.
## Social authentication
The “bring your own identity” scenario offered by Facebook, Google, etc., is a valuable way of simplifying the user authentication experience without compromising security, and using [Universal Login](#universal-login) makes it easy to start adding support for [Social Connections](/docs/authenticate/identity-providers/social-identity-providers) with minimal disruption.
Auth0 provides a simple way to test social connections using [pre-configured developer keys](/docs/authenticate/identity-providers/social-identity-providers/devkeys). However, these have [limitations](/docs/authenticate/identity-providers/social-identity-providers/devkeys#limitations-of-developer-keys), and before going into production, you’ll need to set up your own application-specific keys by following the [instructions](/docs/authenticate/identity-providers/social-identity-providers) for your chosen social provider(s).
With [social](https://auth0.com/learn/social-login/) support, user identities and credentials are managed by the social provider, as are certain identity claims, which Auth0 will use to populate the user [profile](/docs/get-started/architecture-scenarios/business-to-consumer/profile-management). Auth0 can also provide access to Social Identity Providers' (Social IdPs') [Access Tokens](/docs/secure/tokens/access-tokens), so that your application can also call third-party Social IdP APIs on behalf of the user.
Social is a great feature to provide, but when you offer more than one way to sign in, you need to consider the possibility that your customers will actually use more than one way to sign in. By default, every user identity in Auth0 has its own user profile, so you’ll probably want to consider Auth0's capability to [link user accounts](/docs/manage-users/user-accounts/user-account-linking) to provide an effective way of associating one user profile with multiple identities.
The Auth0 [Custom Social Connections extension](/docs/authenticate/identity-providers/social-identity-providers) extends social authentication even further by allowing you to connect with any [OpenID Connect (OIDC)](/docs/authenticate/protocols/openid-connect-protocol) third-party-compliant vendor not supported out of box. For example, support for the government-issued-identity provider [SwissID](https://www.swissid.ch/) can be configured in Auth0 by using a Custom Social Connection.
## Multi-factor authentication (MFA)
In an era where misuse of user credentials is at an all-time high, protecting your systems when it’s so common for hackers to steal users identity information in general is a challenge. One of the most effective ways though is to provide users with the ability to configure a second factor for protecting their account. More commonly referred to as [Multi-Factor Authentication](/docs/secure/multi-factor-authentication). This will ensure that only a valid user can access their account, even if they use a username and password that may have been compromised from a different application.
It's quite common for customer facing applications to provide users with an *option* for adding a second factor rather than *forcing* them to use a second factor. For more information regarding this, see [providing your users with an option to add MFA](https://auth0.com/learn/multifactor-authentication-customers/).
Auth0 supports a number of different options when it comes to enabling MFA for protecting user account access, and there are several practices to ensure that you will truly be providing a flexible second factor barrier to access:
* Auth0 [Guardian](https://auth0.com/multifactor-authentication): a service that provides both Push notification generation and an application for allowing or denying requests. Push sends notification to a user’s pre-registered device—typically a mobile or tablet—from which a user can immediately allow or deny account access via the simple press of a button.
* Time-based One-Time Password ([TOTP](https://auth0.com/blog/from-theory-to-practice-adding-two-factor-to-node-dot-js/)): allows you to register a device—such as Google Authenticator—that will generate a one-time password which changes over time and which can be entered as the second factor to validate a user’s account.
* SMS: for sending a one-time code over SMS which the user is then prompted to enter before they can finish authenticating.
* Voice: for delivering a one-time code through a phone call which the user is then prompted to enter before they can finish authenticating.
* Duo: allows you to use your Duo account for multi-factor authentication.
* Email: allows you to use your email account for multi-factor authentication.
Whilst MFA workflow using technologies such as Guardian or Google Authenticator is typically provided via a separate application that runs on a mobile or tablet device, if you don’t want your customers to have to download a separate application Auth0 also provides you with an [SDK](https://auth0.com/blog/announcing-guardian-whitelabel-sdk/) that you can use to build second factor workflow right in your existing mobile device application(s).
## Project Planning Guide
We provide planning guidance in PDF format that you can download and refer to for details about our recommended strategies.
[B2C IAM Project Planning Guide](https://assets.ctfassets.net/cdy7uua7fh8z/3er1aEQ7Ul0q3c9leJWczR/b1f18b4c16abb7e78b01e4eb2b52bb8e/B2C_Project_Planning.pdf)
# Business-to-Consumer Authorization
Source: https://auth0.com/docs/get-started/architecture-scenarios/business-to-consumer/authorization
User authorization and related planning considerations for your B2C IAM implementation.
Let's start by taking a step back and talking about Access Control. There isn't one clear cut definition of Access Control in the industry, but if you spend some time searching and reading you'll see that most authoritative sources agree that it is the umbrella concept that puts all of Authentication, Authorization, Consent, and Policy Enforcement together to ensure that only the right people and services have access to your applications and APIs. Next, let's look more closely into the distinctions between Authentication, Authorization, Consent, and Policy Enforcement. Your Auth0 tenant (your Authorization Server) is typically responsible for Authentication and Consent, and some or all of Authorization and Policy Enforcement. Additionally, an Application or API itself almost always is the primary enforcer of policies, especially where contextual access is required:
* **Authentication**: the process of determining if a principal (a user or application) is who or what they say they are.
* **Authorization**: the process of determining what is allowed, based on the principal, what permissions they have been given, and/or the set of contextually specific access criteria.
* **Consent**: what permissions the user (Resource Owner) has given permission to an application to do on its behalf. This is generally a requirement of delegated authorization. The user has to give permission to the Client to access the user's data in a different system.
* **Policy Enforcement**: The act of enforcing the policies of the application or API, rejecting or allowing access based on a user's authentication and/or authorization information.
In general we typically group different types of access control into three distinct categories so that it's easier to understand a) which actor is responsible for storing the information, b) which actor is responsible for making decisions, and c) which is responsible for enforcing the restrictions.
* The first category is where access is either granted or denied to an application or an API in its entirety. Both the data required to enforce this and the enforcement process is typically defined in the context of the Authorization Server For example, by using [`app_metadata`](/docs/manage-users/user-accounts/metadata) associated with a user and a [Action](/docs/customize/actions) defined in your Auth0 tenant.
* The second category is where access is either granted or denied to a specific subset of application or API functionality. The data required to enforce this is typically stored in the Authorization Server For example, by using `app_metadata` on a user in your Auth0 tenant with the enforcement process performed in the application or API itself. In this scenario, the data is typically communicated as one or more custom claims in an [`id`](/docs/secure/tokens/id-tokens) or [`access`](/docs/secure/tokens/access-tokens) token.
* The third category is where access is either granted or denied depending on what the principal (subject) can operate on within the context of an application or API. Both the data required to enforce this, and the enforcement process is typically defined in the context of the application or API. In this scenario, the data communicated as one or more custom claims in an `id` or `access` token may be consumed with or without data from an external source that is not Auth0.
In addition, Role-based Access Control (RBAC) and Attribute-based Access Control (ABAC) mechanisms can be applied in any of the Access Control categories described above. Whatever your use case then, there are a number of things you will want to consider when looking at the functionality and workflow you require:
* Are there scenarios where access to an entire application or API should be rejected?
* Will you be providing APIs that can be accessed by third-party applications?
* Will your APIs also be accessed by your own (first-party) applications?
* Will your application be calling a third-party API?
* Should your applications and/or APIs be enforcing access control based on user claims?
Auth0 supports access restriction for either applications or APIs based on certain conditions. In certain scenarios, you may want to create an Action that denies access using `api.access.deny()` when, for example, a user attempts access to an application or an API at an incorrect time (as described in this [example](/docs/manage-users/access-control/sample-use-cases-actions-with-authorization#allow-access-only-on-weekdays-for-a-specific-application)) - or if the user doesn’t have the right claim(s) contained in their `app_metadata`. For an application using [OpenID Connect (OIDC)](/docs/authenticate/protocols/openid-connect-protocol), this would prevent the allocation of the [ID Token](/docs/secure/tokens/id-tokens) used to authorize access. Similarly, for an API, allocation of any OAuth2 [Access Token](/docs/secure/tokens/access-tokens) (used when calling the API), could be prevented as described in this [example](/docs/manage-users/access-control/sample-use-cases-actions-with-authorization#deny-access-to-anyone-calling-an-api).
In the main, we have found that [OIDC](/docs/authenticate/protocols/openid-connect-protocol) is the most commonly used industry-standard protocol used by Auth0 customers when it comes to authentication in their applications. We have also found that, even though [OAuth2](/docs/authenticate/protocols/oauth) was created as a delegation protocol, it is commonly used within first party applications when there is an API that does not have a shared session with the application.
Auth0 also can provide the information needed so that an application can enforce restrictions. For [application level integration](#application-integration), Auth0 allows you to add [custom claims](#id-token-claims) to an ID Token, which your application can then verify and subsequently use to perform policy enforcement. In this case you will need to decide what information you require for your application to make enforcement decisions. If you need to make decisions at an API instead of in your application, you will likely need to use an Access Token instead of an ID token. Continue reading for more information.
When deciding what data to include in your ID token and/or access token, consider token size, especially if you are passing the token in the URL. Even if you are not passing tokens in the URL, you will also need to consider the potential of exposing sensitive PII (Personally Identifiable Information). Token information is not encrypted, so although it isn't generally a security issue for an ID token to be leaked, it can become a privacy issue depending on the data that is included in the token.
For [API level integration](#api-integration), Auth0 supports both [custom claims](#access-token-claims) as well as [scope](#access-token-scopes) re-configuration, both within the context of an Access Token. Again, you will need to decide what information will be required in order for your API to make access decisions, and your API will need to enforce that by validating the contents of the Access Token.
When deciding whether you should use permissions through custom claims or scopes, you should make sure you understand the nature and purpose of scopes. There is a nice [blog post](https://auth0.com/blog/on-the-nature-of-oauth2-scopes/) on that which is easy to read and helps clear up the topic.
## Application integration
In this scenario, your Auth0 tenant provides a token as an indicator of authorized access to an application. For applications utilizing [OpenID Connect (OIDC)](/docs/authenticate/protocols/openid-connect-protocol), the industry-standard protocol we typically find most utilized when it comes to customer facing applications, this would be an ID Token expressed as a [JWT](/docs/secure/tokens/json-web-tokens).
### ID Token claims
Using Action extensibility, Auth0 allows you to easily [add custom claims to an ID Token](/docs/get-started/apis/scopes/sample-use-cases-scopes-and-claims#add-custom-claims-to-a-token) based on, for example, a user’s [Metadata](/docs/manage-users/user-accounts/metadata) content. Your application can then verify the ID Token for the necessary claims, and either allow or prevent access to certain functionality as required. Note that though the process of adding custom claims via Action is streamlined, the Action runtime is flexible and allows you to write custom code that may have negative effects.
When you are considering adding custom claims, we recommend that you store any access control data you may need to include within claims as part of the user's [`app_metadata`](/docs/manage-users/user-accounts/metadata). Firstly, this prevents you from needing to call an external API to fetch the data, which can negatively impact the performance and scalability of the login sequence. Secondly `app_metadata` **cannot** be modified by a user - so the user cannot directly circumvent any access control restrictions by modifying their own metadata. Also remember to check out our [metadata best practices](/docs/get-started/architecture-scenarios/business-to-consumer/profile-management#metadata) guidance too.
### ID Token scopes
[OIDC Scopes](/docs/get-started/apis/scopes/openid-connect-scopes) are typically used by an application to obtain consent for authorized access to a user's details during authentication. Each of the pre-defined scopes returns the set of standard claims where defined, and as described in the [OIDC specification](https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims). The scopes an application requests depend on which user attributes the application needs. Once the requested scopes are authorized by the user, the claims are returned in the ID Token and are also made available via the [/userinfo](https://auth0.com/docs/api/authentication#get-user-info) endpoint.
## API integration
In this scenario your Auth0 tenant can provide an OAuth2 [Access Token](/docs/secure/tokens/access-tokens), typically expressed as a [JWT](/docs/secure/tokens/json-web-tokens), which can be used by your API to restrict access to certain parties. In addition, Auth0 provides support for what is notionally described as both [First-Party and Third-Party Applications](/docs/get-started/applications/first-party-and-third-party-applications).
Acting as the authorization server, and with the consent of the user (the resource owner), your Auth0 tenant can be used to provide an Access Token - typically expressed as a [JWT](/docs/secure/tokens/json-web-tokens) - to an application (client) so that it can access a protected resource hosted by a resource server on behalf of the resource owner. The issued Access Token is typically passed as the Bearer token in the HTTP Authorization header sent to an API.
Whether you have a single API, or perhaps a suite of logically related [microservice APIs](/docs/get-started/apis/set-logical-api), you can leverage the Access Tokens that Auth0 provides in order to secure access to your service(s). Though relatively easy to set this up in the [Auth0 Dashboard](https://manage.auth0.com/) or through the [Auth0 Management API](https://auth0.com/docs/api/management/v2#!/Resource_Servers/post_resource_servers), it's important to review the different application scenarios and API layouts to determine the best architecture for your system.
OAuth2 Access Tokens are primarily designed for use in securing public facing APIs; when expressed as a JWT, an Access Token is a self contained entity which can be verfied without the need to make any additional 3rd party API call. If your APIs do not fall into this category - i.e they are part of an application itself (as in only called by that application) or are sat behing your firewall - then protecting them with tokens may well be overkill, and your existing cookie based (et al) workflow may well suffice.
OAuth2 was designed specifically with third-party access in mind, for example, a scenario might be that a user (resource owner) wants to use an application (a client) that does not belong to the same organization as the service that provides the user's data (the resource server). In this case, when the application needs to access data that the user owns, it redirects to the organization where the user’s data resides, which in turn authenticates the user and then prompts the user to give the application permission to access their data. This prompting for permission is referred to as providing [consent](/docs/get-started/applications/third-party-applications/user-consent-and-third-party-applications) and is a large part of what providing support for [third party applications](/docs/get-started/apis/scopes/api-scopes#example-an-api-called-by-a-third-party-application) entails. If you are planning to integrate third-party applications, then it's important you mark them as third-party early on so that Auth0 will handle prompting for user consent.
On the other hand, if your organization owns the application(s), the user data itself and the API(s) through which that data is accessed, then consent is not typically required as the interactions are all [first-party](/docs/get-started/apis/scopes/api-scopes#example-an-api-called-by-a-first-party-application). If you're only creating first-party applications, then you can ensure that you are not presenting your users with any unnecessary consent screen(s) by [allowing user consent to be skipped](/docs/get-started/apis) as part of any resource service definition.
Though you can configure your applications to be first-party and subsequently configure your APIs to allow first-party clients to ignore consent, if you are using `localhost` then Auth0 cannot verify that the application is truly a first-party app so your users will be prompted for consent anyway. To work around this constraint, when testing on your local machine during development, create a [fake local hostname and use that instead](https://community.auth0.com/t/how-do-i-skip-the-consent-page-for-my-api-authorization-flow/6035).
Alternatively, you may have data relating to a user for which additional [functionality is provided](/docs/get-started/apis/scopes/api-scopes#example-an-api-called-by-a-back-end-service) and for which explicit user consent cannot be obtained (i.e. there is no authenticated user who can provide it). In this scenario, a [list of applications for which Client Credentials grant is enabled](/docs/get-started/authentication-and-authorization-flow/client-credentials-flow) can be defined.
### Access Token claims
As is the case with ID Tokens, you can [add custom claims to Access Tokens](/docs/get-started/apis/scopes/sample-use-cases-scopes-and-claims#add-custom-claims-to-a-token) using Auth0 Action extensibility. Once added, your API can then verify an Access Token for the necessary claims and either allow or prevent access to certain functionality as required.
When you are considering adding custom claims, we recommend that you store any access control data you may need to include within claims as part of the user's [`app_metadata`](/docs/manage-users/user-accounts/metadata). Firstly, this prevents you from needing to call an external API to fetch the data, which can negatively impact performance and scalability. Secondly `app_metadata` **cannot** be modified by a user - so the user cannot directly circumvent any access control restrictions by modifying their own metadata. Also remember to check out our [metadata best practices](/docs/get-started/architecture-scenarios/business-to-consumer/profile-management#metadata) guidance too.
### Access Token scopes
[OAuth2 Scopes](/docs/get-started/apis/scopes/api-scopes) are typically used as the mechanism by which an API can determine what actions can be performed on behalf of a user. Scopes can be added on a per API basis to [define specific access permissions](/docs/get-started/apis/add-api-permissions) in the Auth0 Dashboard or through the Auth0 Management API. Scopes can also be manipulated via Auth0 extensibility (e.g. via an Action, as in this [example](/docs/get-started/architecture-scenarios/spa-api/part-2#create-an-action-to-validate-token-scopes)). The scopes an application requests for accessing an API should depend on what functionality the application needs the user to give permission for the application to use. Once the requested scopes are authorized, they will be returned in the Access Token which can be subsequently [verified by said API](/docs/secure/tokens/access-tokens/validate-access-tokens). A good example of this is when you log in to an application that is using a social provider for login: the social provider API requires that the application specifies whether the user will want the application to post items on your behalf. This allows the user to accept or deny this request. This example demonstrates how the user is delegating permission to the application - which is different than the API restricting access based on a user's role, and should be handled differently.
Even though you have the ability to fully manipulate Access Token Scopes via Auth0 extensibility, as a security best practice you should only remove scopes which are not authorized and refrain from adding scopes that were not requested.
Though scopes are often used as a way to enforce access permissions for a user, there are situations where it can become [tricky when you use them in this manner](https://auth0.com/blog/on-the-nature-of-oauth2-scopes/). We therefore recommend that you use scopes for their intended purpose (i.e. delegating permission to an application) and use [custom claims](#access-token-claims) for your role-based or other access control scenarios.
## Fine Grained Authorization (FGA)
[Fine Grained Authorization](https://docs.fga.dev/fga-concepts) allows you to grant individual users access to a specific resource or object based on:
* A user's role within an organization, such as `editor` or `admin`
* An attribute of the user or object, such as `manager` for a user or `marketing` for an object
* A relationship between a user and an object, such as a user with view access to a parent folder also has view access to the child folder
With FGA, you can create an authorization model to determine what relationship you want to determine user access.
## Role Based Access Control (RBAC)
Auth0 has out-of-box support for Role Based Access Control ([RBAC](/docs/manage-users/access-control/rbac)). RBAC refers to assigning permissions to users based on their role within an organization, and provides for simpler access control by offering a more manageable approach that is less prone to error.
## Machine-to-Machine (M2M) authorization
There are many scenarios that require an application without any user-interactive session to obtain an access token in order to call an API. In such scenarios you must authenticate the client instead of the user, and OAuth 2 provides the [client credentials](/docs/get-started/authentication-and-authorization-flow/client-credentials-flow) grant type to make this easy to achieve. Some common examples of where this is required include:
* A cron job or other service that needs to communicate with your API (e.g. where a daily report needs to be generated and emailed it to an administrator).
* A separate API the supports privileged access (e.g. the API is not exposed to users directly, but instead to a backend only).
* In certain microservice architectures, where some API layers need to communicate to other API layers without a user involvement, or after a user token has expired.
* A privileged API that may need to be called before a user has authenticated (i.e. from an action or custom DB script in your Auth0 tenant)
Traditionally, a special "service account" would have been created in order to cater for these scenarios: a user with a username and password that was configured for services which supported non-interactive use cases. That is no longer a recommended approach for many reasons, and the current best practice is to use [OAuth 2.0 Client Credentials Grant](/docs/get-started/authentication-and-authorization-flow/client-credentials-flow) in these situations.
## Project planning guide
We provide planning guidance in PDF format that you can download and refer to for details about our recommended strategies.
[B2C IAM Project Planning Guide](https://assets.ctfassets.net/cdy7uua7fh8z/3er1aEQ7Ul0q3c9leJWczR/b1f18b4c16abb7e78b01e4eb2b52bb8e/B2C_Project_Planning.pdf)
# Business-to-Consumer Branding
Source: https://auth0.com/docs/get-started/architecture-scenarios/business-to-consumer/branding
How to configure Auth0 items to reflect your brand and desired user experience.
Auth0 can be customized with a look and feel that aligns with your organization's brand requirements and user expectations. Branding Auth0 collateral provides a consistent user experience for your customers, and gives them peace of mind that they’re using a product from a trusted and secure provider.
Auth0 provides support for [internationalization (I18N)](/docs/customize/internationalization-and-localization) and localization (L10N), both of which are important if you work on branding for an international clientele. Out-of-box collateral, such as the Auth0 Lock UI widget, comes ready enabled for multiple language support, with built-in extensibility for adding more languages if what you require [doesn’t already exist](/docs/customize/internationalization-and-localization/lock-internationalization).
Almost all applications need Internationalization and/or Localization in one form or another. Auth0 makes it easy to add, but you need to account for it up front: retro-fitting localization, for example, can be a painful process if left too late.
When considering the items you want to brand, as well as how best to brand them, there are a number of things you'll want to review:
* Do you need to brand your login page?
* Do you need to localize your login page?
* How can you customize emails so that they're not just branded, but vary based on user preference?
* How will users know that they're still on your domain when they see your login page?
* What do you need to do to provide additional browser security (e.g., implement Extended Validation)?
* Where do you want to direct users in the event of errors?
Auth0 provides tremendous flexibility when it comes to customizing and configuring Auth0 pages such as [Universal Login](#universal-login-and-login-pages) and [Password Reset](#password-reset-page-customization). So you can pretty much set up whatever UX look and feel you require. For many, the out-of-the-box experience - with perhaps a little alteration - is all that's required. However, for others the value of their brand and brand awareness requires more extensive customization. This flexibility extends to not only Auth0 pages, but via extensibility can also be applied to the [email templates](#email-template-customization). Auth0 [Custom Domain](#custom-domain-naming) functionality further enhances consumer awareness by providing users with the confidence and peace of mind when it comes to safety and security.
While Auth0 provides for default information when it comes to error situations, out-of-the-box information can be somewhat cryptic as the context that can only be provided by you is missing. Auth0 [error page customization](#error-page-customization) guidance can however help mitigate that by allowing you to provide information of a more context-specific nature via your own support organization.
To provide helpful resources for users who experience problems, you should also configure a friendly name and a logo, as well as provide the support email address and URL for your organization. To learn how, see [Dashboard Tenant Settings](/docs/get-started/tenant-settings#settings).
## Universal login and login pages
[Universal Login](/docs/authenticate/login/auth0-universal-login) is the recommended method for authenticating users, and it centers around use of the Login page. You can customize the Login page to support your organization's branding requirements.
If you choose to customize the Universal Login page script, we strongly recommend that you make use of version control. To do this, you should deploy the script to your Auth0 tenant via [deployment automation](/docs/get-started/architecture-scenarios/business-to-consumer/deployment) or via one of the [alternative strategies](/docs/customize/login-pages/classic-login/version-control).
## Custom domain naming
By default, the URL associated with your tenant will include its name and possibly a region-specific identifier. For example, tenants based in the US have the a URL similar to `https://example.auth0.com` while those based in Europe have something that is of the fashion `https://example.eu.auth0.com`. A [Custom Domain](/docs/customize/custom-domains) offers a way of providing your users with a consistent experience by using a name that’s consistent with your organization's brand.
Only one custom Domain Name can be applied per Auth0 Tenant, so if you absolutely must have independent domain name branding then you will require an [architecture](/docs/get-started/architecture-scenarios/business-to-consumer/architecture) where multiple Auth0 Tenants are deployed to production.
In addition, Custom Domain functionality offers you complete control over the certificate management process. By default, Auth0 provides standard SSL certificates, but if you configure a custom domain, you can use Extended Validation (EV) SSL certificates or similar to provide the visual, browser-based cues that offer your visitors additional peace of mind.
In general, we see customers having the most success when they use a centralized domain for authentication - this is especially the case if the company offers multiple products or service brands. By using a centralized domain, you can provide end users with a consistent user experience while also minimizing the need to maintain multiple production tenants in Auth0.
## Email template customization
Auth0 makes extensive use of email to provide both user notifications and to drive the functionality needed for secure identity management (for example, email verification, account recovery, and brute force protections), and Auth0 provides a number of templates for these.
Before customizing email templates, please set up your [Email Provider](/docs/get-started/architecture-scenarios/business-to-consumer/operations#email-provider-setup).
Out of the box, the email templates used contain standard verbiage and Auth0 branding. However, you can configure almost every aspect of these templates to reflect the verbiage and user experience you want and make changes to things like the preferred language, accessibility options, and so forth.
Email templates are customized using [Liquid syntax](/docs/customize/email/email-templates/use-liquid-syntax-in-email-templates). If you are interested in customizing your templates based on user preferences, you will also have access to the [metadata](/docs/manage-users/user-accounts/metadata) located in users' profiles, as well as any specific application metadata too.
## Password reset page customization
The [Password Reset](/docs/customize/login-pages/classic-login/customize-password-reset-page) page is used whenever a user takes advantage of password change functionality and, as with the login page, you can customize it to reflect your organization's particular branding requirements.
## Error page customization
If there are issues encountered during user interactive workflow (e.g. user sign up or login), Auth0 provides error messages that indicate what the problem is under the hood. The default messages are somewhat cryptic, especially to the end user, since they will likely be missing context that only you can supply. As such, we recommend [customizing your error pages](/docs/customize/login-pages/custom-error-pages) to provide the missing context-specific information directly to your users. Furthermore, customizing your error pages allows you to display your branding, not Auth0's, as well as provide useful information to your users as to what should be done next. This information might include a link to a FAQ or how to get in touch with your company's support team or help desk.
Out-of-the-box there is no user interface for customizing Auth0 provided error pages, but you can use the [Tenant Settings endpoint of the Management API](https://auth0.com/docs/api/management/v2#!/Tenants/patch_settings) to configure them. Alternatively, if you can create and host your own error page, then you can have Auth0 direct users to that page instead of using the Auth0-hosted option.
## Guardian multi-factor page customization
The Multi-factor Authentication pages can be customized by adjusting the Universal Login branding options in the [Universal Login Settings](https://manage.auth0.com/#/login_settings) section.
If you need further customization, you can also customize [the full HTML content](/docs/secure/multi-factor-authentication/customize-mfa/customize-mfa-classic-login) to reflect your organization's particular UX requirements.
## Project planning guide
We provide planning guidance in PDF format that you can download and refer to for details about our recommended strategies.
[B2C IAM Project Planning Guide](https://assets.ctfassets.net/cdy7uua7fh8z/3er1aEQ7Ul0q3c9leJWczR/b1f18b4c16abb7e78b01e4eb2b52bb8e/B2C_Project_Planning.pdf)
# Business-to-Consumer Deployment Automation
Source: https://auth0.com/docs/get-started/architecture-scenarios/business-to-consumer/deployment
Automate Auth0 tenant deployment for a B2C IAM implementation using the Deploy CLI alongside source control and environment-specific configuration files.
In addition to adopting best practices for change management and [QA](/docs/get-started/architecture-scenarios/business-to-consumer/quality-assurance), successful customers will also integrate Auth0 collateral management as part of some automated deployment process. As discussed in the Architecture section under [SDLC support](/docs/get-started/architecture-scenarios/business-to-consumer/architecture#sdlc-support), you will want to ensure you configure separate Auth0 tenants for development, testing, and production environments, and you will want that configuration to be almost identical for the tenant in each environment. Using deployment automation helps ensure this, so that each environment tenant is configured the same, and you will be less likely to see bugs show up as a result of mismatched configurations between environments.
However you configure deployment automation, we’d recommend you unit test your rules, custom DB scripts, and hooks prior to deployment, and run some integration tests against your tenant post-deployment too. For more details regarding this, see the [Quality Assurance](/docs/get-started/architecture-scenarios/business-to-consumer/quality-assurance) guidance provided.
Auth0 provides support for a couple of different options when it comes to the deployment automation approaches you can use, and each can be used in conjunction with the other if desired:
* The [Auth0 Deploy CLI tooling](/docs/deploy-monitor/deploy-cli-tool) provides you with an easy-to-use script that can help you integrate with your existing Continuous Integration/Continuous Deployment (CI/CD) pipeline.
* If you can’t integrate directly with, or for some reason you don’t have a CI/CD pipeline, then the Auth0 [Source Control Extensions](/docs/customize/extensions) can provide an easy-to-set-up basic automation process with very low maintenance.
Both the Deploy CLI Tool and source control extensions can cause destructive changes; manual changes made directly in the dashboard between automated deployments could be lost! For this reason, if either is used, then **all** changes should be deployed from the source control subsystem referenced via the tooling and not made manually.
Each environment may also need some environment-specific configuration--Application Client ID’s and Client Secrets will be different between the Auth0 tenants, for example--so you’re going to want some way of being able to dynamically reference this rather than having hard-coded values. Auth0 provides support for handling environment-specific configuration information through one of the following two approaches:
* Use [Tenant Specific Variables](#tenant-specific-variables)
* Use keyword replacement if using the Auth0 Deploy CLI tool
## Tenant specific variables
Auth0 allows you to configure variables that are available from within custom [extensibility](/docs/customize/extensions); these can be thought of as environment variables for your Auth0 tenant. Rather than hard code references that change when moving code between development, test, and production environments, you can use a variable name that is configured in the tenant and referenced by the custom extensibility code. This makes it easier for the same custom code to function, without changes, in different tenants as the code can reference variables which will be populated with tenant-specific values at execution time:
* For use of variables in Actions, see [Write Your First Action](/docs/customize/actions/write-your-first-action) to learn how to configure secrets in the editor
* For use of variables in Rules, see how to [configure values](/docs/customize/rules/configuration)
* For use of variables in Hooks, see how to configure [secrets](/docs/customize/hooks/hook-secrets) in the editor
* For use of variables in Custom DB Scripts, see the [configuration parameters](/docs/authenticate/database-connections/custom-db/create-db-connection#step-3-add-configuration-parameters)
We recommend using variables to contain tenant-specific values as well as any sensitive secrets that should not be exposed in your custom code. If your custom code is deployed in GitHub/Gitlab/Bitbucket/VSTS, then using a tenant-specific variable avoids exposure of sensitive values via your repository.
## Project Planning Guide
We provide planning guidance in PDF format that you can download and refer to for details about our recommended strategies.
[B2C IAM Project Planning Guide](https://assets.ctfassets.net/cdy7uua7fh8z/3er1aEQ7Ul0q3c9leJWczR/b1f18b4c16abb7e78b01e4eb2b52bb8e/B2C_Project_Planning.pdf)
# Business-to-Consumer Launch Preparation
Source: https://auth0.com/docs/get-started/architecture-scenarios/business-to-consumer/launch
Plan the launch of a B2C IAM Auth0 implementation by sequencing testing and support readiness ahead of launch day across consumer-facing applications.
Use this guide as you prepare for the launch of your application. We’ve included reminders about some content you may have viewed earlier during your planning or development phases as well as some new content unique to the launch phase. The sections below are useful to developers and project owners to ensure that you have everything lined up for a smooth launch. There are several things to check so it may help to assign ownership of different sections to different members of your team.
We provide a [B2C IAM Project Planning Guide](https://assets.ctfassets.net/cdy7uua7fh8z/3er1aEQ7Ul0q3c9leJWczR/b1f18b4c16abb7e78b01e4eb2b52bb8e/B2C_Project_Planning.pdf) in PDF format that you can download and refer to for details about our recommended strategies.
# Business-to-Consumer Compliance Readiness
Source: https://auth0.com/docs/get-started/architecture-scenarios/business-to-consumer/launch/compliance-readiness
Compliance checks to perform before launch of your B2C IAM implementation.
There are several requirements related to privacy and compliance. Auth0 cannot provide legal guidance on your privacy or other regulatory obligations, but we can provide a curated list of privacy requirements below for which Auth0 offers features that may help you meet your obligations. Prior to launch, you should check that you’ve met all your privacy obligations and review the features outlined below to ensure you’re leveraging all the available Auth0 features to help you meet your privacy and compliance requirements.
## Publish privacy policy and obtain user consent
If you collect or process personal data about users, you should have published a privacy policy and have established procedures to ensure your operations abide by the contents of the policy. You also need to obtain a user’s consent for the collection and processing of information. Auth0 provides options for [displaying a link to your privacy policy storing user consent](/docs/secure/data-privacy-and-compliance/gdpr).
## Provide access to view, correct and erase data
Privacy legislation often requires that users have the right to view and correct any data held about them. If you are a data controller, you should provide a mechanism for this. Auth0 customers can build a self-service feature to access and correct data via the management API.
## Provide access to data portability
If you are a data controller, you may be obligated to provide users a means to export their data from your system in a transportable format. Auth0 provides user data portability mechanisms to help you satisfy this obligation via both manual export capabilities and the Management API which enables you to implement a self-service feature for users.
## Take steps to minimize personal data
You should have reviewed the personal data you collect about users to ensure it is legitimately required for the purposes of the processing covered in the privacy policy and consent. You should also confirm you have minimized the data you collect, and established a data retention policy. You can optionally elect to encrypt data you store in user metadata for additional protection.
## Data retention policy enforcement automated
You should have a published data retention policy and automate the enforcement of it. The Auth0 management API or the Auth0 dashboard can be used to facilitate [erasure of user accounts](/docs/secure/data-privacy-and-compliance/gdpr/gdpr-right-to-access-correct-and-erase-data).
## Protect personal data
Regardless of whether you are a data controller or a data processor, you have obligations to protect the personal data you hold about users. This includes use of encryption where possible, and implementing reasonable security measures to protect user accounts. Prior to launch, you should check if you are using all the security features available from Auth0 to help with this such as Brute Force Detection, Multi-Factor Authentication (for both users and administrators), and a strong password policy if using passwords. You should also ensure you have a process ready to respond to Brute Force attacks.
## Supplier evaluation
Another common compliance obligation is to perform due diligence review of the security of any third-party suppliers to which you expose personal data. For Auth0, you will find information to facilitate this task on the Auth0 [security and certifications](https://auth0.com/security/) page where you can view the security certifications Auth0 has obtained.
## Additional resources
Additional resources that may be useful for your compliance requirements include:
* [Auth0 Privacy Policy](https://auth0.com/privacy)
* [Security and Compliance](https://auth0.com/security/)
* [Auth0 Compliance and Certifications](/docs/secure/data-privacy-and-compliance)
* [Auth0 General Data Protection Regulation Compliance](/docs/secure/data-privacy-and-compliance/gdpr)
## Project Planning Guide
We provide planning guidance in PDF format that you can download and refer to for details about our recommended strategies.
[B2C IAM Project Planning Guide](https://assets.ctfassets.net/cdy7uua7fh8z/3er1aEQ7Ul0q3c9leJWczR/b1f18b4c16abb7e78b01e4eb2b52bb8e/B2C_Project_Planning.pdf)
# Business-to-Consumer Launch Day Preparation
Source: https://auth0.com/docs/get-started/architecture-scenarios/business-to-consumer/launch/launch-day
Review launch day considerations for a B2C IAM Auth0 implementation, like coordinating cutover and rollback paths across the consumer-facing applications going live.
## Notifications / announcements
It helps a launch go smoothly if all stakeholders are aware of the impending launch and understand the launch plan as well as their role and responsibilities. In addition to notifying teams that will be actively involved, it can help to notify teams that might be needed if anything goes wrong. Having someone on standby during a launch can help expedite response. Be sure to identify and notify any team that might need to answer questions from customers, including on social media.
### Parties to notify
* Customers
* Business parters, if applicable
* Application team(s) impacted by launch
* Support teams
* Network teams (network changes, on standby, in case of issues)
* Security teams (on standby, in case of issues)
* Marketing teams (ready for announcements, response to issues)
* Social media teams (ready to monitor social media, respond)
* Sales teams (prepared to answer questions from customers)
* Customer success teams (prepared to answer questions from customers)
## Notification plan
Your notification plan should include elements such as the target audience, the key takeaways for the audience, the message content, the plans for distributing the notification and how to test the messaging.
A list of elements to include in the plan are:
* Target audience (consider both internal & external audiences)
* Message
* Timing
* Dependencies
* Responsible parties (who will send it)
* Mechanism (how it will be communicated)
* Test message and delivery (if applicable - test to ensure notifications sent)
## Notification distribution
A common tactic is to release notifications in batches to spread out the initial onslaught of load and reduce the scope of confusion if there are any unforeseen glitches. It’s easier to correct issues with a small group than during a big-bang launch.
* One approach is to start with a relatively small batch of notifications, and if no issues are identified, increase the size of the batches over time.
* You can also send out batches on a rolling schedule around the globe to spread out load hitting the system at once and have notifications arrive at an optimal time within each timezone to increase the likelihood of the messages being read.
* You can do a soft-launch to a portion of users, such as individual customers, regions or some other grouping that makes sense for your application.
## Outage windows (if needed)
Some organizations require a formal request for an outage window if any outages or downtime is required for a launch. If your organization requires this, be sure to identify if any downtime is required for the cutover or launch (or other dependent systems) and file the necessary outage or change requests in advance of any lead-time requirements.
## Cutover plan (if needed)
Some launches involve cutover from a previous solution to a new solution. If your project fits this scenario, you should be sure to identify everything that needs to happen as well as any dependencies, the responsible party for each task, and necessary timing. You may wish to plan alternates for all important roles or in each region in case anyone is unexpectedly sick or otherwise unavailable. A checklist of items to consider for the cutover plan is:
* Have you documented the cutover plan and rollback plan if needed?
* Are backups needed of anything prior to change?
* Are any preparatory data changes required?
* Any DNS records to be changed?
* Any Firewall changes?
* Any new monitoring targets?
* Any software to be deployed?
## Go / no-go criteria
In your overall launch plan, it is helpful to have go/no-go criteria and to have discussed in advance the types of issues which could occur and which could be worked through vs would require reverting. A launch plan can specify periodic check-in timeframes with criteria of what to assess at each checkpoint and how long to allow an issue to continue unresolved.
For each stage of the launch, it helps to have success criteria defined, that indicate the launch is proceeding as planned and can continue. Some example criteria could be:
* User signups growing with minimal errors
* User logins at expected rate, minimal errors
* Reported support issues below a certain threshold
* No issues identified that could lead to corrupted data
It’s also helpful to have identified criteria which could trigger a “no-go” decision to halt the launch. The risk tolerance for each environment varies, but a few example criteria might include:
* High percent of user signup or login resulting in errors that cannot be resolved quickly
* High number of support issues that cannot be resolved quickly
* Condition identified that could lead to data corruption
* High severity security issue discovered
## Rollback
It is always wise to have a plan for how to rollback or revert a launch, just in case something unforeseeable occurs which cannot be resolved. Reviewing the launch plan for every step which involves a change can help identify the tasks or changes requires to revert a launch or cutover.
The rollback plan should include the steps to take, the sequence, how long each is likely to take and the responsible party. Understanding the cumulative time required to roll back can help to determine the timing of the final go/no-go decision to fit within any required outage window.
If any data is migrated or changed for the launch, the plan should include how to revert it, if needed. Reverting may require running scripts to undo operational changes or restoring a data store from a backup taken before the launch process began.
It is also necessary to plan for the case where some data is entered into a new system before it has to be reverted. Will such data / transactions need to be abandoned with the rollback or will you have a way to capture and apply them elsewhere so they aren’t lost?
If the resolution of issues or process to revert could potentially take longer than one shift, you’ll want to ensure you have a primary and perhaps a secondary person available and prepared to handle things during each work shift. If an issue results in the need for prolonged response, significantly beyond one shift, there are limits for how long people can realistically function without a break. It can help to be prepared with resources for a follow-the-sun issue response effort if needed.
## Standby contacts
As the launch day approaches, it’s a good idea to identify all contacts who might be needed for troubleshooting or resolving issues and request them to be on standby and ready to help if needed. The launch leader should have contact information for each person on the standby list to expedite communications.
If there is a physical or virtual "launch room", the people on standby should know where it is and be ready to join if needed. Having a central room or video conference prepared can expedite communications and troubleshooting across all parties if an issue occurs.
## Success Criteria
A lot of planning goes into a launch in order to be successful, but will you know how to evaluate the launch? If you define success criteria before the launch, you can determine what to monitor and if any additional monitoring or checks need to be in place to evaluate the launch. For example - if one element of the success criteria is the number of sign-ups or logins - do you have a way of monitoring that and has it been tested to ensure it is accurate?
You’ll want statistics to be able to trumpet the success of your launch. You don’t want to find out after the launch that you didn’t capture any data to quantify all the hard work your team put into the launch.
## Risks & mitigations plan
It’s no fun to think of things that could go wrong, but if anything happens, you’ll be glad you did as having a plan can expedite response. A few examples to plan for include:
* Software application bug
* Application incompatibility with user browser settings
* Network failure/outage
* DoS attack
* Hosting environment failure
* Load / capacity issues
* Data / corruption issues
* Security vulnerability discovered
If you had a beta period, it may help to review the results of the beta to identify additional possible failure scenarios.
## Project Planning Guide
We provide planning guidance in PDF format that you can download and refer to for details about our recommended strategies.
[B2C IAM Project Planning Guide](https://assets.ctfassets.net/cdy7uua7fh8z/3er1aEQ7Ul0q3c9leJWczR/b1f18b4c16abb7e78b01e4eb2b52bb8e/B2C_Project_Planning.pdf)
# Business-to-Consumer Operations Readiness
Source: https://auth0.com/docs/get-started/architecture-scenarios/business-to-consumer/launch/operations-readiness
Operations checks to perform before launch of your B2C IAM implementation.
## Status
You should ensure your operations staff knows how to monitor Auth0 service status and has set up a means to subscribe to updates on Auth0 status.
The Auth0 [status dashboard](https://status.auth0.com/) together with the Auth0 [uptime dashboard](http://uptime.auth0.com/) shows current and past status of the Auth0 service in a human-readable format. If any monitoring alerts are triggered, and as a first step in troubleshooting, your operations staff should check the status dashboard to see if there is a current outage. The public cloud status page also provides a facility for subscribing to outage notifications, and we also recommend that you check the status of any third-party [external services](/docs/deploy-monitor/monitor/check-external-services-status) you depend on, such as Social Providers. Having this information handy can help quickly eliminate possible causes when troubleshooting an issue and should be at the top of a troubleshooting checklist for developers as well as the help desk staff.
Information on how to check the status of Auth0 as well as any dependent services (such as Social Providers) should be at the top of a troubleshooting checklist for both developers and helpdesk staff, and we recommend you subscribe via the Auth0 status page to set up notification of any status updates.
In the event of an outage to the public cloud service, Auth0 performs a Root Cause Analysis (RCA) and publishes the results on the Auth0 status page. Auth0 performs a thorough investigation after an outage—including a determination of root cause, as well as contributing factors and how to prevent the issue from occurring again—and as a result, an RCA document can take a few weeks to be published.
## Email provider setup
You should double check that you have set up your own email provider to support production volumes of emails that might be sent to customers for signup, email validation, account recovery and the like.
Auth0 sends [emails](/docs/customize/email) to users for events such as signup welcome, email validation, breached password, and password reset events. You can customize the email templates for each type of event, and advanced customization of email handling is also possible. Auth0 provides a test email provider with limited capacity for basic testing, but you must set up your own email provider for production use, and customization of email templates will not work until you have established your own provider.
The default Auth0 email provider does not support sending production volumes of email or customization of email templates. You should therefore configure your own email provider before deploying to production.
## Infrastructure
### Firewalls
If custom code executing in Auth0 (such as in an Action, Rule, Hook, or Custom DB scripts) will call a service inside your network, or if you configure an on-premise SMTP provider in Auth0, then you may need to configure your firewall to allow [inbound traffic from Auth0](/docs/secure/security-guidance/data-security/allowlist). The IP addresses to allow through the firewall are specific to each region and are listed on the Rules, Hooks, custom database scripts, and email provider configuration screens in your Auth0 dashboard.
## NTP
If this is not handled automatically by your hosting environment, you should have scripts which will automatically restart NTP (Network Time Protocol) if it fails and alerts that will notify someone if NTP is not running. Authentication transactions rely on accurate system time because security tokens may be evaluated as expired when received if there are time discrepancies between sending and receiving systems.
## LoadBalancer timeouts checked
If you use the AD/LDAP connector, you should check the load balancer settings in your environment to see if they terminate long running connections that are inactive. If they do, you can modify the [Auth0 AD/LDAP Connection settings](/docs/authenticate/identity-providers/enterprise-identity-providers/active-directory-ldap/ad-ldap-connector/ad-ldap-connector-to-auth0) to use the `LDAP_HEARTBEAT_SECONDS` setting to send periodic heartbeat messages to keep the connection open.
## LoadBalancer configuration
If your application maintains server state such that it depends on sticky load balancing to route users to a particular server, it can be beneficial to double check that all load balancer configurations are correct. One load balancer in a pool that is out of sync can cause intermittent errors that are hard to troubleshoot. A quick check of load balancer configuration can avoid such issues in the first place.
## Logs
You should check that you have set up the ability to capture log data, that logs are covered by your data retention policy and you have mechanisms to enforce logs data retention limits. You should also make sure that your development, support, and security teams know how to access logs data for troubleshooting and forensics purposes. Exporting log files to services that provide comprehensive analytics can help you identify patterns such as usage trends and errors.
Auth0 provides extensive capability when it comes to the logging of events, and also in the scanning of logs in order to identify event anomalies (see [logs documentation](/docs/deploy-monitor/logs) for further details). Standard log retention period for Auth0 logs is determined by subscription level with the shortest period being two days and the longest period being only 30 days. Leveraging Auth0 support for integrating with external logging services will allow you to retain logs outside of this, and will also provide for log aggregation across your organization.
You should leverage one of the log streaming solutions to send log data to an external log analytics service. This will enable keeping data for longer periods of time and provide advanced analytics on the log data.
You should review the log data [retention period](/docs/deploy-monitor/logs/log-data-retention) for your subscription level, and implement a log data export service to send log data to an external log analytics service. You can use one of our [log streaming solutions](https://marketplace.auth0.com/features/log-streaming) in Auth0 Marketplace.
Development teams can use log files for troubleshooting and detecting intermittent errors that may be hard to find via QA tests. Security teams will probably want log data in case forensic data is ever needed. Exporting log files to services that provide comprehensive analytics can help you see patterns such as usage trends and attack protection triggers.
### Rate limits and other errors
Auth0 provides a unique error code for errors reported when the [rate limit is exceeded](/docs/troubleshoot/customer-support/operational-policies/rate-limit-policy). You should set up automatic scanning of logs to check for rate limit errors so you can proactively address activity that hits rate limits before it causes too much trouble for your users. Auth0 also publishes error codes for other types of errors, and you will find it helpful to scan logs for [authentication errors](/docs/libraries/common-auth0-library-authentication-errors) as well as errors from Auth0 Management API calls (Management API error codes are shown below each call in the [Management API Explorer](https://auth0.com/docs/api/management/v2)).
Calling the Management API to retrieve user profile information from within a Rule is a common cause of rate limit errors because such API calls can execute for every login as well as periodic session checks.
## Monitoring
Be sure to set up proactive monitoring of the Auth0 service as well as end-to-end authentication through your application.
You should establish mechanisms for [monitoring Auth0 implementations](/docs/deploy-monitor/monitor), so your support or operations team receives the timely information needed to proactively handle service outages. Auth0 provides monitoring endpoints that can be incorporated into your monitoring infrastructure. These endpoints are designed to provide a response suitable for consumption by monitoring services. It should be noted that they only provide data on Auth0. For complete end-to-end monitoring, which is essential for checking the ability of users to log in, we recommend that you set up synthetic transaction monitoring. This will provide greater granularity for your monitoring and enable you to detect outages unrelated to Auth0 as well as degradation of performance, so you can respond more proactively.
You should set up the ability to send synthetic login transactions to facilitate end-to-end monitoring of authentication. You can do this with a simple application that uses the [Resource Owner Password Grant](/docs/get-started/authentication-and-authorization-flow/resource-owner-password-flow/call-your-api-using-resource-owner-password-flow) in combination with a test user that has no privileges, and don’t forget about [Auth0 rate limiting policies](/docs/troubleshoot/customer-support/operational-policies/rate-limit-policy) too.
## Auth0 Notifications
You should ensure your team is monitoring all of the following communication channels from Auth0 to stay abreast of important announcements and changes.
There are several different types of notifications from Auth0 that you should watch for as they contain important information that could impact your tenant(s) and project.
Proactive security notifications and other operational announcements are sent by Auth0 to dashboard administrators. You should ensure that the people who need to receive such messages are dashboard administrators.
### Dashboard notifications
From time to time, Auth0 may send an important announcement related to your tenant. These announcements about your service will be sent to your Auth0 dashboard and depending on the severity of the announcement, via email to the registered Auth0 dashboard administrators. You should make a regular practice of logging in to the dashboard and checking the bell icon at the top for any important notices. In addition, you should review emails from Auth0 in a timely fashion as they may convey important information about changes or actions you need to take.
### Change log
Auth0 provides information on changes to the service in the Auth0 [change log](https://auth0.com/changelog). You should make a regular practice of reviewing Auth0 change logs to be aware of changes. Support teams researching an issue may find it useful to review the change log to determine if recent changes might be related, especially if these are breaking changes. Development teams will also want to review the change logs to identify new features that may be beneficial.
In addition, you should periodically check the [Auth0 migrations page](/docs/troubleshoot/product-lifecycle/deprecations-and-migrations) for news about upcoming deprecations that might require your team to make changes.
## Automated Deployment, version control
While not required, it is highly recommended that you have deployment automation set up. You can respond more efficiently if you need to make any changes after launch if you have automated the ability to deploy and revert changes to dev, test and production environments.
In addition to adopting best practices for change management and [QA](/docs/get-started/architecture-scenarios/business-to-consumer/quality-assurance), successful customers will also integrate Auth0 collateral management as part of some automated deployment process. As discussed in the Architecture section under [SDLC support](/docs/get-started/architecture-scenarios/business-to-consumer/architecture#sdlc-support), you will want to ensure you configure separate Auth0 tenants for development, testing, and production environments, and you will want that configuration to be almost identical for the tenant in each environment. Using deployment automation helps ensure this, so that each environment tenant is configured the same, and you will be less likely to see bugs show up as a result of mismatched configurations between environments.
However you configure deployment automation, we’d recommend you unit test your rules, custom DB scripts, and hooks prior to deployment, and run some integration tests against your tenant post-deployment too. For more details regarding this, see the [Quality Assurance](/docs/get-started/architecture-scenarios/business-to-consumer/quality-assurance) guidance provided.
Auth0 provides support for a couple of different options when it comes to the deployment automation approaches you can use, and each can be used in conjunction with the other if desired:
* The [Auth0 Deploy CLI tooling](/docs/deploy-monitor/deploy-cli-tool) provides you with an easy-to-use script that can help you integrate with your existing Continuous Integration/Continuous Deployment (CI/CD) pipeline.
* If you can’t integrate directly with, or for some reason you don’t have a CI/CD pipeline, then the Auth0 [Source Control Extensions](/docs/customize/extensions) can provide an easy-to-set-up basic automation process with very low maintenance.
Both the Deploy CLI Tool and source control extensions can cause destructive changes; manual changes made directly in the dashboard between automated deployments could be lost! For this reason, if either is used, then **all** changes should be deployed from the source control subsystem referenced via the tooling and not made manually.
Each environment may also need some environment-specific configuration—Application Client ID’s and Client Secrets will be different between the Auth0 tenants, for example—so you’re going to want some way of being able to dynamically reference this rather than having hard-coded values. Auth0 provides support for handling environment-specific configuration information through one of the following two approaches:
* Use [Tenant Specific Variables](#tenant-specific-variables)
* Use [keyword replacement](/docs/deploy-monitor/deploy-cli-tool/configure-the-deploy-cli) if using the Auth0 Deploy CLI tool
## Tenant specific variables
Auth0 allows you to configure variables that are available from within custom [extensibility](/docs/customize/extensions); these can be thought of as environment variables for your Auth0 tenant. Rather than hard code references that change when moving code between development, test, and production environments, you can use a variable name that is configured in the tenant and referenced by the custom extensibility code. This makes it easier for the same custom code to function, without changes, in different tenants as the code can reference variables which will be populated with tenant-specific values at execution time:
* For use of variables in Actions, see [Write Your First Action](/docs/customize/actions/write-your-first-action) to learn how to configure secrets in the editor
* For use of variables in Rules, see how to [configure values](/docs/customize/rules/configuration)
* For use of variables in Hooks, see how to configure [secrets](/docs/customize/hooks/hook-secrets) in the editor
* For use of variables in Custom DB Scripts, see the [configuration parameters](/docs/authenticate/database-connections/custom-db/create-db-connection#step-3-add-configuration-parameters)
We recommend using variables to contain tenant-specific values as well as any sensitive secrets that should not be exposed in your custom code. If your custom code is deployed in GitHub/Gitlab/Bitbucket/VSTS, then using a tenant-specific variable avoids exposure of sensitive values via your repository.
## Backup / Restore
You should have a plan and mechanism in place to support any backup/restore capability needed for your project. This can be done using the Auth0 Management API for data as well as the Automated Deployment capabilities described in the automated deployment section for Auth0 configuration.
As noted in the Auth0 [Data Tenant Restore policy](/docs/troubleshoot/customer-support/operational-policies) and [Data Transfer policy](/docs/troubleshoot/customer-support/operational-policies/data-export-and-transfer-policy), Auth0 does not restore deleted tenants or move data between tenants. Auth0 provides the Auth0 Management API to provide customers a completely flexible capability to backup, restore and move data as needed. Customers can write scripts to retrieve data from Auth0 for backup purposes, and similarly write scripts for use with the Automated Deployment capability to restore any aspect of their Auth0 configuration.
## Versions Up to Date
You should double check that all technologies in your application stack, as well as browser versions used by your users are on current, up-to-date versions as this will impact Auth0’s ability to provide support if issues arise.
* Check you are using the latest supported version of node.js in [Auth0 dashboard settings](/docs/get-started/tenant-settings).
* Check you are using a version of SDK/Libraries supported by Auth0 per the [Auth0 Support Matrix](/docs/troubleshoot/customer-support/product-support-matrix).
## Certificate rollover plan
Certificates may be used in identity deployments. To ensure a certificate expiration does not catch you by surprise, you should have a list of certificates in your environment along with the expiration dates, how you will be notified when expiration draws near and how the certificate rollover process works.
### SAML connections
For SAML connections, you obtain a certificate from the IdP and upload it to a SAML connection for the IdP in your Auth0 dashboard. When one of these certificates is about to expire, Auth0 will send email to dashboard administrators warning of the upcoming expiration. You can obtain the new certificate and upload it using the connection configuration screen.
### WS-Fed connections
For WS-Fed connections, if you configure them by specifying an ADFS URL, any changes will be picked up by a daily update. You can trigger an update manually by visiting the connection configuration page in the Auth0 dashboard and doing a Save. If a certificate is changed at the remote IdP, Auth0 can be updated by those mechanisms or by uploading a new metadata file in the same connection configuration screen.
## Disaster Recovery / Business Continuity Plan in place
While not an absolute requirement prior to launch, it is useful to have a disaster recovery plan in place to ensure business continuity in the face of different types of disasters, including system outages and natural disasters hitting a region where critical staff is located.
## Processes documented
Another item which is not an absolute requirement, but also recommended is to ensure all processes related to Auth0 are documented. This can include the following:
* Change management for configuration
* Deployment of new changes and any automatic deployment mechanisms used, how to revert to previous version if issues found
* Certificate rollover processes, if any
* Adding or removing new Identity Providers, if applicable
* Changes to user profile structure in Auth0 or in directories Auth0 pulls from
* Adding or removing applications or APIs
* Capturing and exporting logs
* Backup/restore process you have implemented
* User management (forgotten password, lost phone)
* Root cause analysis after an incident
## Project Planning Guide
We provide planning guidance in PDF format that you can download and refer to for details about our recommended strategies.
[B2C IAM Project Planning Guide](https://assets.ctfassets.net/cdy7uua7fh8z/3er1aEQ7Ul0q3c9leJWczR/b1f18b4c16abb7e78b01e4eb2b52bb8e/B2C_Project_Planning.pdf)
# Business-to-Consumer Support Readiness
Source: https://auth0.com/docs/get-started/architecture-scenarios/business-to-consumer/launch/support-readiness
Get support ready for a B2C IAM Auth0 launch by training agents and preparing the escalation paths and diagnostic playbooks end-user issues will need.
## Review Auth0 Policies
When starting to prepare for your launch, be sure to read through [Auth0 Policies](/docs/troubleshoot/customer-support/operational-policies) and prepare your production operations accordingly for any required lead times or responsibilities on your part, according to the policies.
## Review your Support plan, SLAs, Severity definitions and Support center documentation
You should review the specifics of the [support plan](/docs/troubleshoot/customer-support) you’ve purchased and the Service Level Agreements associated with it, to ensure it is adequate for your needs. If you haven’t already done so, explore the [support center](https://support.auth0.com/) and familiarize yourself with support features such as viewing suggested solutions to common issues and [filing tickets](/docs/troubleshoot/customer-support/open-and-manage-support-tickets) and viewing your quota usage. It will be helpful to review the severity level definitions for support tickets so that you file tickets with the correct severity. One important note is that it is not possible today in the Support Center to increase the severity of a support ticket. If you file a ticket for a medium-grade issue which later becomes a high severity issue, you should file a new urgent, high severity ticket that explains anything new that triggers the urgency and references the original ticket for details.
You should also ensure your development and support teams are familiar with the [Auth0 community forum](https://community.auth0.com/), discussed further below. Customers can often find answers there right away to common issues, avoiding the need to file a ticket, so it should be your first stop for technical questions.
## Review the Auth0 community forum
The [Auth0 community forum](https://community.auth0.com/) contains a wealth of information. If you have a question, chances are someone else has already asked the question on the forum. Answers are contributed by both Auth0 staff and the larger community of Auth0 users.
Important notices are posted to the community forum to help you stay abreast of important news. Be sure to check out the “Community” and “FAQ” categories. The Community category contains pro-active posts on product announcements, roadmap information, How-To videos as well as important information about any upcoming feature deprecations.
It’s a good idea to check out the Auth0 Community on a regular basis, not just when you have questions. While you are there, if you see a question you’ve already solved, please contribute your wisdom to help others!
## Gather Auth0 troubleshooting information needed for support tickets
We recommend your support team become familiar with our [troubleshooting guides](https://support.auth0.com/center/s/knowledge) specific to identity protocols and Auth0. This includes the questions to research and information to collect before posting a question on the Auth0 forum or filing a support ticket. Authentication transactions often span multiple systems so there are some specialized troubleshooting techniques that are helpful to learn.
## Have troubleshooting tools ready
Your team will doubtless have already done some troubleshooting during the development of your application, but we recommend making sure your support team is also familiar with any tools below relevant to your project. If you need to file a ticket, the Auth0 support team may ask for a HAR (HTTP Archive) file to help analyze the issue so it’s helpful for your support staff to be familiar with how to do this.
Before sharing a HAR file with anyone (including Auth0), ensure that you remove or obfuscate all sensitive data, such as:
* Confidential user information
* Personal identifiable information (PII)
* Confidential application information
To learn more, read the following articles on [Auth0 Community](https://community.auth0.com):
* [Sanitizing HTTP Traces](https://community.auth0.com/t/sanitizing-http-traces/119488)
* [How to Sanitize an HTTP Trace File Automatically](https://community.auth0.com/t/how-to-sanitize-a-http-trace-file-automatically/120583)
* [How to Manually Redact Sensitive Information](https://community.auth0.com/t/how-to-manually-redact-sensitive-information/122554)
* [HAR File is Too Large to Upload to the Support Case](https://community.auth0.com/t/har-file-is-too-large-to-upload-to-the-support-case/122488)
### Capture HAR file
A [HAR file](https://support.auth0.com/center/s/article/generate-and-analyze-har-files-to-troubleshoot-auth0-issues) captures a sequence of browser interactions and is a commonly used tool when debugging authentication issues. The process of authenticating a user often involves redirecting the user’s browser from an application to Auth0, and possibly to another remote Identity Provider, depending on the type of connection used. You can capture the redirection and the responses and analyze it to find clues about the cause of an issue.
### Analyze HAR file
Analyze the HAR file to obtain valuable troubleshooting information. It shows the sequence of browser redirects involved in an authentication transaction, along with the parameters used. The HAR file also shows if the authentication process stopped mid-stream and if so where, which helps to pinpoint the location of the issue. The HAR file contains tokens returned to the application front-end, and these can be pasted into appropriate viewers to see if they contain the expected contents.
### View JWT
The [jwt.io](https://jwt.io/) tool was written by Auth0 and allows you to view the contents of a JWT-formatted token. Applications that delegate authentication to Auth0 via OIDC will receive an ID Token from Auth0. Depending on your type of application, the ID Token may be captured in a HAR file. The ID Token is in JWT format and can be pasted into jwt.io to view the contents of the ID Token.
### View SAML request/response
There are many SAML decoders available. The [samltool.io](https://samltool.io/) decoder was written by Auth0 and allows you to view the contents of a SAML Request or Response. Applications that delegate authentication to Auth0 via SAML or use a SAML type of connection in Auth0 will use SAML Requests and Responses. These SAML Requests and Responses may be captured in a HAR file. The requests and responses can be pasted into samltool.io or other SAML decoders to view the contents of the SAML Request or Response.
## Review Auth0 support matrix
One potential cause of issues is using out of date versions of SDKs or libraries. We strongly recommend your team check your software stack, browsers, SDKs and libraries against the [Auth0 support matrix](/docs/troubleshoot/customer-support/product-support-matrix) to ensure you are running on up-to-date, supported versions. In the event of an issue, the Auth0 support team may ask you to upgrade to a supported version. To avoid slowing down progress on issue resolution, be sure you are on up-to-date versions.
## Use Auth0 feedback portal
Auth0 welcomes feedback and ideas from Auth0 customers. If you have a suggestion for our product team, you can submit product feedback directly on the [Product Feedback portal](https://auth0.com/feedback).
## Actions Real-time Logs
For debugging and supporting custom code in Auth0, including Actions, Rules, Hooks, custom database scripts, and custom OAuth connections, knowledge of [Actions Real-time Logs](/docs/customize/actions/actions-real-time-logs) is essential. This enables you to view output from your custom code, including output from `console.log` statements.
We recommend using Actions Real-time Logs and getting familiar with using it to view log output from your custom code as a debugging and support tool.
## Project Planning Guide
We provide planning guidance in PDF format that you can download and refer to for details about our recommended strategies.
[B2C IAM Project Planning Guide](https://assets.ctfassets.net/cdy7uua7fh8z/3er1aEQ7Ul0q3c9leJWczR/b1f18b4c16abb7e78b01e4eb2b52bb8e/B2C_Project_Planning.pdf)
# Business-to-Consumer Tenant Check
Source: https://auth0.com/docs/get-started/architecture-scenarios/business-to-consumer/launch/tenant-check
Tenant Checks to perform before launch of your B2C IAM implementation.
This section covers a list of configurations to check in your tenant. This should be done periodically during development and sufficiently before launch so you have time to fix anything amiss.
## General tenant check
### Tenant preparation check
Check to ensure you have set up tenant environments to support your SDLC lifecycle and that Dev, Test and Prod tenants are cleanly separated so that ongoing development work after launch doesn’t negatively impact your production environment.
Every company has some form of Software Development Life Cycle (SDLC), and throughout the development process you will want to align with that strategy. For instance, you need to be able to test your integration with Auth0 in a similar fashion as you test the applications themselves. It is therefore important to [structure Auth0 tenants to support your SDLC](/docs/get-started/auth0-overview/create-tenants/set-up-multiple-environments), and there is a consistent pattern which our customers typically follow when it comes to the best practices associated with tenant layout for doing so:
| Environment | Sample Tenant Name | Description |
| - | - | - |
| Development | **company-dev** | A shared environment where most of your development work occurs |
| QA/Testing | **company-qa** or **company-uat** | An environment for formal testing of the changes you've made |
| Production | **company-prod** | The production tenant |
In some cases you may also want to create one or more sandboxes (e.g., **company-sandbox1**, **company-sandbox2**) so that you can test changes without compromising your development environment. This might be where you test deployment scripts and the like.
You can also take advantage of our [Implementation Checklists](/docs/get-started/architecture-scenarios/checklists) that you can download and customize to meet your implementation project needs.
### Tenant association check
To ensure that your [tenants are all associated with your Auth0 contractual agreement](/docs/get-started/auth0-overview/create-tenants/child-tenants) and have the same features, ensure all your tenants are associated with your company account. If you have individual developers that want to create their own sandboxes for testing, make sure they get associated with your account so they have the same permissions too. To do this you should contact your Auth0 representative or the [Auth0 Support Center](https://support.auth0.com/center/s/).
### Specify production tenant
To ensure Auth0 recognizes your production tenant, be sure to [set your production tenant](/docs/get-started/auth0-overview/create-tenants/set-up-multiple-environments#set-the-environment) with the “production” flag in the Support Center.
### Tenant production check
Auth0 provides a [Production Check](/docs/deploy-monitor/pre-deployment-checks) facility to detect many common errors. You should ensure this has been run and any findings from the report mitigated before launch.
In addition, you should check the [best practice configurations advice](/docs/deploy-monitor/pre-deployment-checks/production-checks-best-practices), for which checking cannot be automated.
### Tenant settings check
#### Tenant settings
Make sure to follow the Auth0 [tenant settings](/docs/get-started/tenant-settings) recommendations in configuring your branding as well as your support email and support URL so users know how to get help if an issue occurs. You'll want to check your SSO Session Timeout settings and the list of dashboard admins with access to your production tenant as well.
#### Error page customization
If there are issues encountered during user interactive workflow (e.g. user sign up or login), Auth0 provides error messages that indicate what the problem is under the hood. The default messages are somewhat cryptic, especially to the end user, since they will likely be missing context that only you can supply. As such, we recommend [customizing your error pages](/docs/customize/login-pages/custom-error-pages) to provide the missing context-specific information directly to your users. Furthermore, customizing your error pages allows you to display your branding, not Auth0's, as well as provide useful information to your users as to what should be done next. This information might include a link to a FAQ or how to get in touch with your company's support team or help desk.
Out-of-the-box there is no user interface for customizing Auth0 provided error pages, but you can use the [Tenant Settings endpoint of the Management API](https://auth0.com/docs/api/management/v2#!/Tenants/patch_settings) to configure them. Alternatively, if you can create and host your own error page, then you can have Auth0 direct users to that page instead of using the Auth0-hosted option.
#### Legacy feature flags off
If you have an older tenant, you may have various legacy feature flags enabled in your [tenant settings advanced tab](/docs/get-started/tenant-settings). If you have any toggles on in the “Migrations” section of this tab, you should review your usage and make plans to migrate off the legacy feature.
#### Delegated admin extension
While you are checking the list of users with access to your production tenant, don't forget to check any users specified in the [Delegated Admin Extension](/docs/customize/extensions/delegated-administration-extension).
### Custom Domain Naming set up
By default, the URL associated with your tenant will include its name and possibly a region-specific identifier. For example, tenants based in the US have the a URL similar to `https://example.auth0.com` while those based in Europe have something that is of the fashion `https://example.eu.auth0.com`. A [Custom Domain](/docs/customize/custom-domains) offers a way of providing your users with a consistent experience by using a name that’s consistent with your organization's brand.
Only one custom Domain Name can be applied per Auth0 Tenant, so if you absolutely must have independent domain name branding then you will require an [architecture](/docs/get-started/architecture-scenarios/business-to-consumer/architecture) where multiple Auth0 Tenants are deployed to production.
In addition, Custom Domain functionality offers you complete control over the certificate management process. By default, Auth0 provides standard SSL certificates, but if you configure a custom domain, you can use Extended Validation (EV) SSL certificates or similar to provide the visual, browser-based cues that offer your visitors additional peace of mind.
In general, we see customers having the most success when they use a centralized domain for authentication - this is especially the case if the company offers multiple products or service brands. By using a centralized domain, you can provide end users with a consistent user experience while also minimizing the need to maintain multiple production tenants in Auth0.
## Application and Connection settings check
Each of your connection settings should be reviewed against the [connection configuration best practices](/docs/authenticate/connection-settings-best-practices).
In addition, you should review that all connections are appropriate and that no experimental connections are left in your production tenant as they could enable unauthorized access.
If you use SAML connections, it is a best practice to configure the connections to sign SAML requests.
## Page customization check
If you use the Auth0 universal login page, password reset page, or Guardian multi-factor authentication, you should check that you have adequately customized the pages displayed to the end user.
### Universal Login Page
[Universal Login](/docs/authenticate/login/auth0-universal-login) is the recommended method for authenticating users, and it centers around use of the Login page. You can customize the Login page to support your organization's branding requirements.
If you choose to customize the Universal Login page script, we strongly recommend that you make use of version control. To do this, you should deploy the script to your Auth0 tenant via [deployment automation](/docs/get-started/architecture-scenarios/business-to-consumer/deployment) or via one of the [alternative strategies](/docs/customize/login-pages/classic-login/version-control).
### Password reset page
The [Password Reset](/docs/customize/login-pages/classic-login/customize-password-reset-page) page is used whenever a user takes advantage of password change functionality and, as with the login page, you can customize it to reflect your organization's particular branding requirements.
### Guardian
The Multi-factor Authentication pages can be customized by adjusting the Universal Login branding options in the [Universal Login Settings](https://manage.auth0.com/#/login_settings) section.
If you need further customization, you can also customize [the full HTML content](/docs/secure/multi-factor-authentication/customize-mfa/customize-mfa-classic-login) to reflect your organization's particular UX requirements.
## Authorization check
If you are using Auth0’s authorization feature, be sure to double check all privileges granted to ensure authorizations are appropriate for your production environment.
## API configuration check
### Access token expiration
You should double check the [API access token expiration settings](/docs/get-started/apis/api-settings) to ensure they are appropriate for each API in your production environment.
### API offline access
If your application does not request refresh tokens, this should be off.
### Access token signing algorithm
It is recommended that the [API access token signing algorithm](/docs/get-started/applications/signing-algorithms) be set to RS256 rather than HS256 to minimize exposure of the signing key.
### API Access token validation
If you have any custom APIs, be sure to check that they are adequately [validating the access tokens](/docs/secure/tokens/access-tokens/validate-access-tokens) they receive before using the information in them.
## API Scopes
If you have applications making machine-to-machine calls to any of your APIs, you should review the scopes specified for the API to ensure they are all appropriate for your production environment. For further information see the documentation on [client credentials grant](/docs/get-started/applications/update-grant-types).
## Email templates customized
Auth0 makes extensive use of email to provide both user notifications and to drive the functionality needed for secure identity management (for example, email verification, account recovery, and brute force protections), and Auth0 provides a number of templates for these.
Before customizing email templates, please set up your [Email Provider](/docs/get-started/architecture-scenarios/business-to-consumer/operations#email-provider-setup).
Out of the box, the email templates used contain standard verbiage and Auth0 branding. However, you can configure almost every aspect of these templates to reflect the verbiage and user experience you want and make changes to things like the preferred language, accessibility options, and so forth.
Email templates are customized using [Liquid syntax](/docs/customize/email/email-templates/use-liquid-syntax-in-email-templates). If you are interested in customizing your templates based on user preferences, you will also have access to the [metadata](/docs/manage-users/user-accounts/metadata) located in users' profiles, as well as any specific application metadata too.
## Attack protection configured
The reason that authentication systems are important is to prevent bad actors from accessing applications and user data that they should not. We want to place as many barriers as possible between those bad actors and access to our systems. One of the easiest ways to do this is to ensure that your [attack protection](/docs/secure/attack-protection) with Auth0 is configured correctly, so take a moment to read the guidance on this subject and ensure that it's working correctly for you.
Anomaly detection is handled behind the scenes by Auth0 and provides a great security feature for your product. If you're going to utilize it, ensure that you have set up your [Email Provider](/docs/get-started/architecture-scenarios/business-to-consumer/operations#email-provider-setup) and configured your [Email Templates](/docs/get-started/architecture-scenarios/business-to-consumer/branding#email-template-customization) before turning on email delivery to your users.
## Project Planning Guide
We provide planning guidance in PDF format that you can download and refer to for details about our recommended strategies.
[B2C IAM Project Planning Guide](https://assets.ctfassets.net/cdy7uua7fh8z/3er1aEQ7Ul0q3c9leJWczR/b1f18b4c16abb7e78b01e4eb2b52bb8e/B2C_Project_Planning.pdf)
# Business-to-Consumer Testing Complete
Source: https://auth0.com/docs/get-started/architecture-scenarios/business-to-consumer/launch/testing
Plan testing for a B2C IAM Auth0 launch by covering Universal Login flows, social connections, and the consumer-specific signup configuration each app uses.
Prior to launch, you should have completed all the testing that applies to your environment.
Quality Assurance is important in identifying issues before they impact your customers and, depending on the nature of your project, there are several different types of quality assurance testing that you’re going to want to consider as part of your integration with Auth0:
* Is your application easy to understand and use, even by those with a disability?
* Does your application need to work across various different browsers and devices?
* Does your application need to work in multinational and/or international environments?
* How will your application perform when subjected to unexpected production loads?
* How can you ensure your application is safe from security-related vulnerabilities?
Auth0 [Universal Login](/docs/authenticate/login/auth0-universal-login) and associated UI widgets (such as [Lock](/docs/libraries/lock)) have already been designed and built following usability and accessibility best practices, and provide tested out-of-box support for a whole host of [browsers and devices](/docs/troubleshoot/customer-support/product-support-matrix). Support for [internationalization](/docs/customize/internationalization-and-localization) (I18N) is also provided out-of-box, with built-in extensibility designed for custom multi-language and localization (L10N) situations.
To ensure functional requirements are met and unexpected events are handled correctly, guidance is provided for testing the [integration](#integration-testing) between your application(s) and Auth0, and for [unit testing](#unit-testing) individual extensibility modules (such as [Rules](/docs/customize/rules/debug-rules), [Hooks](/docs/customize/hooks/update-hooks), and Custom Database scripts). Guidance is also provided regarding Auth0's [penetration testing policy](/docs/troubleshoot/customer-support/operational-policies/penetration-testing-policy) to help when testing for security vulnerability, and also how [Mock](#mock-testing) testing can be leveraged in conjunction with our [load testing policy](/docs/troubleshoot/customer-support/operational-policies/load-testing-policy) to help ensure your application(s) perform under unexpected load.
## Unit testing
The objective of unit testing is to test individual units of code. If you create custom code within Auth0 in the form of Rules, Hooks, and/or Custom DB scripts, you should consider use a testing framework (such as [Mocha](https://mochajs.org/)) to test your code. Companies who have been most successful with Auth0 have found it useful to execute these unit tests prior to [automatically deploying](/docs/get-started/architecture-scenarios/business-to-consumer/deployment) Auth0 tenant configuration and collateral.
## Integration testing
It is a recommended best practice that you set up different tenants for development, testing, and production as discussed in Architecture guidance for [SDLC support](/docs/get-started/architecture-scenarios/business-to-consumer/architecture#sdlc-support). Auth0 allows you to configure variables that are available from within custom [extensibility](/docs/customize/extensions); these can be thought of as environment variables for your Auth0 tenant. Rather than hard code references that change when moving code between development, test, and production environments, you can use a variable name that is configured in the tenant and referenced by the custom extensibility code. This makes it easier for the same custom code to function, without changes, in different tenants as the code can reference variables which will be populated with tenant-specific values at execution time:
* For use of variables in Rules, see how to [configure values](/docs/customize/rules/configuration)
* For use of variables in Hooks, see how to configure [secrets](/docs/customize/hooks/hook-secrets) in the editor
* For use of variables in Actions, see Explore Flows and Triggers
* For use of variables in Custom DB Scripts, see the [configuration parameters](/docs/authenticate/database-connections/custom-db/create-db-connection#step-3-add-configuration-parameters)
It’s a recommended best practice to use variables to contain tenant-specific values as well as any sensitive secrets that should not be exposed in your custom code. If your custom code is deployed in GitHub, then using a tenant-specific variable avoids exposure of sensitive values via your GitHub repository.
### Test automation
You can automate your overall build process by incorporating deployment automation as well as test automation. This can be used to deploy new versions of configuration and/or custom code to Auth0 and execute automated tests. If the tests uncover any failures, the deployment automation capabilities can be used to revert to the last working version. For further information, see the [deployment automation guidance](/docs/get-started/architecture-scenarios/business-to-consumer/deployment) provided.
## Mock testing
In a balance between Auth0’s [load testing policy](/docs/troubleshoot/customer-support/operational-policies/load-testing-policy) and the desire to load test, it is common practice among Auth0’s customers to mock out Auth0’s endpoints. This is a valuable practice in order to ensure that your application works with your expected interfaces without having to restrict your testing, and tools such as [MockServer](http://www.mock-server.com/), [JSON Server](https://github.com/typicode/json-server) or even [Postman](https://learning.getpostman.com/docs/postman/mock_servers/setting_up_mock/) can be used to assist.
## Pen testing (optional)
If you will be conducting penetration tests, you should be aware of Auth0’s [penetration testing policy](/docs/troubleshoot/customer-support/operational-policies/penetration-testing-policy) and abide by it. Penetration tests require advance notice to Auth0 so that your tests are not mistaken for malicious activity and shut down.
## Load testing (optional)
If you will be conducting load tests, you should be aware of Auth0’s [load testing policy](/docs/troubleshoot/customer-support/operational-policies/load-testing-policy) and abide by it. Load tests require advance notice to Auth0. In planning your load testing, you will also need to be aware of Auth0’s [API rate limits](/docs/troubleshoot/customer-support/operational-policies/rate-limit-policy).
Load tests require prior approval from Auth0, as explained in the Auth0 load test policy. Be sure to note the lead time for a request to be reviewed and allow enough time for review as well as conducting the tests. If your load test request has been approved, the following guidance can help avoid errors and faulty test results.
* Run an HTTP trace on a test execution of your application to identify all the calls your application or intended test needs to make, and make sure your test includes them so it is representative of what will happen in production.
* Design your test to be mindful of Auth0 API rate limits.
* Use of any custom code in Auth0 (Actions, Rules, Hooks, custom database scripts, custom OAuth connections) will invoke the Auth0 custom code sandbox and this may cost more in terms of performance. Turn off Rules unless they are essential to the test. If they are off you will have higher throughput than if they are on.
* Estimate the expected overall load for your production environment and percent of calls to each endpoint and structure your performance test accordingly so it gives you a realistic test result. Different endpoints have different performance costs. Failure to design a representative test will result in misleading results.
* Don’t make calls that depend on the results of earlier calls without checking that pre-requisite calls or responses have completed. Simply building in a delay may not be adequate.
* Be sure to implement adequate error handling. A frequent cause of issues during tests is errors in custom code (Actions, Rules, Hooks, custom database scripts, custom OAuth connection scripts) caused by unhandled exceptions in the custom code.
* Load tests should be written to start at a low level and increase the load gradually, capturing data at each level, to get the most useful results. Starting at a high level and immediately failing gives less information about what the system can sustain.
* It is normal to need to run a performance test multiple times, possibly adjusting the code under test or the test harness/configuration. Be sure to start your testing early to allow enough time for more than one iteration.
* Use your own mail provider account and make sure to arrange ahead of time for enough mail-sending quota or you may be rate-limited by the mail provider. Turn off mail sending if you do not use it.
* Be sure to use your own account credentials for all social connections rather than Auth0 dev keys. In the Auth0 dashboard, go to Connections -> Social -> \{name of connection}—to see instructions for how to add your own social provider account credentials into the connection. Note: some social providers do not allow load testing. Check your provider(s) for their policy
* In order to avoid rate limiting, and more accurately simulate real load, your tests will need to send requests for different users, not all requests for the same user. If you use only one or a few users, caching may reduce the effective load and not provide realistic results.
* Be sure to stay within the agreed-upon parameters for the test and the Auth0 load test policy. Auth0 reserves the right to terminate any performance/load testing which does not stay within the bounds of agreed-upon parameters or which extends beyond the scheduled test window.
## Project Planning Guide
We provide planning guidance in PDF format that you can download and refer to for details about our recommended strategies.
[B2C IAM Project Planning Guide](https://assets.ctfassets.net/cdy7uua7fh8z/3er1aEQ7Ul0q3c9leJWczR/b1f18b4c16abb7e78b01e4eb2b52bb8e/B2C_Project_Planning.pdf)
# Business-to-Consumer Logout
Source: https://auth0.com/docs/get-started/architecture-scenarios/business-to-consumer/logout
Plan user logout for a B2C IAM Auth0 implementation by deciding which session layers to end on each sign-out, from the application down to the identity provider.
[Logout](/docs/authenticate/login/logout) is the act of terminating an authenticated session when it's no longer needed, thus minimizing the likelihood that unauthorized parties can "take over" the session. This is typically achieved by provisioning a logout option on the user interface you provide to your users. Multiple types of sessions can be created when a user logs in (e.g., local application sessions, Auth0 session, third-party Identity Provider sessions), and you will need to determine which of these sessions need to be terminated when the user clicks any **Logout** option.
Your logout behavior should make it clear to a user which session(s) are being terminated, and ideally, will display a visual confirmation of logout afterward.
When configuring logout behavior, you'll need to consider:
* Which sessions should be terminated when the user initiates logout?
* What information should you provide to users as confirmation of the sessions terminated?
* Where should users be redirected to after logout completes?
* How long do you want sessions to last in the event that users do not trigger the logout process?
Given the varying types of sessions that can be created whenever a user logs in, there are several types of logout possible. Local application logout ends the session with the application, whereas Auth0 logout [terminates the Auth0 session](/docs/authenticate/login/logout/log-users-out-of-auth0). If you have organizations that are using their own IDP, you may want to consider a [Federated Logout](/docs/get-started/architecture-scenarios/business-to-consumer/logout#federated-logout) strategy and implement accordingly. Global, or [Single Logout](/docs/authenticate/login/logout/log-users-out-of-applications) (SLO), ends the Auth0 session and also sends a logout request/notice to applications relying on the Auth0 session.
The functionality provided by your application, as well as your use of features like [Single Sign-on (SSO)](/docs/authenticate/single-sign-on), will inform your decision as to what type of logout is required and what visual confirmation you'll need to provide to your users. Regardless of which option you choose, the logout process you implement should make it clear to the user which sessions are being terminated, and also when the logout process has completed.
If the logout feature in one application terminates an Auth0 SSO session that is used by other applications, the user may lose work if they have uncommitted transactions. Be sure to add the functionality needed to handle such conditions to minimize the likelihood of lost work.
## Where to send users after logout
Once your user logs out, they will be redirected to a specific location of your choosing. This location is specified as the **logout redirect URL**, and you can [define this as a parameter](/docs/authenticate/login/logout/redirect-users-after-logout) via the Auth0 Dashboard.
The URL(s) you use to redirect users after logging out must be [allowlisted in the Dashboard](/docs/authenticate/login/logout#redirect-users-after-logout) to mitigate open-redirect security vulnerabilities. You can allowlist them at the tenant or application levels.
If the user logs out and you redirect them back to the application, and the application redirects to an Identity Provider that still has a valid session for the user, the user will be logged in silently to the application. This may appear to the user as if the logout process didn't function properly.
## Automatic termination of sessions
Not all users will trigger the logout process manually, so Auth0 also provides **session timeout** to prevent overly long-lived sessions. This setting is [available and configurable via the Auth0 Dashboard](/docs/get-started/tenant-settings#login-session-management).
## Project Planning Guide
We provide planning guidance in PDF format that you can download and refer to for details about our recommended strategies.
[B2C IAM Project Planning Guide](https://assets.ctfassets.net/cdy7uua7fh8z/3er1aEQ7Ul0q3c9leJWczR/b1f18b4c16abb7e78b01e4eb2b52bb8e/B2C_Project_Planning.pdf)
# Business-to-Consumer Operations
Source: https://auth0.com/docs/get-started/architecture-scenarios/business-to-consumer/operations
Operationalize Auth0 tenant environments for a B2C IAM implementation by setting up the change management and monitoring routines each tenant needs.
Operationalization requires configuring or setting up infrastructure to support the scalable, measurable, and quantifiable operation that’s necessary for business continuity. In Auth0, this includes configuring supporting services (such as email providers), monitoring services for your deployment, detecting anomalous situations, and making preparations to recover quickly and smoothly when something goes wrong in a production environment.
Establishing effective operational behaviors is something that successful customers have found pays dividends, and there are a number of things you will want to consider when looking at your workflow:
* What should you do to proactively detect failures?
* How can you obtain data on Auth0’s operational status?
* Does Auth0 provide information regarding impending changes in the Auth0 service?
* How can you check for important notices from Auth0?
* What should you do with Auth0 log data so that you can analyze it and keep it for longer than Auth0’s limited data retention period?
* How can you scan Auth0 logs to determine if peak loads in your application trigger any rate limits or other errors?
* What email services should you use to support production volumes of email messages to users? Can I use Auth0's out-of-box email provider in my production environment?
* Do you need to configure your firewall and what firewall ports will you need to open for internal services that need to receive communications from Auth0 (such as custom databases, web services, and email servers)?
Auth0 supports functionality for [monitoring](/docs/get-started/architecture-scenarios/business-to-consumer/operations#monitoring) Auth0 service operation as well as providing information regarding Auth0 [service status](/docs/get-started/architecture-scenarios/business-to-consumer/operations#service-status). In addition, Auth0 makes information regarding upcoming changes to the Auth0 service available via various [notifications](/docs/get-started/architecture-scenarios/business-to-consumer/operations#notifications). Auth0 [logging](/docs/get-started/architecture-scenarios/business-to-consumer/operations#logging) services also provide extensive functionality for tracing and identifying operational anomalies, including restrictions encountered due to rate limiting and/or excessive loading.
Out-of-box, Auth0 provides email delivery services to help you accelerate your integration. These services, however, are not meant for scale-of-use in production environments, and do not provide for any specific service level or guarantee when it comes to email delivery. Our best practice recommendation, which customers typically follow, involves configuring your own [email service provider](/docs/get-started/architecture-scenarios/business-to-consumer/operations#email-provider-setup).
You may also need to make changes to [infrastructure](/docs/get-started/architecture-scenarios/business-to-consumer/operations#infrastructure) configuration in order to support integration with Auth0 and to support use of Auth0 extensibility. For example, if you need to provide callbacks to your internal or even external infrastructure (e.g., if you need to make external API calls in Actions, Rules, or Hooks, or via custom database scripts if you need to leverage existing legacy identity storage), then you may need to configure your Firewall settings.
## Service status
The Auth0 [status dashboard](https://status.auth0.com/) together with the Auth0 [uptime dashboard](http://uptime.auth0.com/) shows current and past status of the Auth0 service in a human-readable format. If any monitoring alerts are triggered, and as a first step in troubleshooting, your operations staff should check the status dashboard to see if there is a current outage. The public cloud status page also provides a facility for subscribing to outage notifications, and we also recommend that you check the status of any third-party [external services](/docs/deploy-monitor/monitor/check-external-services-status) you depend on, such as Social Providers. Having this information handy can help quickly eliminate possible causes when troubleshooting an issue and should be at the top of a troubleshooting checklist for developers as well as the help desk staff.
Information on how to check the status of Auth0 as well as any dependent services (such as Social Providers) should be at the top of a troubleshooting checklist for both developers and helpdesk staff, and we recommend you subscribe via the Auth0 status page to set up notification of any status updates.
In the event of an outage to the public cloud service, Auth0 performs a Root Cause Analysis (RCA) and publishes the results on the Auth0 status page. Auth0 performs a thorough investigation after an outage—including a determination of root cause, as well as contributing factors and how to prevent the issue from occurring again—and as a result, an RCA document can take a few weeks to be published.
## Email provider setup
Auth0 sends [emails](/docs/customize/email) to users for events such as signup welcome, email validation, breached password, and password reset events. You can customize the email templates for each type of event, and advanced customization of email handling is also possible. Auth0 provides a test email provider with limited capacity for basic testing, but you must set up your own email provider for production use, and customization of email templates will not work until you have established your own provider.
The default Auth0 email provider does not support sending production volumes of email or customization of email templates. You should therefore configure your own email provider before deploying to production.
## Infrastructure
### Firewalls
If custom code executing in Auth0 (such as in an Action, Rule, Hook, or custom database scripts) will call a service inside your network, or if you configure an on-premise SMTP provider in Auth0, then you may need to configure your firewall to allow [inbound traffic from Auth0](/docs/secure/security-guidance/data-security/allowlist). The IP addresses to allow through the firewall are specific to each region and are listed on the Rules, Hooks, custom database scripts, and email provider configuration screens in your Auth0 dashboard.
## Logging
Auth0 provides extensive capability when it comes to the logging of events, and also in the scanning of logs in order to identify event anomalies (see [logs documentation](/docs/deploy-monitor/logs) for further details). Standard log retention period for Auth0 logs is determined by subscription level with the shortest period being 2 days and the longest period being only 30 days. Leveraging Auth0 support for integrating with external logging services will allow you to retain logs outside of this, and will also provide for log aggregation across your organization.
You should leverage one of the log streaming solutions to send log data to an external log analytics service. This will enable keeping data for longer periods of time and provide advanced analytics on the log data.
You should review the log data [retention period](/docs/deploy-monitor/logs/log-data-retention) for your subscription level, and implement a log data export extension to send log data to an external log analytics service. You can use one of our [log streaming solutions](https://marketplace.auth0.com/features/log-streaming) in Auth0 Marketplace.
Development teams can use log files for troubleshooting and detecting intermittent errors that may be hard to find via QA tests. Security teams will probably want log data in case forensic data is ever needed. Exporting log files to services that provide comprehensive analytics can help you see patterns such as usage trends and attack protection triggers.
### Rate limits and other errors
Auth0 provides a unique error code for errors reported when the [rate limit is exceeded](/docs/troubleshoot/customer-support/operational-policies/rate-limit-policy). You should set up automatic scanning of logs to check for rate limit errors so you can proactively address activity that hits rate limits before it causes too much trouble for your users. Auth0 also publishes error codes for other types of errors, and you will find it helpful to scan logs for [authentication errors](/docs/libraries/common-auth0-library-authentication-errors) as well as errors from Auth0 Management API calls (Management API error codes are shown below each call in the [Management API Explorer](https://auth0.com/docs/api/management/v2)).
Calling the Management API to retrieve user profile information from within a Rule is a common cause of rate limit errors because such API calls can execute for every login as well as periodic session checks.
## Monitoring
You should establish mechanisms for [monitoring Auth0 implementations](/docs/deploy-monitor/monitor), so your support or operations team receives the timely information needed to proactively handle service outages. Auth0 provides monitoring endpoints that can be incorporated into your monitoring infrastructure. These endpoints are designed to provide a response suitable for consumption by monitoring services. It should be noted that they only provide data on Auth0. For complete end-to-end monitoring, which is essential for checking the ability of users to log in, we recommend that you set up synthetic transaction monitoring. This will provide greater granularity for your monitoring and enable you to detect outages unrelated to Auth0 as well as degradation of performance, so you can respond more proactively.
You should set up the ability to send synthetic login transactions to facilitate end-to-end monitoring of authentication. You can do this with a simple application that uses the [Resource Owner Password Grant](/docs/get-started/authentication-and-authorization-flow/resource-owner-password-flow/call-your-api-using-resource-owner-password-flow) in combination with a test user that has no privileges, and don’t forget about [Auth0 rate limiting policies](/docs/troubleshoot/customer-support/operational-policies/rate-limit-policy) too.
## Notifications
There are several different types of notifications from Auth0 that you should watch for as they contain important information that could impact your tenant(s) and project.
Proactive security notifications and other operational announcements are sent by Auth0 to dashboard administrators. You should ensure that the people who need to receive such messages are dashboard administrators.
### Dashboard notifications
From time to time, Auth0 may send an important announcement related to your tenant. These announcements about your service will be sent to your Auth0 dashboard and depending on the severity of the announcement, via email to the registered Auth0 dashboard administrators. You should make a regular practice of logging in to the dashboard and checking the bell icon at the top for any important notices. In addition, you should review emails from Auth0 in a timely fashion as they may convey important information about changes or actions you need to take.
### Change log
Auth0 provides information on changes to the service in the Auth0 [change log](https://auth0.com/changelog). You should make a regular practice of reviewing Auth0 change logs to be aware of changes. Support teams researching an issue may find it useful to review the change log to determine if recent changes might be related, especially if these are [breaking changes](/docs/troubleshoot/product-lifecycle/deprecations-and-migrations). Development teams will also want to review the change logs to identify new features that may be beneficial.
## Project Planning Guide
We provide planning guidance in PDF format that you can download and refer to for details about our recommended strategies.
[B2C IAM Project Planning Guide](https://assets.ctfassets.net/cdy7uua7fh8z/3er1aEQ7Ul0q3c9leJWczR/b1f18b4c16abb7e78b01e4eb2b52bb8e/B2C_Project_Planning.pdf)
# Business-to-Consumer Profile Management
Source: https://auth0.com/docs/get-started/architecture-scenarios/business-to-consumer/profile-management
User profile management planning considerations for your B2C IAM implementation.
At some point, you may need to change the information stored in a user’s profile. A user’s profile (also known as the user’s account) is stored in Auth0, and changes to the information it contains may need to happen for a number of different reasons:
* Self-served information updates
* Mandatory updates concerning your organizations T's & C’s
* Changes due to regulatory compliance
You cannot directly access a user profile across multiple Auth0 tenants. If you’re deploying multiple Auth0 tenants to production then this is something you need to be aware of.
An [Identity Provider](/docs/authenticate/identity-providers) populates a user’s profile using data supplied during the login process, and this is referred to as the [Normalized User Profile](/docs/manage-users/user-accounts/user-profiles/normalized-user-profiles).
The Normalized User Profile is updated from the identity provider during login, and you can change the limited set of the information it contains through the Auth0 Management API. You can also use Auth0 extensibility, such as [Actions](/docs/customize/actions), as an alternative to override information in the Normalized User Profile. See [User Profile Data Modification](https://auth0.com/docs/manage-users/user-accounts/user-profiles#change-user-profile-data) for more information.
By default, there is one user profile created for each user identity, and there are a number of things to consider:
* What should you do if you need to store information to help customize a user’s experience?
* What if you need to store user information that didn’t originate from an identity provider?
* Why would you need to store user-related information that a user cannot modify?
* What do you do if you need to store user-related information that a user cannot modify?
* What happens if a user forgets their password?
* What should a user do if they want to change their password?
Auth0 provides for the storage of metadata against a user’s profile, which allows for the capture of additional information, such as preference for language and/or accessibility in order to enhance the user experience. Metadata can be used to store both information that a user can change, and also information they can’t; the latter giving you the capability of associating, for example, a user profile with records in your existing systems without modifying existing implementation.
For users who forget their passwords or who are allowed to change their password via some existing self-service mechanism (or self-service mechanism you have planned), you can leverage Auth0-provided [Password Reset](#password-reset) functionality. This can be integrated with your existing implementation and comes already incorporated with any out-of-box Auth0 UI widgets including [Universal Login](/docs/authenticate/login/auth0-universal-login).
You’ll also want to make sure that you are working with a [verified user account](#account-verification) at all times. Auth0 provides out-of-box mechanisms for doing that too. You should also consider [regulatory compliance](/docs/secure/data-privacy-and-compliance) such as ([GDPR](https://eugdpr.org/) which has very specific requirements when it comes to protecting EU citizens from privacy and data breaches.
Though Auth0 doesn’t currently provide a centralized profile management portal out-of-the-box, for the purpose of self-serviced profile management, you can use the Auth0 Management API to build your own or utilize an already built UI. See our Auth0 [community guidance](https://community.auth0.com/t/how-to-allow-the-end-user-to-update-their-own-profile-information/6228) which describes the Management API endpoint. All calls to the Management API will require use of an [Access Token](/docs/secure/tokens/access-tokens).
Self-service profile management can raise security as well as data privacy concerns. For example, you may want to allow a user to change their email address, however, doing so without following best practice security guidance could result in a user locking themselves out of their account, leaking Personally Identifiable Information (PII), or worse, opening up a potential breach in security.
Alternatively, you can use the Auth0 Dashboard to [manage aspects of a user’s profile](/docs/manage-users/user-accounts/manage-users-using-the-dashboard). Managing a user’s profile via the Auth0 Dashboard is more of an administrative provision and **should not** be used for self-serviced profile management in a production environment. However, the interface provided by the Dashboard can be extremely useful during development as it provides a quick and simple way of manipulating a user’s profile information.
## Metadata
In addition to the Normalized User Profile information, metadata can be stored in an Auth0 user profile. Metadata provides a way to store information that did not originate from an identity provider, or a way to store information that overrides what an identity provider supplies.
Use of Metadata should follow Auth0 [user data storage best practices](/docs/secure/security-guidance/data-security/user-data-storage#metadata). Metadata storage is not designed to be a general purpose data store, and you should still use your own external storage facility when possible. Metadata size and complexity should also be kept to a minimum, and the Auth0 Management API has a strict set of guidance when it comes to updating and/or deleting metadata associated with a user.
You can manipulate metadata via both the Auth0 Management API and the Auth0 Authentication API. As is the case when managing the Normalized User Profile, calls to the Management API for manipulating Metadata requires use of an [Access Token](https://auth0.com/docs/api/management/v2/tokens).
Calls to the Management API are subject to [Auth0 Rate Limiting policy](/docs/troubleshoot/customer-support/operational-policies/rate-limit-policy). You must take this into consideration, and to assist, Auth0 generally recommends use of the appropriate [Auth0 SDK](/docs/libraries) for your development environment rather than calling our APIs directly.
### User metadata
User metadata (also referred to as `user_metadata`) is information that can be stored against a user profile and that a user can read and update as part of any self-service profile management. Metadata of this nature may be something like salutation for a user, or a user’s preferred language which could be used to [customize the emails](/docs/customize/email/email-templates) sent by Auth0.
Store any information that you want use to customize Auth0 emails in metadata and preferably `user_metadata` if the user is allowed to change it, such as information used to determine the language for an email.
### App metadata
App metadata (also referred to as `app_metadata`) is, on the other hand, information that can be stored with a user profile but can **only be read or updated with appropriate authorization**; `app_metadata` is not directly accessible to a user. This type of metadata could be something like a flag to indicate that the last set of valid terms and conditions was accepted by the user, and a date to indicate when the user accepted them.
## Password reset
For users who forget their passwords or who are allowed to change their password via some existing self-service mechanism, Auth0 provides [Password Reset](/docs/authenticate/database-connections/password-change) functionality. You can integrate this with your existing implementation and comes already incorporated with out-of-the-box Auth0 UI widgets included as part of [Universal Login](/docs/authenticate/login/auth0-universal-login).
Password change and password reset is only supported for Auth0 [Database Connection](/docs/authenticate/database-connections/password-change) types.
Auth0 Universal Login provides built-in UX support for password reset using Auth0 Authentication API functionality. Alternatively, you can use the [Auth0 Authentication API](/docs/authenticate/database-connections/password-change#authentication-api), through one of the Auth0 SDKs appropriate to your development environment. Email templates used during password reset workflow can also be fully customized, whether you use Auth0 out-of-box UI widgets or customized Universal Login.
You can use the Auth0 Management API, on the other hand, to [directly change the password](/docs/authenticate/database-connections/password-change#directly-set-the-new-password) for a user identity defined using a Database Connection type. You can use the Auth0 Management API as part of any self-service profile management implementation, and also as part of any [Change Password page customization](/docs/get-started/architecture-scenarios/business-to-consumer/branding).
## Account verification
You’ll also need to work with a verified user account at all times and make use of the mechanisms Auth0 provides. You should also consider regulatory compliance like [GDPR](https://eugdpr.org/) which has very specific requirements for protecting EU citizens from privacy and data breaches.
Auth0 provides out-of-box functionality for sending a [verification email](/docs/customize/email/manage-email-flow) to a user's email address to verify their account. By default, Auth0 automatically sends verification emails for any [Database Connection](/docs/authenticate/database-connections/password-change) identity created as part of [self sign-up](/docs/get-started/architecture-scenarios/business-to-consumer/provisioning#self-sign-up). However, Auth0 also provides a [Management API endpoint](https://auth0.com/docs/api/management/v2/tickets/post-email-verification) that you can use to send verification emails in cases where email address validation is not performed by a Social Provider upon user registration.
## Blocking users
[Blocking user access](/docs/manage-users/user-accounts/block-and-unblock-users) in Auth0 provides a way to prevent user login to applications under certain conditions. By default, the Auth0 Dashboard provides an out-of-the-box mechanism to give administrators the ability to both block and unblock user access to all applications, and you can implement this functionality via use of the [Auth0 Management API](https://auth0.com/docs/api/management/v2#!/Users/patch_users_by_id). You can also use Auth0 extensibility to [disable user access to certain applications](/docs/manage-users/user-accounts/manage-user-access-to-applications) as well as provide more fine-grained [access control](/docs/get-started/architecture-scenarios/business-to-consumer/authorization).
In addition, the Auth0 Management API provides you with the ability to [unblock](https://auth0.com/docs/api/management/v2#!/User_Blocks/delete_user_blocks_by_id) users disabled due to excessive use of incorrect credentials.
## Linking user accounts
By default, there is one user profile (user account) for each user identity. If you enable login from multiple identity providers - via Facebook or Google [social authentication](/docs/get-started/architecture-scenarios/business-to-consumer/authentication#social-authentication) as well as via Auth0 [username and password authentication](/docs/get-started/architecture-scenarios/business-to-consumer/authentication#username-and-password-authentication) - then each will have a separate user profile. You can use Auth0’s functionality for [linking user accounts](/docs/manage-users/user-accounts/user-account-linking) to create one profile for a user as an aggregate of all their associated identities.
The process of linking accounts merges user profiles in pairs: a primary account and a secondary account must be specified in the linking process. The number of accounts that can be linked, however, extends beyond a single pair. For example, you can use an account which already has multiple accounts merged with it as the primary, and link an additional secondary account to it. This means that one user account can have multiple identities associated with it, which provides a number of advantages:
* Users can log in using multiple identities without creating a separate profile for each one.
* Registered users can use new login identities, but continue using their existing profile.
* Users can carry their profile around, irrespective of which identity they use for login.
* Users can link to an account with more identity information in order to provide a more complete profile.
* Your applications can retrieve connection-specific user profile data.
## De-provisioning
Your application may need to support a user’s request to remove their account (for example, you might need to meet [GDPR](https://eugdpr.org/) requirements). You can implement such a feature, along with a number of other profile-related functions, using the [Management API](https://auth0.com/docs/api/management/v2#!/Users). The Management API allows you to retrieve information stored about a user and update it as required.
Auth0 is capable of supporting various privacy-related requirements including the display of links to consent notices on signup and data protection to support the rights of users to view and correct data you’ve collected about them.
[GDPR](https://eugdpr.org/) and other privacy directives require that users have the right to view and correct data held about them. They also have the right to be “forgotten.” You can use the Management API to address these requirements and meet your legislative obligations.
## Project Planning Guide
We provide planning guidance in PDF format that you can download and refer to for details about our recommended strategies.
[B2C IAM Project Planning Guide](https://assets.ctfassets.net/cdy7uua7fh8z/3er1aEQ7Ul0q3c9leJWczR/b1f18b4c16abb7e78b01e4eb2b52bb8e/B2C_Project_Planning.pdf)
# Business-to-Consumer Provisioning
Source: https://auth0.com/docs/get-started/architecture-scenarios/business-to-consumer/provisioning
User provisioning functionality and considerations for your B2C IAM implementation.
Determining how users get signed up is important to address early, and the decisions you make here will influence many of the decisions you will need to make going forward. We’ve found there are a typical set of patterns for how users will get added to your system, and things to take note of when considering workflow design too.
While Auth0 supports numerous workflows, web based workflows using Auth0 [Universal Login](/docs/authenticate/login/auth0-universal-login) for sign up are considered both industry and Auth0 best practice as they provide for optimal functionality and the best security.
Auth0 supports user sign up via a number of different [identity providers](/docs/authenticate/identity-providers). During sign up, Auth0 provisions the user profile so that it contains the user’s account information. There are a number of things to consider when looking at functionality and workflow:
* Should you use Auth0 as an identity store?
* Can you use your own (legacy) identity store with Auth0?
* How do you migrate user identities from your identity store to Auth0?
* Can your users sign up using their existing social accounts such as Google and Facebook?
Auth0 provides out-of-the-box identity storage that can be leveraged to store user credentials safely and securely. See [Self Sign Up](#self-sign-up) for more information. If you already have a legacy identity store and you want to offload the management of it, then the [User Migration](#user-migration) capabilities provide you with a number of options to do so.
Alternatively, if you have to maintain your legacy identity store - perhaps because you’ve got applications which you aren’t ready to migrate or which can’t be migrated - then you can use the [identity store proxy](#identity-store-proxy) capability. Allowing your customers to use “bring their own identity” is also an attractive proposition and though we find our customers don’t initially do so, you can use the [Social Sign Up](#social-sign-up) capability to provide it.
## User migration
In addition to hosting the [User Profile](/docs/get-started/architecture-scenarios/business-to-consumer/profile-management), Auth0 also has the capability to both [proxy](#identity-store-proxy) your own legacy identity store and provide a secure Auth0 hosted replacement. Both of these capabilities are supported via the use of Auth0 [Database Connections](/docs/authenticate/database-connections). If you decide to use Auth0 as a replacement for your legacy identity store then you can [migrate users](/docs/manage-users/user-migration) either all at once with bulk migration, or progressively with automatic migration.
Customers often opt for a two-stage approach to user migration, using Automatic Migration first to migrate as many users as possible, then using Bulk Migration for the users that remain. See [User Migration Scenarios](/docs/manage-users/user-migration/user-migration-scenarios) for more information.
Automatic Migration is preferred as it allows users to be migrated individually and also allows them to retain their existing password in almost all situations. For Bulk Migration, we recommend using the [Management API](https://auth0.com/docs/api/management/v2#!/Jobs/post_users_imports) over the [User Import/Export extension](/docs/manage-users/user-migration/user-import-export-extension) in all but the most simple cases, as the Management API provides for greater flexibility and control.
With Bulk Migration users typically need to **reset their password once migration is complete**, unless passwords are stored hashed in your legacy identity store using bcrypt (or you can generate them in bcrypt form). In this case, you may be able to use bulk migration and **preserve user passwords** as part of the process, depending on the bcrypt algorithm and the number of salt rounds used. See [Bulk Import Database Schema Examples](/docs/manage-users/user-migration/bulk-user-import-schema) for more information.
Calls to the Management API are subject to [Auth0 Rate Limiting policy](/docs/troubleshoot/customer-support/operational-policies/rate-limit-policy). You must take this into consideration, and to assist, Auth0 generally recommends use of the appropriate [Auth0 SDK](/docs/libraries) for your development environment rather than calling our APIs directly.
### Identity store proxy
Auth0 Database Connection types can also be configured to proxy an existing (legacy) identity store. If you need to keep user identities defined in your own legacy store - for example, if you have one or more business critical applications that you can’t migrate to Auth0, but which still need access to these identities - then you can easily integrate with Auth0. See [Authenticate Users Using Your Database](/docs/authenticate/database-connections/custom-db) for more information.
## Self sign up
Self sign up leverages Auth0 [Database Connections](/docs/authenticate/database-connections) to store the user ID, password, and (optional) username identity information collected from new users during the sign up process. Database connection policies governing things such as minimum [username length](/docs/authenticate/database-connections/require-username) or [password strength and complexity](/docs/authenticate/database-connections/password-options) can be configured via the Auth0 Dashboard.
Auth0 [Universal Login](/docs/authenticate/login/auth0-universal-login) as well Auth0 widgets such as [Lock](https://auth0.com/lock) integrate with Database Connections to provide comprehensive user interface functionality for sign up out-of-the-box. These UI artifacts are fully reactive, and with feature rich configuration and comprehensive customization, you can deploy functionality for user self sign up as well as login.
## Social sign up
Social signup is synonymous with sign in via [social authentication](/docs/get-started/architecture-scenarios/business-to-consumer/authentication) - there’s no distinction here \*per se\*, as user [profile](/docs/get-started/architecture-scenarios/business-to-consumer/profile-management) creation happens automatically upon first social login.
## Project planning guide
We provide planning guidance in PDF format that you can download and refer to for details about our recommended strategies.
[B2C IAM Project Planning Guide](https://assets.ctfassets.net/cdy7uua7fh8z/3er1aEQ7Ul0q3c9leJWczR/b1f18b4c16abb7e78b01e4eb2b52bb8e/B2C_Project_Planning.pdf)
# Business-to-Consumer Quality Assurance
Source: https://auth0.com/docs/get-started/architecture-scenarios/business-to-consumer/quality-assurance
Plan quality assurance for a B2C IAM Auth0 implementation by defining test environments and the regression coverage and sign-off gates each release must pass.
Quality Assurance is important in identifying issues before they impact your customers and, depending on the nature of your project, there are several different types of quality assurance testing that you’re going to want to consider as part of your integration with Auth0:
* Is your application easy to understand and use, even by those with a disability?
* Does your application need to work across various different browsers and devices?
* Does your application need to work in multinational and/or international environments?
* How will your application perform when subjected to unexpected production loads?
* How can you ensure your application is safe from security-related vulnerabilities?
Auth0 [Universal Login](/docs/authenticate/login/auth0-universal-login) and associated UI widgets (such as [Lock](/docs/libraries/lock)) have already been designed and built following usability and accessibility best practices, and provide tested out-of-box support for a whole host of [browsers and devices](/docs/troubleshoot/customer-support/product-support-matrix). Support for [internationalization](/docs/customize/internationalization-and-localization) (I18N) is also provided out-of-box, with built-in extensibility designed for custom multi-language and localization (L10N) situations.
To ensure functional requirements are met and unexpected events are handled correctly, guidance is provided for testing the [integration](#integration-testing) between your application(s) and Auth0, and for [unit testing](#unit-testing) individual extensibility modules (such as [Rules](/docs/customize/rules/debug-rules), [Hooks](/docs/customize/hooks/update-hooks), and Custom Database scripts). Guidance is also provided regarding Auth0's [penetration testing policy](/docs/troubleshoot/customer-support/operational-policies/penetration-testing-policy) to help when testing for security vulnerability, and also how [Mock](#mock-testing) testing can be leveraged in conjunction with our [load testing policy](/docs/troubleshoot/customer-support/operational-policies/load-testing-policy) to help ensure your application(s) perform under unexpected load.
## Unit testing
The objective of unit testing is to test individual units of code. If you create custom code within Auth0 in the form of Rules, Hooks, and/or Custom DB scripts, you should consider use a testing framework (such as [Mocha](https://mochajs.org/)) to test your code. Companies who have been most successful with Auth0 have found it useful to execute these unit tests prior to [automatically deploying](/docs/get-started/architecture-scenarios/business-to-consumer/deployment) Auth0 tenant configuration and collateral.
## Integration testing
It is a recommended best practice that you set up different tenants for development, testing, and production as discussed in Architecture guidance for [SDLC support](/docs/get-started/architecture-scenarios/business-to-consumer/architecture#sdlc-support). Auth0 allows you to configure variables that are available from within custom [extensibility](/docs/customize/extensions); these can be thought of as environment variables for your Auth0 tenant. Rather than hard code references that change when moving code between development, test, and production environments, you can use a variable name that is configured in the tenant and referenced by the custom extensibility code. This makes it easier for the same custom code to function, without changes, in different tenants as the code can reference variables which will be populated with tenant-specific values at execution time:
* For use of variables in Rules, see how to [configure values](/docs/customize/rules/configuration)
* For use of variables in Hooks, see how to configure [secrets](/docs/customize/hooks/hook-secrets) in the editor
* For use of variables in Actions, see Explore Flows and Triggers
* For use of variables in Custom DB Scripts, see the [configuration parameters](/docs/authenticate/database-connections/custom-db/create-db-connection#step-3-add-configuration-parameters)
We recommend using variables to contain tenant-specific values as well as any sensitive secrets that should not be exposed in your custom code. If your custom code is deployed in GitHub, then using a tenant-specific variable avoids exposure of sensitive values via your GitHub repository.
### Test automation
You can automate your overall build process by incorporating deployment automation as well as test automation. This can be used to deploy new versions of configuration and/or custom code to Auth0 and execute automated tests. If the tests uncover any failures, the deployment automation capabilities can be used to revert to the last working version. For further information, see the [deployment automation guidance](/docs/get-started/architecture-scenarios/business-to-consumer/deployment) provided.
## Mock testing
In a balance between Auth0’s [load testing policy](/docs/troubleshoot/customer-support/operational-policies/load-testing-policy) and the desire to load test, it is common practice among Auth0’s customers to mock out Auth0’s endpoints. This is a valuable practice in order to ensure that your application works with your expected interfaces without having to restrict your testing, and tools such as [MockServer](http://www.mock-server.com/), [JSON Server](https://github.com/typicode/json-server) or even [Postman](https://learning.getpostman.com/docs/postman/mock_servers/setting_up_mock/) can be used to assist.
## Project Planning Guide
We provide planning guidance in PDF format that you can download and refer to for details about our recommended strategies.
[B2C IAM Project Planning Guide](https://assets.ctfassets.net/cdy7uua7fh8z/3er1aEQ7Ul0q3c9leJWczR/b1f18b4c16abb7e78b01e4eb2b52bb8e/B2C_Project_Planning.pdf)
# Multiple Organization Architecture
Source: https://auth0.com/docs/get-started/architecture-scenarios/multiple-organization-architecture
An integration guide to multi-tenant architectures that must accommodate application instances for multiple Auth0 Organizations.
There are multiple use cases where users belong to third-party organizations that have signed up for the services you provide. These users may be employees of a third-party organization, customers, or a combination of both. Whatever the situation, this guide will provide you with a high-level overview of common use cases for multi-tenant applications.
B2B applications strive to create a pleasant user experience for the employees and customers of the businesses they serve. To accomplish this, service providers in B2B environments often allow branding to be added to their service for each of the organizations that use it. For example, let’s say you work for AwesomeSaaS (an SaaS software company), and your company uses Human0, an HR application for managing benefits and other HR functions. You access your HR app, and when you log in, the login experience is customized to display the AwesomeSaaS logo and use AwesomeSaaS colors.
As a B2B service provider designing an integration with Auth0, you will need to consider whether or not your customers (i.e., third-party organizations) will allow users from other organizations to log in to their instance of the application, and whether those users should be shared between organizations or isolated to a single organization.
Let’s start by introducing a couple of example applications that will highlight the various use cases. Travel0 is a fictitious company that offers online travel agency services. Travel0 has several applications, but for the purpose of this exercise, we’ll focus on two applications that are marketed directly to organizations:
* **Travel0 Corporate Booking**: Provides organizations with an online application where their employees can log in to and book work-related travel. Organizations that are customers of this application include:
* **Hoekstra & Associates**: A small law office with just a few employees. They do not have an IT department and don’t have the time or capacity to learn how to set up a corporate Identity Provider (IdP).
* **Gupta & Smith Law**: A larger law office, but they also do not have an IT department and don’t have the time or capacity to learn how to set up a corporate IdP.
* **MetaHexa Bank**: A large finance organization. They provide banking and insurance services and have their own IdP.
* **Many Student University (MSU)**: A large university with several campuses, where each campus has its own IdP.
* **Travel0 Adventure Management**: Allows organizations to create and market adventures such as whitewater rafting. Guides (who are freelance, or employees of some third-party travel/event organization) can use this application to create an account and handle scheduling to lead adventures. Organizations that are customers of this application include:
* **AdventureZ**: A large tour/event organizer. They have their own IdP that they use for their employees. They rarely need freelancers because they have enough guides on staff, some of whom only work during busy times. They also facilitate their guides’ ability to do freelance work for other companies.
* **Rocky Mountain High Adventures**: A new group entering the market for the first time. The cofounders run tours; they reach out to freelancers for help during busy times.
* **Suzie’s Rafting and Ziplines**: This company has been around for a long time. They have a staff of guides that handle most of their events, but they also hire freelancers when busy.
## Terminology
Many of the words used in the provided guidance can mean a number of different things. Take a moment to read through each definition so it’s clear when reading through the examples who is fulfilling what role:
* **Auth0 Tenant** (otherwise known as **Authorization Server**)**:** Tenant that you create in Auth0. It is an instance of an Authorization Server and represents one or more user domains.
* **Auth0 Organizations:** Refers to the Auth0 Tenant feature designed to support organizations. An instance of an [Auth0 Organization](/docs/manage-users/organizations/organizations-overview) will typically refer to a specific customer of yours.
* **Employee**: Person who works for your company. They will typically have an account in your Identity Provider (IdP) and may need admin access to one or more Organization Tenant instances. We will only use the term Employee to refer to Employees of your company. For users who belong to your customers' Organizations, see **Organization User**.
* **Identity Provider (IdP)**: Service, such as Auth0, that manages authentication of users, and optionally, provides user profile information and/or credentials management. The service may also provide delegation of credential validation and profile management via the use of a third-party IdP (such as Azure AD, Google, Facebook, etc.)
* **Organization:** Third-party company that is one of you customers. You may refer to an organization instance that is created for your application as a tenant; we will refer to it as an **Organization Tenant** to avoid confusing it with an Auth0 Tenant.
* **Organization Tenant:** Refers to a tenant that has been created for your customer as part of your application subscription/provision. This is different from an Auth0 Tenant.
* **Organization User**: Person who is logging in to the application as a member of an Organization. This may be an employee (of the Organization) or a customer. Any user referenced in an organization context can be considered an Organization User.
## User Isolation
It's important to determine the type of application you provide when it comes to organizational user isolation. There are two fundamental approaches to how and where each of these users are stored: [users isolated by organization](#users-isolated-by-organization) and [users shared between organizations](#users-shared-between-organizations).
The flow diagram above outlines the decision-making process. You should also consider whether [administrative-type access](#administrative-access-to-organizations) is required for an organization instance. This may be for an employee of your organization who acts as an administrator for one or more organizations, or for some other third party that provides help desk services or similar.
The following sections provide detail for each approach to organizational user isolation. Pay close attention to the atypical scenarios associated with each (i.e., where users need access to more than one organization) because these types of use cases often determine which approach more closely aligns with your requirements.
### Users isolated by Organization
Each organization has its own set of users, and users cannot and should not be able to access other organizations. If they attempt to do so, they should be rejected as unauthorized. If desired, you can force your users to create a separate account for each organization they belong to. As a person, they would be considered to be two or more different users.
In this scenario, a user is tied directly to the organization to which they belong or have access. Users have two options for how they log in: A) they create credentials in identity storage provisioned for the appropriate organization (i.e., UserID/Password Database Connection in your Auth0 Tenant), or B) they log in using their own organization’s IdP. In this use case, it would not make sense for a user to be part of multiple organizations, and the better practice would be to create a separate identity for each organization. Using Travel0 Corporate Booking as an example, the diagram below shows how this would look:
Sally is a typical user: she is an employee of MetaHexa Bank, and she can only access MetaHexa Bank’s instance of Travel0 Corporate Booking.
Pat, on the other hand, is an atypical user. Pat is a freelance paralegal, so she works for both Hoekstra & Associates and Gupta & Smith Law; she will access the Travel0 Corporate Booking instance for each using a separate user identity. One of many advantages for this approach is to limit the possibility of errors by forcing Pat to create two separate personas--one for each law firm. When Pat books travel, she must log in separately to the specific organization instance in order to make the booking.
Pat's situation is likely a rare use case. However, she illustrates what needs to be considered when determining user isolating requirements. If you want to isolate users to the organization with which they’re associated, this requires the creation of separate user identities. In this case, there is one identity for Pat when accessing the Hoekstra & Associates instance of Travel0 Corporate Booking, and a separate one for accessing Gupta & Smith Law’s instance of Travel0 Corporate Booking.
#### Use cases when isolating by organization
Applications that have users isolated per organization typically support three different use cases. For the examples in this section, we'll use the Travel0 Corporate Booking application scenarios described in our introduction. Travel0 is the Auth0 customer.
* **Organizations that either don’t have their own IdP or don’t know how to use it**. These tend to be smaller organizations that don’t have an IT department available to configure Single Sign-On (SSO) with the organization’s Identity Provider (IdP), or else don’t have an organization IdP fit for the task. In our Travel0 Corporate Booking example, Hoekstra & Associates is such an organization.
* **Organizations that prefer to configure their own IdP** so that their employees don’t have to create a new set of credentials for your application. Most organizations fall into this category. In our Travel0 Corporate Booking example, MetaHexa Bank is such an organization.
* **Organizations that require multiple authentication options**. Examples of this type of organization include those that frequently acquire new companies, organizations like schools that allow staff and parents to log in to the same application, and organizations that invite partners or customers to log in to their application instance (i.e., B2B2C organizations). In our examples, Many Student University (MSU) would be such an organization.
For the first two types of organizations, the solution tends to be fairly straightforward. These organizations are considered Single IdP organizations, and the approach is almost always the same. To learn more, read [Single Identity Provider Organizations](/docs/get-started/architecture-scenarios/multiple-organization-architecture/single-identity-provider-organizations).
Organizations that have more than one IdP for the organization trend toward a higher order of intricacy, but there are a few approaches that can minimize complexity. To learn more, read [Multiple Identity Provider Organizations](/docs/get-started/architecture-scenarios/multiple-organization-architecture/multiple-idp-orgs).
### Users shared between Organizations
A user may belong to more than one organization, and it would be convenient if that user did not have to have a separate identity/account as they navigate from one organization to another. Organizations can still use their own IdP in such cases.
In this scenario, a user is no longer tied directly to the organization to which they belong or have access. Users now have two options for how they log in: A) they create credentials in identity storage provisioned generally (i.e., in a single UserID/Password Database Connection in your Auth0 Tenant), rather than in any identity store specifically allocated in your Auth0 Tenant for the organization, or B) they log in using their own organization’s IdP. Once a user has an identity, they are then given permission to access each of the organizations to which they should have access. This could mean access to just one organization, or it may mean they have access to more than one organization. Users will need to understand that when prompted to log in, they can use the same credentials to access each organization’s instance. Using Travel0 Adventure Management as an example, the diagram above shows how this would look.
Jonno is a typical user. Jonno is an employee of Suzie’s Rafting and Ziplines. Jonno is only able to log in to the instance of Travel0 Adventure Management provisioned to create and guide adventures for Suzie’s Rafting and Ziplines. Jonno’s credentials are either stored in a Database Connection associated with Travel0’s Auth0 Tenant or in Suzie’s Zipline and Rafting’s IdP (depending on whether they want to manage their user identities or not).
Sumana is an atypical user. Sumana is an employee of AdventureZ, but as AdventureZ also coordinates freelance opportunities for the smaller guide companies during high peak times, Sumana has been invited to join Rocky Mountain High Adventures as a freelancer. Sumana is authorized to log in to both AdventureZ and Rocky Mountain’s instances of Travel0 Adventure Management. However, because she has never been invited as a guide to Suzie’s Rafting and Ziplines, she is not authorized to access that instance.
Sumana needs to have the same identity for both organizations because guiding involves the use of a rating system, and Sumana’s ratings need to carry over and be combined between the organizations with which she works. Sumana’s credentials, like Jonno’s, are either stored in a Database Connection associated with Travel0’s Auth0 Tenant, or in AdventureZ’s IdP (depending on whether AdventureZ wants to manage user identities or not). Where her credentials are stored has no bearing on the organization instances to which she has access.
### Administrative access to Organizations
There are scenarios where you will need to provide administrative access across your organizations. Typically, this will be for administrative tasks outside of user Profile/Account management (as described in [Profile Management](/docs/get-started/architecture-scenarios/multiple-organization-architecture/single-identity-provider-organizations/profile-management)), and you may need to provide access to your employees as well as to third parties.
Always enable Multi-factor Authentication (MFA) for Auth0 Tenant administrators who are provided access via the Auth0 Dashboard. Note that you must follow a different process to enable MFA for an Auth0 Tenant administrator than you do to enable MFA for the Auth0 Tenant itself. To learn how to enable MFA for an Auth0 Tenant Administrator, see [Manage Dashboard Access with Multi-factor Authentication](/docs/get-started/manage-dashboard-access/add-change-remove-mfa).
The Auth0 Dashboard can be configured via [role-based access control](/docs/get-started/manage-dashboard-access/feature-access-by-role), which will allow you to define specific roles for your employees across your Auth0 Tenant deployment as a whole. You can even leverage your own corporate IdP to provide Auth0 Tenant Administrator authentication for your employees, as well as extended Tenant Administrator access to trusted third-parties.
For other administrative access, you will typically want to build your own API and/or application, which you will use in conjunction with the Auth0 Management API. Providing administrative access to your Auth0 Tenant via the Auth0 Dashboard for a wide range of users is not recommended. While building such an application/API is beyond the scope of this document, it’s recommended that you seek help from [Auth0 Professional Services](/docs/get-started/professional-services) before embarking on such an endeavor.
## Learn more
* [Single Identity Provider Organizations](/docs/get-started/architecture-scenarios/multiple-organization-architecture/single-identity-provider-organizations)
* [Multiple Identity Provider Organizations](/docs/get-started/architecture-scenarios/multiple-organization-architecture/multiple-idp-orgs)
# Multiple Identity Provider Organizations
Source: https://auth0.com/docs/get-started/architecture-scenarios/multiple-organization-architecture/multiple-idp-orgs
Learn about multiple Identity Provider (IdP) Organizations, in which every Auth0 Organization has more than one Auth0 connection.
In the Multiple Identity Provider (IdP) Organizations scenario, every organization that uses the [Auth0 Organizations](/docs/manage-users/organizations/organizations-overview) feature uses more than one [Auth0 Connection](/docs/authenticate/identity-providers). In many ways, the implementation for this scenario is identical to the implementation for [Single Identity Provider Organizations. I](/docs/get-started/architecture-scenarios/multiple-organization-architecture/single-identity-provider-organizations)n fact, the Auth0 Organizations feature supports mix and match, as well as easy transition between the two. However, you should consider a few additional items.
## Connections
In addition to the information that typically is included as part of [Authorization](/docs/get-started/architecture-scenarios/multiple-organization-architecture/single-identity-provider-organizations/authorization), you can add details regarding the specific [Auth0 Connection](/docs/authenticate/identity-providers) via which first-factor authentication for the user was performed. While not explicitly required, you can add such information to an ID Token and/or Access Token as a custom claim in order to provide your application and/or API with additional context that can be used with access control.
As illustrated in the following example, custom claims are typically added via Rule extensibility, which can access Connection specifics via use of the [`context`](/docs/customize/rules/context-object) object:
```js lines theme={null}
context.idToken['http://travel0.net/connection'] = context.connection; // Connection name claim
context.accessToken['http://travel0.net/connection'] = context.connection; // Connection name claim
```
The Rules context object provides access to various aspects of the connection used to first-factor authenticate a user, including the `connection` name, `connectionID`, and `connectionStrategy`. This also provides Rule extensibility with additional information that can be used as part of any [centralized policy enforcement](/docs/get-started/architecture-scenarios/multiple-organization-architecture/single-identity-provider-organizations/authorization).
### Database Connection
While Auth0 allows you to [provision](/docs/get-started/architecture-scenarios/multiple-organization-architecture/single-identity-provider-organizations/provisioning) multiple [Database and Custom Database Connections](/docs/authenticate/database-connections), we do not recommend that you associate more than one of these types of connection with an Auth0 Organization. Because Database and Custom Database Connections do not currently support Home Realm Discovery, which is a key component of [Identifier-First Authentication](/docs/authenticate/login/auth0-universal-login/identifier-first), the Universal Login New Experience cannot select between them if more than one is defined.
**Best Practice**
If you are defining a custom database connection for use with an Auth0 Organization, then make sure that one, and only one, custom database connection is associated with that Auth0 Organization at any given time.
### Enterprise Connection
If your enterprise application uses [Enterprise Federation](/docs/authenticate/enterprise-connections), you can activate [Identifier First Authentication with Home Realm Discovery](/docs/authenticate/login/auth0-universal-login/identifier-first) in its Authentication Profile. Once enabled, Home Realm Discovery detects email addresses from a known domain and automatically sends them to the proper Workforce login.
To learn more, read [Identifier First Authentication](/docs/manage-users/organizations/login-flows-for-organizations#identifier-first-authentication) in [Login Flows for Organizations](/docs/manage-users/organizations/login-flows-for-organizations).
### Social Connection
Other than the considerations described in the [Authentication](/docs/get-started/architecture-scenarios/multiple-organization-architecture/single-identity-provider-organizations/authentication) section, no additional concerns need to be addressed when Social Connections are used as part of a multiple IdP organization scenario.
# Single Identity Provider Organizations
Source: https://auth0.com/docs/get-started/architecture-scenarios/multiple-organization-architecture/single-identity-provider-organizations
Learn about Single Identity Provider(IdP) Organizations, in which every Auth0 Organization has exactly one Auth0 connection.
In the Single Identity Provider (IdP) Organizations scenario, every organization that uses the [Auth0 Organizations](/docs/manage-users/organizations/organizations-overview) feature uses exactly one Auth0 connection. This feature allows each application to select the appropriate organization defined on the Auth0 Tenant, which will either authenticate user credentials directly or forward the authentication request to the appropriate IdP to handle.
In this scenario, we’ll continue to use the [Travel0 Corporate Booking](/docs/get-started/architecture-scenarios/multiple-organization-architecture) example. In this example, the corporate booking application equates to your application and Travel0 corresponds to your company.
The Auth0 Organizations feature currently supports applications that use the [SAML](/docs/authenticate/protocols/saml/saml-configuration), [Open ID Connect](/docs/authenticate/protocols/openid-connect-protocol) protocols and/or the [OAuth 2](/docs/authenticate/protocols/oauth) framework. Applications that require [WS-Fed](/docs/authenticate/protocols/ws-fed-protocol) are not supported.
Regardless of how credentials are processed--whether user credentials are stored in a database connection (like with Hoekstra & Associates) or are validated via an enterprise connection (like with MetaHexa Bank) or a social connection--your application behaves the same way. Leveraging the [Organizations](/docs/manage-users/organizations/organizations-overview) feature allows you to configure and control the experience.
## Learn more
* [Single Identity Provider: Provisioning](/docs/get-started/architecture-scenarios/multiple-organization-architecture/single-identity-provider-organizations/provisioning)
* [Single Identity Provider: Branding](/docs/get-started/architecture-scenarios/multiple-organization-architecture/single-identity-provider-organizations/branding)
* [Single Identity Provider: Authentication](/docs/get-started/architecture-scenarios/multiple-organization-architecture/single-identity-provider-organizations/authentication)
* [Single Identity Provider: Authorization](/docs/get-started/architecture-scenarios/multiple-organization-architecture/single-identity-provider-organizations/authorization)
* [Single Identity Provider: Profile Management](/docs/get-started/architecture-scenarios/multiple-organization-architecture/single-identity-provider-organizations/profile-management)
* [Single Identity Provider: Logout](/docs/get-started/architecture-scenarios/multiple-organization-architecture/single-identity-provider-organizations/logout)
# Single Identity Provider: Authentication
Source: https://auth0.com/docs/get-started/architecture-scenarios/multiple-organization-architecture/single-identity-provider-organizations/authentication
Learn about authentication users through Organizations for multi-tenant architectures.
In our architecture scenarios, we provide general purpose guidance on [B2B Authentication](/docs/get-started/architecture-scenarios/business-to-business/authentication), including the use of the [Universal Login](/docs/authenticate/login/auth0-universal-login) as a recommended best practice, which we recommend reviewing alongside the guidance provided here.
**Best Practice**
While numerous authentication workflows are supported within Auth0, workflows using Auth0 Universal Login are considered both industry and Auth0 best practice because they provide [optimal functionality and security](/docs/authenticate/login/universal-vs-embedded-login). In particular, Universal Login provides [Single Sign On (SSO) out of the box](https://auth0.com/learn/how-to-implement-single-sign-on/) and helps mitigate attacks such as [phishing](https://auth0.com/blog/all-you-need-to-know-about-the-google-docs-phishing-attack/) and [bucket brigade](/docs/secure/security-guidance/prevent-threats); for this reason, it should be preferred wherever password credentials are supplied by a user. Crucially, the [New Universal Login Experience](/docs/authenticate/login/auth0-universal-login/universal-login-vs-classic-login/universal-experience) is also the only mechanism supported when using the Auth0 Organizations feature.
Authenticating users requires the processing of first-factor credentials. Whether this is performed by Auth0 or by some third-party Identity Provider (IdP), when you use the Auth0 Organizations feature, you must also use Auth0 [Universal Login Experience](/docs/authenticate/login/auth0-universal-login/universal-login-vs-classic-login/universal-experience) capability.
Auth0 supports only one authenticated user context per Auth0 Tenant; tenants cannot selectively switch between authenticated user contexts. Changing user context has an impact on any active SSO session, and this extends to the Auth0 Organizations feature. If per-organization contexts are absolutely necessary, then multiple Auth0 Tenants will need to be deployed to production. Because using multiple tenants has ramifications that affect Single Sign-On (SSO), user profile management, and so on, you should carefully consider before going down this route.
## Database Connection
Using our Hoekstra & Associates example, let's see how this Authentication implementation might flow with a user authenticated via an Auth0 Database Connection; most of the workflow described will typically be handled by using the relevant Auth0 SDK or library associated with your technology stack:
1. Jennifer from Hoekstra & Associates opens her browser and navigates to Hoekstra & Associates' instance of Travel0 Corporate Booking.
1. If Jennifer already has a session cookie with Hoekstra & Associates' instance of Travel0 Corporate Booking, then she will typically be logged in to the system, and we will exit here. For more information, see [Single Sign-On](/docs/authenticate/single-sign-on).
2. Hoekstra & Associates' instance of Travel0 Corporate Booking redirects to the Travel0 Auth0 Tenant using [Authorization Code Flow](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow) (with or without [PKCE](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow-with-pkce)) by calling the `/authorize` endpoint and passing parameters, typically via use of an [Auth0 SDK](/docs/libraries) or third-party library:
1. `redirect_uri`: [`https://hoekstra.corp.travel0.net/login/callback`](https://hoekstra.corp.travel0.net/login/callback)
2. `response_type`: `code`
3. `state`: Unique [state](/docs/secure/attack-protection/state-parameters) generated in this session
4. `scope`: `openid profile` ...
5. any necessary additional [OIDC Scopes](/docs/get-started/apis/scopes/openid-connect-scopes), depending on the information required about the user.
6. `client_id`: Client ID associated with the Application created in the Travel0 Auth0 Tenant for Hoekstra & Associates' instance of Travel0 Corporate Booking.
7. `organization`: Auth0 Organization to use. Where the organization is known ahead of time, a request to `/authorize` can include this parameter, which is specified in the form `organization=`organization\_id, where organization\_id is set to the identifier associated with the corresponding Auth0 Organization definition in your Auth0 Tenant. Alternatively, you can omit the `organization` parameter from the call to `/authorize` and configure your Auth0 Tenant to prompt the user to select the appropriate organization as part of first-factor authentication. For more information, see [Define Organization Behavior](/docs/manage-users/organizations/configure-organizations/define-organization-behavior).
If the `organization` parameter is included on a call to the `/authorize` endpoint, then this should be used consistently for the duration of any session with Auth0. The Organizations feature does not associate any selected organization with the Auth0 SSO session, so omitting the parameter will always prompt the user to select the desired organization.
3. The Travel0 Auth0 Tenant redirects to `/login` to collect credentials from the user. If Jennifer already has a Database session with Hoekstra & Associates, then steps 3a and 4 will be skipped. For more information, see [Single Sign-On](/docs/authenticate/single-sign-on).
1. The Universal Login Page, which you can configure to include organization-specific brand collateral as described in [Branding](/docs/get-started/architecture-scenarios/multiple-organization-architecture/single-identity-provider-organizations/branding), is displayed.
4. The user enters their credentials and clicks `login`.
5. The Travel0 Auth0 Tenant checks the credentials for the user; if valid, the [Rules](/docs/customize/rules) pipeline executes. Rules can be used to handle access control as described in [Authorization](/docs/get-started/architecture-scenarios/multiple-organization-architecture/single-identity-provider-organizations/authorization). If credentials for the user are invalid, then the user will be prompted to re-enter them.
Automatic membership assignment will be performed if this option has been specified. For more information, see [Grant Just-In-Time Membership to an Organization Connection](/docs/manage-users/organizations/configure-organizations/grant-just-in-time-membership). For [manually-assigned Membership](/docs/manage-users/organizations/configure-organizations/assign-members), validation will fail if the user is not already assigned as a member of the Organization.
6. Upon successful first-factor authentication and Rules execution, the user is redirected to the `redirect_uri` ([`https://hoekstra.corp.travel0.net/login/callback`](https://hoekstra.corp.travel0.net/login/callback)) with the `state` passed in step 2, as well as a `code`.
7. Hoekstra & Associates' instance of Travel0 Corporate Booking validates the `state` and then calls the Travel0 Auth0 Tenant at [`https://auth.travel0.net/oauth/token`](https://auth.travel0.net/oauth/token), passing the `code` and its `client id` and `client secret` in exchange for the [ID Token](/docs/secure/tokens/id-tokens). The ID Token is then used to generate a session for [`https://hoekstra.corp.travel0.net`](https://hoekstra.corp.travel0.net).
8. Hoekstra & Associates' instance of Travel0 Corporate Booking instance displays the appropriate page to the user.
## Enterprise Connection
Authenticating via an Enterprise Connection follows a very similar process. Using our MetaHexa Bank example, let's see how this Authentication implementation might flow with a user authenticated via the Enterprise Connection to MetaHexa Bank; again, most of the workflow described will typically be handled by using the relevant Auth0 SDK or library associated with your technology stack
1. Amintha from MetaHexa Bank opens her browser and navigates to MetaHexa Bank's instance of Travel0 Corporate Booking.
1. If Amintha already has a session cookie with MetaHexa Bank's instance of Travel0 Corporate Booking, then she will typically be logged in to the system, and we will exit here. For more information, see [Single Sign-On](/docs/authenticate/single-sign-on).
2. MetaHexa Bank's instance of Travel0 Corporate Booking redirects to the Travel0 Auth0 Tenant using [Authorization Code Flow](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow) (with or without [PKCE](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow-with-pkce)) by calling the `/authorize` endpoint and passing parameters, typically via use of an [Auth0 SDK](/docs/libraries) or third-party library:
1. `redirect_uri`: [`https://metahexa.corp.travel0.net/login/callback`](https://metahexa.corp.travel0.net/login/callback)
2. `response_type`: `code`
3. `state`: Unique [state](/docs/secure/attack-protection/state-parameters) generated in this session
4. `scope`: `openid profile` ...
5. any necessary additional [OIDC Scopes](/docs/get-started/apis/scopes/openid-connect-scopes), depending on the information required about the user.
6. `client_id`: Client ID associated with the Application created in the Travel0 Auth0 Tenant for MetaHexa Bank's instance of Travel0 Corporate Booking.
7. `organization`: Auth0 Organization to use. Where the organization is known ahead of time, a request to `/authorize` can include this parameter, which is specified in the form `organization=`organization\_id, where organization\_id is set to the identifier associated with the corresponding Auth0 Organization definition in your Auth0 Tenant. Alternatively, you can omit the `organization` parameter from the call to `/authorize` and configure your Auth0 Tenant to prompt the user to select the appropriate organization as part of first-factor authentication. For more information, see [Define Organization Behavior](/docs/manage-users/organizations/configure-organizations/define-organization-behavior).
If the `organization` parameter is included on a call to the `/authorize` endpoint, then this should be used consistently for the duration of any session with Auth0. The Organizations feature does not associate any selected organization with the Auth0 SSO session, so omitting the parameter will always prompt the user to select the desire organization.
8. `connection`: Name of the configured Auth0 Enterprise Connection for MetaHexa Bank.
**Best Practice**
Always supply the `connection` parameter. When not provided, the user is prompted to select the Enterprise Connection associated with the upstream Identity Provider (IdP), which is an extra step from a UX perspective.
3. The Travel Auth0 Tenant redirects to the MetaHexa IdP to authenticate first-factor credentials.
1. The login page is displayed, and the user enters credentials. If Amintha already has a session with the MetaHexa IdP, then steps 3a and 4 will be skipped. For more information, see [Single Sign-On (SSO)](/docs/authenticate/single-sign-on).
4. The user enters their credentials and clicks `login`.
5. Upon successful first-factor authentication, the [Rules](/docs/customize/rules) pipeline executes. Rules can be used to handle access control as described in [Authorization](/docs/get-started/architecture-scenarios/multiple-organization-architecture/single-identity-provider-organizations/authorization). If credentials for the user are invalid, then the user will be prompted to re-enter them.
Automatic membership assignment will be performed if this option has been specified. For more information, see [Grant Just-In-Time Membership to an Organization Connection](/docs/manage-users/organizations/configure-organizations/grant-just-in-time-membership). For [manually-assigned Membership](/docs/manage-users/organizations/configure-organizations/assign-members), validation will fail if the user is not already assigned as a member of the Organization.
Steps 6 through 8 will match those described in the [Database Connection](#database-connection) scenario, but where Amintha is the user instead of Jennifer, and where MetaHexa Bank (`metahexa.corp.travel0.net`) will be used in place of Hoekstra & Associates.
## Social Connection
Authentication via Social Connection follows a similar pattern to that associated with an [Enterprise Connection](#enterprise-connection), but where the upstream IdP is associated with the social provider rather than any specific organization.
Auth0 Social Connections are defined at the Tenant level. Typically, only one Social Connection is configured per social provider per Auth0 Tenant, which represents a definition to the Auth0 Tenant overall. Thus, any consent provided by a user will apply across all Auth0 Organizations defined in an Auth0 Tenant and not to any one organization in particular.
With Social Connections, user isolation cannot be modeled consistently on a per-organization basis. Although it may be tempting to model user isolation by creating multiple connections to a social provider, such as by using [Custom Social Connections](/docs/authenticate/identity-providers/social-identity-providers/oauth2), you should refrain from doing so; such a strategy can result in the same user ID being created in multiple connection definitions, which will invariably lead to problems down the line.
# Single Identity Provider: Authorization
Source: https://auth0.com/docs/get-started/architecture-scenarios/multiple-organization-architecture/single-identity-provider-organizations/authorization
Learn about authorizing users for Organizations in multi-tenant architectures.
When thinking about authorization, you typically need to consider how you determine what a person is allowed to do and how you communicate this information to your applications and/or APIs. Depending on the applications you have, you may be affected by one or both of these. In our architecture scenarios, we provide general purpose guidance on [B2B Authorization](/docs/get-started/architecture-scenarios/business-to-business/authorization), which we recommend reviewing alongside the guidance provided here.
* [ID Tokens](/docs/secure/tokens/id-tokens) are often used to convey user authorization information to applications through custom claims, which can be added using [Rules](/docs/customize/rules) extensibility. Added claims can allow you to present a user interface in which users don’t have the ability to attempt something they are not permitted to do. Authorization information in an ID Token also provides any application backend with a way to restrict users from bypassing frontend controls for traditional web apps.
**Best Practice**
You can leverage [Auth0 Role-Based Access Control](/docs/manage-users/access-control/rbac) (RBAC) via the [Auth0 Authorization Core](/docs/manage-users/access-control/configure-core-rbac) feature to define access permissions, which can be automatically applied to Access Tokens. For further details, see [Enable Role-Based Access Control for APIs](/docs/get-started/apis/enable-role-based-access-control-for-apis).
Auth0 RBAC functionality can also provide information that you can add as custom claims to identity tokens (and access tokens, if you prefer manual application). Auth0 Organizations can leverage Auth0 RBAC capability via one or more membership-assigned roles. To learn more, see [Add Roles to Organization Members](/docs/manage-users/organizations/configure-organizations/add-member-roles).
* APIs that provide public-facing access to shared resource services are typically protected via access control mechanisms. For this purpose, Auth0 provides the ability to create an authorization bearer token, or OAuth 2 [access token](/docs/secure/tokens/access-tokens), which can convey user authorization information to an API, typically by using Auth0 [Role-Based Access Control (RBAC)](/docs/manage-users/access-control/configure-core-rbac) to apply one or more [membership-assigned roles](/docs/manage-users/organizations/configure-organizations/add-member-roles) or by adding custom claims via [Rules](/docs/customize/rules) extensibility. You can also leverage Auth0 RBAC capability to automatically adjust the `scope` claim of an access token. APIs can then use this information to apply the appropriate level of access control, which allows your API to enforce policy rules without having to do an extra lookup to get information about the user.
* In certain cases, you may want to implement application-level policies at the Auth0 Tenant; this allows you to apply policies to a whole range of applications and resource services (APIs) without needing to modify each one independently. You typically implement this via [Rules](/docs/customize/rules) extensibility.
**Best Practice**
Auth0 Organizations provides Auth0 Rules with access to organization-centric information that can be accessed when authenticating a user. This information is available via the `organization` object contained within the Rules `context` object. The `organization` object also provides access to any metadata provisioned against an Organization definition in Auth0. To learn more, see [Custom Development for Organizations](/docs/manage-users/organizations/custom-development).
## ID token claims
Usually claims can be added to identity tokens as discussed in our [ID Token Claims](/docs/get-started/architecture-scenarios/business-to-consumer/authorization) best practice guidance. When using the Auth0 Organizations feature, an `org_id` claim is automatically added to any identity token (for an example, see [Work with Tokens and Organizations](/docs/manage-users/organizations/using-tokens)) issued for users with organization membership. This parameter is validated by Auth0 SDKs. You can also add supplemental information associated with an Auth0 Organization by adding a custom claim to the identity token:
```js wrap lines theme={null}
context.idToken['http://travel0.net/multifactor'] = context.multifactor;
```
**Note**: If you have configured your tenant to support organization names in the Authentication API, the `org_name` claim is automatically included in ID tokens. To learn more, review [Use Organization Names in Authentication API](/docs/manage-users/organizations/configure-organizations/use-org-name-authentication-api).
### SAML assertion
A SAML assertion generated by an upstream Identity Provider (IdP) can be configured to populate standard or custom claims in an identity token consumed downstream.
For example, you can define the mappings section of a SAML Enterprise connection:
```json lines theme={null}
{
"user_id": [
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier",
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn",
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"
],
"email": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress",
"name": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name",
"given_name": [
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname",
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"
],
"family_name": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname",
"groups": "http://schemas.xmlsoap.org/claims/Group"
}
```
In this example, each field is assigned a value in the `user` object in an Action, which maps to standard claims in an ID Token or can be mapped using [custom claims](/docs/secure/tokens/json-web-tokens/json-web-token-claims#custom-claims). To learn more about customizing SAML mappings, read [Connect Your App to SAML Identity Providers: Set up mappings](/docs/authenticate/identity-providers/enterprise-identity-providers/saml#set-up-mappings).
When your application uses SAML and Auth0 acts as the IdP, you can include an [Organization](/docs/manage-users/organizations) in the SAML sign-in request using the organization query parameter:
```js wrap lines theme={null}
https://{YOUR_AUTH0_DOMAIN}/samlp/{YOUR_APP_CLIENT_ID}?organization={YOUR_ORGANIZATION_ID}
```
Auth0 returns the organization in the SAML response as a custom attribute:
```js wrap lines theme={null}
http://schemas.auth0.com/org_id
```
Any non-standard claims included in an OIDC token such as, custom claims set in an Action, are also included in the SAML response, prefixed with `http://schemas.auth0.com/`.
## Access token claims
In addition to any other claims you are adding to your access token for access control decisions (see our general [Access Token Claims](/docs/get-started/architecture-scenarios/business-to-consumer/authorization) best practice guidance), you will typically want to communicate the organization to which the user belongs.
As with the identity token, when using the Auth0 Organizations feature, the `org_id` claim is automatically added to any access token (for an example, see [Work with Tokens and Organizations](/docs/manage-users/organizations/using-tokens)) issued for users with organization membership. You can also add supplemental information associated with an Auth0 Organization by adding a custom claim to the access token:
```js wrap lines theme={null}
context.accessToken['http://travel0.net/multifactor'] = context.multifactor;
```
**Note**: If you have configured your tenant to support organization names in the Authentication API, the `org_name` claim is automatically included in access tokens. To learn more, review [Use Organization Names in Authentication API](/docs/manage-users/organizations/configure-organizations/use-org-name-authentication-api).
Alternatively, you could create a unique API audience for each organization, which would result in a unique API definition in Auth0. While this mechanism can mitigate the need for employing custom Rule extensibility, the complexity it introduces can be challenging. A simple comparison is as follows:
| Approach | Pros | Cons |
| - | - | - |
| Unique API Audience |
Out-of-the-box support for machine-to-machine access for a single organization.
Audience is a standard claim in an access token.
Refresh token processing requires no additional organization logic.
|
Must automate the creation of an API for every organization.
Independent roles may need to be created if using RBAC.
Must automate the provisioning of Roles to Membership.
API implementation has to process for multiple audiences.
|
| Custom Claim | Simplifies Auth0 Tenant configuration. | Custom code needed in a rule to add the organization to the access token. |
### Roles
The Auth0 Organizations feature also supports [Role-Based Access Control (RBAC)](/docs/manage-users/access-control/rbac) via the [Authorization Core](/docs/manage-users/access-control/configure-core-rbac) feature associated with an Auth0 Tenant. RBAC is [applied at the Auth0 Organization membership level](/docs/manage-users/organizations/configure-organizations/add-member-roles).
You can [enable Auth0 Authorization Core RBAC for an API](/docs/get-started/apis/enable-role-based-access-control-for-apis), which will result in the default `scope` claim in access tokens being modified automatically and a `permission` claim being added by default (for an example, see [Work with Tokens and Organizations](/docs/manage-users/organizations/using-tokens)). You can also add role information to identity tokens as custom claims by accessing the `authorization` object available in the Rules `context` object. To learn more, see [Rules with Authorization Sample Use Cases: Add User Roles to Tokens](/docs/manage-users/access-control/sample-use-cases-rules-with-authorization).
## Access control
Resource-level policy enforcement is the responsibility of the applications and/or APIs in your system. If you attempt to enforce policies in a centralized Authorization Server, such as your Auth0 Tenant, you will quickly run into a complex control system that is difficult to maintain and understand. Instead, your centralized Authorization Server can ensure that the appropriate information about a user is included in the tokens, so that your applications and APIs have the necessary information to make policy enforcement decisions. At the very least, in situations where there is too much information to contain in a single token (for example, resource-level permissions) or where information changes frequently enough that it would be out of date if accessed directly in the token, your applications and APIs should be able to look up the correct information.
Some high-level policy enforcement, on the other hand, can be handled in a centralized fashion. For example, when using an Auth0 Tenant context, there are some situations in which you could implement a Rule that mitigates the need for every application and/or API to apply the same restrictions. These include:
* blocking access to users from a particular IP address
* implementing specific requirements around Contextual or Adaptive MFA
* restricting login to only users who have verified their email address
* restricting access to a certain API audience, so a user cannot obtain an access token for any other API audience or cannot obtain an access token for that audience under certain circumstances. In this case, if you’re creating a custom API Audience for each organization, your Rule must also ensure that the authenticating user belongs to the organization that matches the corresponding API audience.
Auth0 Management API access is not restricted by organization; access to the Auth0 Management API is made via an access token allocated for use within a machine-to-machine context and cannot be constrained by an Auth0 Organization. Therefore, do not provide your customers with direct access to your instance of the Auth0 Management API. If your customers must manage aspects of their organization, such as user accounts (see [Profile Management](/docs/get-started/architecture-scenarios/multiple-organization-architecture/single-identity-provider-organizations/profile-management)), then you should build your own independent application and/or API for this purpose.
# Single Identity Provider: Branding
Source: https://auth0.com/docs/get-started/architecture-scenarios/multiple-organization-architecture/single-identity-provider-organizations/branding
Learn about customizing branding for Organizations in multi-tenant architectures.
Branding collateral associated with an organization is extremely valuable because using brand collateral provides users with an environment that they know and trust. Using recognized brand collateral also increases user confidence that the information they provide (for example, credentials) will be handled safely and securely. In our architecture scenarios, we provide general guidance on a number of [B2B Branding](/docs/get-started/architecture-scenarios/business-to-business/branding) topics, which we recommend reviewing alongside the guidance provided here.
## Universal Login
Branding a multi-organization environment can be more complex than in a standard environment where you only have to deal with one set of brand collateral. [Auth0 Organizations](/docs/manage-users/organizations/organizations-overview), however, leverages the [Universal Login experience](/docs/authenticate/login/auth0-universal-login/universal-login-vs-classic-login/universal-experience), which provides a number of [page templates](/docs/customize/login-pages/universal-login/customize-templates) to help simplify brand customization. Auth0 Organization configuration itself also allows you to [select basic color scheme branding](/docs/manage-users/organizations/configure-organizations/create-organizations).
### Login page
When using a [Database or Custom Database Connection](/docs/authenticate/database-connections), the Login page is used to obtain first-factor credentials for a user. You can configure the Login page using a set of [template variables](/docs/manage-users/organizations/create-first-organization) available to assist with per-organization customization.
You can configure the Login Page to display Enterprise and Social Connections for first-factor authentication, so Login Page branding can be relevant in these cases.
### Password Reset page
Similar to the [Login page](#login-page), the Password Reset page can be configured in scenarios that use a Database or Custom Database Connection. For scenarios involving an Enterprise Connection or a Social Connection, password changes are handled external to Auth0 by the upstream Identity Provider (IdP), so an Auth0 Password Reset page is never displayed.
### Multi-factor Authentication pages
Multi-Factor Authentication (MFA) in Auth0 is supported for all methods used to obtain first-factor credentials for a user (i.e., Database or Custom Database Connection, Enterprise Connection, or Social Connection). If you're using MFA, then you will likely want to brand the Universal Login experience pages associated with MFA, which can be done similarly to [Login page](#login-page) branding.
## Email templates
As with Universal Login page templates, a set of [email template variables](/docs/customize/email/email-templates/supported-liquid-syntax#general-variables) are available to assist with per-organization email customization. The email templates that need to be customized will vary depending on how users are authenticated (in other words, via Database or Custom Database Connection, Enterprise Connection, or Social Connection). To learn more about email template customization when using the Auth0 Organizations feature, see [Create Your First Organization: Email Templates](/docs/manage-users/organizations/create-first-organization).
## Custom Domains
The Auth0 Organizations feature supports only one [Custom Domain](/docs/customize/custom-domains), which is defined at the Auth0 Tenant level. Therefore, we recommend that you use a Custom Domain Name that is organization agnostic. If you absolutely must implement per-organization domain naming, then multiple Auth0 Tenants will need to be deployed to production. Because using multiple tenants has ramifications that affect Single Sign-On (SSO), user profile management, and so on, you should carefully consider before going down this route.
# Single Identity Provider: Logout
Source: https://auth0.com/docs/get-started/architecture-scenarios/multiple-organization-architecture/single-identity-provider-organizations/logout
Learn about logging users out for Organizations in multi-tenant architectures.
Terminating an authenticated session when it's no longer needed, otherwise known as Logout, is a good practice when it comes to security hygiene. Providing logout capability helps mitigate a number of potential security issues, including the likelihood that unauthorized parties can "take over" a session. In our architecture scenarios, we provide general purpose guidance on [B2B Logout](/docs/get-started/architecture-scenarios/business-to-business/logout), which we recommend reviewing alongside the guidance provided here. For this scenario, Logout is almost identical to logout in any other system, so it will have the same level of complexity as described in our standard documentation.
## Database Connection
Using our Hoekstra & Associates example, the following diagram illustrates the flow typically encountered when dealing with a user authenticated via an Auth0 Database Connection. Let’s walk through this flow to see what occurs; note that most of the workflow described will typically be handled by using the relevant Auth0 SDK or library associated with your technology stack:
1. Jennifer clicks `logout`.
2. Hoekstra & Associates' Instance of Travel0 Corporate Booking redirects the browser to the Travel0 Auth0 Tenant at [https://auth.travel0.net](https://auth.travel0.net) with the following parameters:
1. `returnTo`: [`https://hoekstra.corp.travel0.net/logoutComplete`](https://hoekstra.corp.travel0.net/logoutComplete)
2. `client_id`: Client ID associated with the Application created in the Travel0 Auth0 Tenant for the Hoekstra & Associates instance of Travel0 Corporate Booking.
**Best Practice**
Define Applications independently in Auth0 to make it easier to configure the `returnTo` URL where the corresponding `client_id` is used to provide correct validation of the supplied URL. To learn more, see [Provisioning](/docs/get-started/architecture-scenarios/multiple-organization-architecture/single-identity-provider-organizations/provisioning).
3. The Travel0 Auth0 Tenant terminates the Auth0 session established on behalf of the user, removing any SSO information, and redirects the browser to the specified `returnTo` URL.
4. The Hoekstra & Associates Instance of Travel0 Corporate Booking renders a page to let Jennifer know that she successfully logged out, likely with a button to log back in if desired.
1. At this stage, the Travel0 Corporate Booking instance will typically want to clean up the application session associated with the user, too.
If you do not wish to remove the user’s SSO session with Auth0, then the application can simply terminate the application session without redirecting to the `/logout` endpoint on the Auth0 Tenant. While the user will be logged out of the application, they will still have an SSO session with Auth0. In this case, you will likely want to tell the user that they are still logged in to the Auth0 Tenant, and that if they click `login` again, they may not be challenged to enter first-factor credentials.
## Enterprise Connection
For this scenario, implementing Logout can be a little more complex than it is when using a Database Connection. You still have the option to either logout from only the application or to have logout from the application result in logout from the Auth0 Tenant, too. However, you may also have the option of allowing logout from the organization’s Identity Provider (IdP), which most applications avoid, especially if users have access to other corporate applications to which they may need to stay logged in. Avoiding this, however, may result in users who subsequently click the `login` button being authenticated automatically without interactively providing first-factor credentials. Such functionality may make for an unexpected user experience, so you should consider communicating this to the user.
Using our MetaHexa Bank example, let's see how this Logout implementation might flow with a user authenticated via an Enterprise Connection to MetaHexa Bank; again, most of the workflow described will typically be handled by using the relevant Auth0 SDK or library associated with your technology stack:
1. Amintha clicks `logout`.
2. MetaHexa Bank's Instance of Travel0 Corporate Booking redirects the browser to the Travel0 Auth0 Tenant at [https://auth.travel0.net](https://auth.travel0.net) with the following parameters:
1. `returnTo`: [`https://metahexa.corp.travel0.net/logoutComplete`](https://metahexa.corp.travel0.net/logoutComplete)
2. `client_id`: Client ID associated with the Application created in the Travel0 Auth0 Tenant for the MetaHexa Bank instance of Travel0 Corporate Booking.
3. `federated`: Optional parameter used to log the user out of the MetaHexa Bank IdP. When specified, the browser is redirected to the `/logout` endpoint associated with the MetaHexa Bank IdP, which terminates the user’s session before redirecting the browser back to the Travel0 Auth0 Tenant.
**Best Practice**
Define Applications independently in Auth0 to make it easier to configure the `returnTo` URL where the corresponding `client_id` is used to provide correct validation of the supplied URL. To learn more, see [Provisioning](/docs/get-started/architecture-scenarios/multiple-organization-architecture/single-identity-provider-organizations/provisioning).
Steps 3 and 4 will match those described in the [Database Connection](#database-connection) scenario, but will use Amintha in place of Jennifer and MetaHexa Bank (`metahexa.corp.travel0.net`) in place of Hoekstra & Associates.
## Social Connection
In the context of Social Connections, Logout follows a similar pattern to that associated with an [Enterprise Connection](#enterprise-connection), but the upstream IdP is associated with the social provider rather than any specific organization. You will almost certainly never want to leverage federated logout capability with a social provider because the resulting user experience would be too disruptive.
# Single Identity Provider: Profile Management
Source: https://auth0.com/docs/get-started/architecture-scenarios/multiple-organization-architecture/single-identity-provider-organizations/profile-management
Learn about user profile management for Organizations in multi-tenant architectures.
Profile Management in Organization-based scenarios is generally the same as in other architecture scenarios. In our architecture scenarios, we provide general purpose guidance on [B2B Profile Management](/docs/get-started/architecture-scenarios/business-to-business/profile-management), which we recommend reviewing alongside the guidance provided here.
Before roles associated with a user can be managed, a user account must exist in Auth0. This is true even if you are using the [Auth0 Organizations Role capability associated with Membership](/docs/manage-users/organizations/configure-organizations/add-member-roles). However, user accounts that are provisioned via the [user invitation](/docs/get-started/architecture-scenarios/multiple-organization-architecture/single-identity-provider-organizations/provisioning) workflow can be assigned a role automatically as part of the invitation process. For details, see the [Invite Organization Members](/docs/manage-users/organizations/configure-organizations/invite-members). If you’re pre-registering a user using some other mechanism, then you must store Role information outside of Auth0 and access/copy it via the use of extensibility (for example, as part of a [Rule](/docs/customize/rules)) during first authentication.
Your application may have an associated specific set of user attributes (for example, user preferences or identifying information you use to better serve the customer) for which you provide some sort of self-service management to users. Additionally/alternatively, you may provide self-service profile management for attributes that are typically maintained by the Identity Provider (IdP).
**Best Practice**
In organization-related scenarios, email addresses should always be verified. Consequently, you should provide self-service email verification functionality for situations in which a user’s email address cannot otherwise be verified. For further details, see [Email Verification](/docs/manage-users/user-accounts/verify-emails).
## Database Connection
Auth0 provides you with the capability to implement self-service profile management support via the Auth0 Management API. If you are using Auth0 Organizations to provide [invitation-based user provisioning](/docs/manage-users/organizations/configure-organizations/invite-members), you will likely need to restrict changes to fields that are typically owned by your Auth0 Tenant as the Identity Provider (IdP). For example, you would want to restrict changes to email address because you would not want a user to use an email address other than the one to which their invitation was sent. Restricting changes to the email address field would prevent company-specific emails from going to entered personal email addresses.
Alternatively, you may want to consider providing a few self-service items for users who authenticate via a Database Connection in Auth0. You may want users to be able to:
* change their email address
* change any associated phone numbers
* change their username
* de-provision their accounts as part of regulatory compliance (such as GDPR)
* perform password change processing, which we typically recommend you implement via [password reset](/docs/authenticate/database-connections/password-change#trigger-an-interactive-password-reset-flow) and which will typically leverage the organization-specific branding described in [Branding: Password Reset Page](/docs/get-started/architecture-scenarios/multiple-organization-architecture/single-identity-provider-organizations/branding).
Self-service capability typically needs to be implemented and hosted external to Auth0 and must be very secure.
## Enterprise connection
Because the upstream Identity Provider (IdP) typically handles IdP-managed user profile attributes, profile management can be fairly non-existent for this use case. However, if you use application-specific user attributes, then you may still want to provide self-service capability.
In addition, you will almost certainly want to provide an organization with a way to de-provision users from your Auth0 Tenant. Auth0 does not communicate with an upstream IdP, except when the Auth0 SSO session expires. Because an SSO session's time to expiration will likely be too long for most scenarios in which a user is deleted, an organization administrator will need a way to block or delete a user independently.
## Social connection
In the context of Social Connections, profile management follows a similar pattern to that associated with an [Enterprise Connection](#enterprise-connection), but the upstream IdP is associated with the social provider rather than any specific organization.
## Administration
In certain situations you will want to give your customers access to manage user accounts associated with their organization. This is often true for help-desk-type scenarios in which a help desk operator may update profile information on behalf of a user or help a user unblock an account.
Out of the box, Auth0 provides the Auth0 Dashboard, which is used for general management of an Auth0 Tenant. However, you would not want to give a customer access to your Auth0 Tenant Dashboard because they would then have the ability to manage all users across all organizations, which would not be desirable.
While the Auth0 Tenant Dashboard can be used to manage user accounts, it does not provide for organizational-level isolation. Giving a customer access to your Auth0 Dashboard allows them to modify users across all organizations, which is not desirable. The Auth0 Delegated Admin dashboard can be configured to provide user account administration that is Auth0-Organization-aware; however, it cannot be used to manage user [Membership](/docs/manage-users/organizations/create-first-organization) or [Invitation](/docs/manage-users/organizations/configure-organizations/invite-members).
If you already provide help-desk-type capability for your customers, then you can use the Auth0 Management API to manage user accounts in Auth0. For example, the Management API can be used to [retrieve organization members](/docs/manage-users/organizations/configure-organizations/retrieve-members) and [organizations to which a user belongs](/docs/manage-users/organizations/configure-organizations/retrieve-user-membership). If you do not already provide help desk capability, then you will need to build this functionality if you require it.
# Single Identity Provider: Provisioning
Source: https://auth0.com/docs/get-started/architecture-scenarios/multiple-organization-architecture/single-identity-provider-organizations/provisioning
Learn about provisioning Organizations for multi-tenant architectures.
By using the Auth0 Organizations feature, a single Auth0 Tenant can be provisioned for deployment to a production environment. For all but the most complex architectural scenarios, provisioning of a single Auth0 Tenant for use in a production environment is recommended because it provides ease of integration/use for [Single Sign-On (SSO)](/docs/authenticate/single-sign-on), user [Profile Management](/docs/get-started/architecture-scenarios/multiple-organization-architecture/single-identity-provider-organizations/profile-management), and so on. Depending on the implementation, you will need to address some additional items concerning setup of your Auth0 Tenant and your corresponding integration.
Branding associated with an organization is extremely valuable because using brand collateral provides users with an environment that they know and trust. Using recognized brand collateral also increases user confidence that the information they provide (for example, credentials) will be handled safely and securely. Default out-of-box Auth0 branding should therefore be replaced. To learn more, see [Branding](/docs/get-started/architecture-scenarios/multiple-organization-architecture/single-identity-provider-organizations/branding).
## Organizations
You should create an independent Auth0 Organization for each of the organizations you will support. In this case, we’ll create the `hoekstra` organization to represent Hoekstra & Associates in our example, and the `metahexa` organization to represent MetaHexa Bank. You can [create organizations](/docs/manage-users/organizations/configure-organizations/create-organizations) either manually via the Auth0 Dashboard or programmatically via the use of the Auth0 Management API.
## Applications
Depending on how your Organization Tenant implementation is designed, you have different options when creating [Application](/docs/get-started/applications) definitions within your Auth0 Tenant. Whichever option you choose, the [Organization behavior is defined at the application level](/docs/manage-users/organizations/configure-organizations/define-organization-behavior).
If you provision a separate Organization Tenant for each of your customers, then you will typically need an independent Application definition in Auth0 for each. This arrangement will also usually involve sending both the Application-specific `client_id` parameter and the `organization` parameter, which identifies which Auth0 Organization to use, as part of the call to the `/authorize` endpoint. To learn more, see [Authentication](/docs/get-started/architecture-scenarios/multiple-organization-architecture/single-identity-provider-organizations/authentication).
**Best Practice**
For ease of configuration and maximized security isolation, define Applications in Auth0 independently. Doing so allows items like allowed callback URLs to be configured independently and, following the principle of least privilege, minimizes the potential exposure of any Client ID and Client Secret information.
Alternatively, the use of a single Application definition in Auth0 is supported. In this case, the user will be prompted to specify the required organization as part of first-factor authentication. This will typically require the use of a common Application `client_id`, but the `organization` parameter will be omitted on the call to the `/authorize` endpoint.
## Connections
Next, define the [Connections](/docs/authenticate/identity-providers) that will be used to authenticate users. In this case, we’ll define a [Database Connection](/docs/authenticate/database-connections) for users associated with Hoekstra & Associates and an [Enterprise Connection](/docs/authenticate/identity-providers/enterprise-identity-providers) for users associated with MetaHexa Bank.
**Best Practice**
For Single Identity Provider (IdP) Organizations, create one Connection for each defined organization in order to provide flexibility for a number of use case scenarios. For example, a single [Database or Custom Database Connection](/docs/authenticate/database-connections) per organization allows you to easily delete users associated with organizations that get decommissioned and offers maximum flexibility for organizations that have differing requirements for password complexity.
Once the Connection has been defined, it can be provisioned to the appropriate Auth0 Organization using either the Auth0 Dashboard or Auth0 Management API. For more information, see [Enable Organization Connections](/docs/manage-users/organizations/configure-organizations/enable-connections).
## Users
For users that are authenticated via Connections other than Database or Custom Database Connections, the user is provisioned to the external Identity Provider (IdP) independent of Auth0 and in the normal way. On the other hand, users that are authenticated via Database or Custom Database Connections can be provisioned in a number of different ways. The Auth0 Dashboard and Auth0 Management API can be used to create a user directly in your Auth0 Tenant. We also support [Automatic Migration](/docs/manage-users/user-migration/configure-automatic-migration-from-your-database) and [Bulk Migration](/docs/manage-users/user-migration/bulk-user-imports).
For a user to be provisioned via the Management API or the Dashboard, you must directly enable a Database or Custom Database Connection for at least one Application. Enabling a Database or Custom Database Connection for an Organization only will not suffice.
Users are then associated with an Auth0 Organization by assigning them memberships, and an Auth0 Organization can be configured to [assign user Membership automatically](/docs/manage-users/organizations/configure-organizations/grant-just-in-time-membership) or [on a manual basis](/docs/manage-users/organizations/configure-organizations/assign-members).
For a user to be manually assigned Membership to an organization, that user must already have a [User Profile](/docs/manage-users/user-accounts/user-profiles) defined in Auth0. You can [manually assign Membership](/docs/manage-users/organizations/configure-organizations/assign-members) using either the Auth0 Tenant Dashboard or the Auth0 Management API.
### Invitation
The Auth0 Organization feature also supports the use of Member Invitation. In the Member Invitation workflow, inviting a user to an application will result in the user being provisioned automatically and their user membership being generated automatically.
#### Database Connection
Using our Hoekstra & Associates example, let’s see how this implementation might flow where a Database Connection is used as part of user invitation; most of the workflow described will typically be handled by using the relevant Auth0 SDK or library associated with your technology stack:
1. Jennifer from Hoekstra & Associates receives an email sent from Travel0’s Auth0 Tenant on behalf of Hoekstra & Associates' instance of Travel0 Corporate Booking.
1. The email was sent as described in [Invite Organization Members](/docs/manage-users/organizations/configure-organizations/invite-members) and may have been triggered using either the Auth0 Dashboard or the Auth0 Management API.
2. Jennifer opens the email and clicks on its contained link. Doing so directs her browser to Hoekstra & Associates' instance of Travel0 Corporate Booking. The base URL used in the link is specified as the [Application Login URI](/docs/get-started/applications/application-settings), which forms part of Hoekstra & Associates' instance of Travel0 Corporate Booking application definition in the Travel0 Auth0 Tenant.
1. The link contains `organization` and `organization_name` parameters. The `organization` parameter is set to the ID of the corresponding Auth0 Organization definition in your Auth0 Tenant. This will be forwarded to the Auth0 Tenant as part of step 3.
2. The link also contains the `invitation` parameter, which will also be forwarded as part of step 3.
3. Hoekstra & Associates' instance of Travel0 Corporate Booking redirects to the Travel0 Auth0 Tenant using [Authorization Code Flow](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow) (with or without [PKCE](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow-with-pkce)) by calling the `/authorize` endpoint and passing parameters similar to the following, typically via use of an [Auth0 SDK](/docs/libraries) or third-party library:
1. `redirect_uri`: [`https://hoekstra.corp.travel0.net/login/callback`](https://hoekstra.corp.travel0.net/login/callback)
2. `response_type`: `code`
3. `state`: Unique [state](/docs/secure/attack-protection/state-parameters) generated in this session
4. `scope`: `openid profile` ...
5. any necessary additional [OIDC Scopes](/docs/get-started/apis/scopes/openid-connect-scopes), depending on the information required about the user.
6. `client_id`: Client ID associated with the Application created in the Travel0 Auth0 Tenant for Hoekstra & Associates' instance of Travel0 Corporate Booking.
7. `organization`: ID of the inviting organization typically obtained via the link in the email described in step 2. Specified in the form `organization=`organization\_id, where organization\_id is set to the identifier associated with the corresponding Auth0 Organization definition in your Auth0 Tenant.
8. `invitation`: Additional `invitation` parameter associated with the link in the email, as described in step 2.
4. The Travel0 Auth0 Tenant redirects to `/signup/invitation` to collect a password credential from the user.
1. A Universal Login Page, which you can configure to display organization-specific brand collateral as described in [Branding](/docs/get-started/architecture-scenarios/multiple-organization-architecture/single-identity-provider-organizations/branding), is displayed.
The invitation workflow associated with the Auth0 Organizations feature does not consider any SSO session held with Auth0. If a user is invited to sign up and they are already signed in, clicking the link in the email will always result in the display of the associated Universal Login Page.
5. The user enters their password (and any additional credentials, such as user name) and clicks continue. The user ID is set to the email address associated with the user and cannot be changed.
6. The Travel0 Auth0 Tenant checks credentials. If valid, the user is provisioned and Auth0 Organization Membership is set. The user is implicitly authenticated, and the [Rules](/docs/customize/rules) pipeline executes. Rules can be used to handle access control, as described in [Authorization](/docs/get-started/architecture-scenarios/multiple-organization-architecture/single-identity-provider-organizations/authorization).
1. If credentials for the user are invalid, then the user will be prompted to re-enter them.
7. Upon successful credential checking and Rules execution, the user is redirected to the `redirect_uri` ([`https://hoekstra.corp.travel0.net/login/callback`](https://hoekstra.corp.travel0.net/login/callback)) with the `state` passed in step 3, as well as a `code`.
8. Hoekstra & Associates' instance of Travel0 Corporate Booking validates the `state` and then calls the Travel0 Auth0 Tenant at [`https://auth.travel0.net/oauth/token`](https://auth.travel0.net/oauth/token), passing the `code` and its `client id` and `client secret` in exchange for the [ID Token](/docs/secure/tokens/id-tokens). The ID token is then used to generate a session for [`https://hoekstra.corp.travel0.net`](https://hoekstra.corp.travel0.net).
9. Hoekstra & Associates' instance of Travel0 Corporate Booking instance displays the appropriate page to the user.
#### Enterprise Connection
Using our MetaHexa Bank example, let’s see how this implementation might flow where an Enterprise Connection is used as part of user invitation; again, most of the workflow described will typically be handled by using the relevant Auth0 SDK or library associated with your technology stack:
1. Amintha from MetaHexa Bank receives an email sent from Travel0’s Auth0 Tenant on behalf of MetaHexa Bank's instance of Travel0 Corporate Booking.
1. The email was sent as described in [Invite Organization Members](/docs/manage-users/organizations/configure-organizations/invite-members) and may have been triggered using either the Auth0 Dashboard or the Auth0 Management API.
2. Amintha opens the email and clicks on its contained link. Doing so directs her browser to MetaHexa Bank's instance of Travel0 Corporate Booking. The base URL used in the link is specified as the [Application Login URI](/docs/get-started/applications/application-settings), which forms part of MetaHexa Bank's instance of Travel0 Corporate Booking application definition in the Travel0 Auth0 Tenant.
1. The link contains `organization` and `organization_name` parameters. The `organization` parameter is set to the ID of the corresponding Auth0 Organization definition in your Auth0 Tenant. This will be forwarded to the Auth0 Tenant as part of step 3.
2. The link also contains the `invitation` parameter, which will also be forwarded as part of step 3.
3. MetaHexa Bank's instance of Travel0 Corporate Booking redirects to the Travel0 Auth0 Tenant using [Authorization Code Flow](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow) (with or without [PKCE](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow-with-pkce)) by calling the `/authorize` endpoint and passing parameters similar to the following, typically via use of an [Auth0 SDK](/docs/libraries) or third-party library:
1. `redirect_uri`: [`https://metahexa.corp.travel0.net/login/callback`](https://metahexa.corp.travel0.net/login/callback)
2. `response_type`: `code`
3. `state`: Unique [state](/docs/secure/attack-protection/state-parameters) generated in this session
4. `scope`: `openid profile` ...
5. any necessary additional [OIDC Scopes](/docs/get-started/apis/scopes/openid-connect-scopes), depending on the information required about the user.
6. `client_id`: Client ID associated with the Application created in the Travel0 Auth0 Tenant for MetaHexa Bank's instance of Travel0 Corporate Booking.
7. `organization`: ID of the inviting organization typically obtained via the link in the email described in step 2. Specified in the form `organization=`organization\_id, where organization\_id is set to the identifier associated with the corresponding Auth0 Organization definition in your Auth0 Tenant.
8. `invitation`: Additional `invitation` parameter associated with the link in the email, as described in step 2.
4. The Travel0 Auth0 Tenant redirects to `/invitation`, where Amintha is informed that she will be redirected to the MetaHexa IdP to authenticate first-factor credentials.
1. The user confirms, and
2. Auth0 redirects to the MetaHexa Bank IdP instance, where
3. The login page is displayed, and the user enters credentials and clicks `login`.
5. If successful, the Auth0 Organization Membership is set, the user is implicitly authenticated, and the [Rules](/docs/customize/rules) pipeline executes. Rules can be used to handle access control as described in [Authorization](/docs/get-started/architecture-scenarios/multiple-organization-architecture/single-identity-provider-organizations/authorization).
Steps 6 through 8 will match those described in the [Database Connection](#database-connection) scenario, but where Amintha is the user instead of Jennifer, and where MetaHexa Bank (`metahexa.corp.travel0.net`) will be used in place of Hoekstra & Associates.
#### Social Connection
Invitation via Social Connection follows a similar pattern to that associated with an [Enterprise Connection](#enterprise-connections), but the upstream IdP is associated with the social provider rather than any specific organization. For additional considerations with respect to using Social Connections, please see [Authentication](/docs/get-started/architecture-scenarios/multiple-organization-architecture/single-identity-provider-organizations/authentication).
# Server Applications with API
Source: https://auth0.com/docs/get-started/architecture-scenarios/server-application-api
Explains the architecture scenario with server to server communication with secure calls to an API (resource server) on behalf of the application.
In this scenario we will build a Timesheet API for a fictitious company named ExampleCo. The API will allow additional timesheet entries for an employee or a contractor.
We will also be building a cron job which will process timesheet entries from an external system to the centralized timesheet database using the API.
### TL;DR
* Auth0 provides API authentication and authorization as a means to secure access to API endpoints (read [API Authentication and Authorization](/docs/get-started/architecture-scenarios/server-application-api/part-1#api-authentication-and-authorization))
* For authorizing a Machine-to-Machine Application (a CLI, service or daemon where no user interaction is involved) Auth0 supports the Client Credentials grant (read [Client Credentials Grant](/docs/get-started/architecture-scenarios/server-application-api/part-1#client-credentials-grant))
* Both the Machine-to-Machine Application and the API must be configured in the Auth0 Dashboard (read [Auth0 Configuration](/docs/get-started/architecture-scenarios/server-application-api/part-2))
* The API will be secured by ensuring that a valid access token (which is implemented as a JSON Web Token) is passed in the HTTP Authorization header when calls are made to the API (read [Implement the API](/docs/get-started/architecture-scenarios/server-application-api/part-3))
* Upon successful authorization an access token is issued to the Machine-to-Machine Application (read [Get an access token](/docs/get-started/architecture-scenarios/server-application-api/part-3#get-an-access-token))
* The Machine-to-Machine Application can in turn use this access token to pass along as an HTTP Authorization header to authenticate calls to API endpoints (read [Invoke the API](/docs/get-started/architecture-scenarios/server-application-api/part-3#invoke-the-api))
## The Premise
ExampleCo is a consulting startup company. Currently they have approximately 100 employees and also outsource to external contractors. All employees and external contractors are required to complete timesheets every week. For this purpose, they built a timesheets application, a scenario we covered in [Single Sign-On for Regular Web Apps](/docs/get-started/architecture-scenarios/sso-for-regular-web-apps). Internal employees use this web app to fill in their timesheets but some of the external contractors already use another tool to track their timesheets. ExampleCo needs a solution to avoid the double work and decided to build a cron job to read the timesheet entries from this external system and automatically upload those to ExampleCo's backend using an API.
### Goals & Requirements
ExampleCo wants to build a flexible solution that:
* Allows for automated processes working on the backend
* Allows for future application launches, like a mobile application, in the architecture
* Allows for the Timesheets API to be secure and accessed by authorized users and applications
* Allows for a large part of code and business logic for the application to be shared across other apps
## Learn more
* [Solution Overview (Server Apps + API)](/docs/get-started/architecture-scenarios/server-application-api/part-1)
* [Auth0 Configuration (Server Apps + API)](/docs/get-started/architecture-scenarios/server-application-api/part-2)
* [Application Implementation (Server Apps + API)](/docs/get-started/architecture-scenarios/server-application-api/part-3)
* [Conclusion (Server Apps + API)](/docs/get-started/architecture-scenarios/server-application-api/part-4)
# Server Apps + API: Node.js Implementation for the API
Source: https://auth0.com/docs/get-started/architecture-scenarios/server-application-api/api-implementation-nodejs
The Node.js implementation of the API for the Server Client + API architecture scenario
As part of the [Server + API Architecture Scenario](/docs/get-started/architecture-scenarios/server-application-api), we will implement the Timesheets API in Node.js. Please refer to the scenario for information on the implemented solution.
Full source code for the Node.js API implementation can be found in [this GitHub repository](https://github.com/auth0-samples/auth0-pnp-exampleco-timesheets/tree/master/timesheets-api/node).
## Step 1. Define the API endpoint
We will use the [Express web application framework](http://expressjs.com/) to build our Node.js API.
### Create a package.json File
Create a folder for your API, navigate into it and run `npm init`. This will set up your `package.json` file.
You can leave the default settings or change them as you see fit.
Our sample’s `package.json` looks like the following:
```json lines theme={null}
{
"name": "timesheets-api",
"version": "1.0.0",
"description": "API used to add timesheet entries for employees and contractors",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/auth0-samples/auth0-pnp-timesheets.git"
},
"author": "Auth0",
"license": "MIT",
"bugs": {
"url": "https://github.com/auth0-samples/auth0-pnp-timesheets/issues"
},
"homepage": "https://github.com/auth0-samples/auth0-pnp-timesheets#readme"
}
```
### Install the Dependencies
Next, we need to set our dependencies. We will use the following modules:
* **express**: This module adds the [Express web application framework](https://expressjs.com/).
* **jwks-rsa**: This library retrieves RSA signing keys from a JWKS (JSON Web Key Set) endpoint. Using `expressJwtSecret` we can generate a secret provider that will provide the right signing key to `express-jwt` based on the `kid` in the JWT header. For more information refer to the [node-jwks-rsa GitHub repository](https://github.com/auth0/node-jwks-rsa).
* **express-jwt**: This module lets you authenticate HTTP requests using JWT tokens in your Node.js applications. It provides several functions that make working with JWTs easier. For more information refer to the [express-jwt GitHub repository](https://github.com/auth0/express-jwt).
* **body-parser**: This is a Node.js body parsing middleware. It extracts the entire body portion of an incoming request stream and exposes it on `req.body` as something easier to interface with.For more information and several alternatives refer to the body-parser GitHub repository.
To install these dependencies run the following:
```bash lines theme={null}
npm install express express-jwt jwks-rsa body-parser --save
```
### Implement the Endpoint
Navigate to your API directory and create a `server.js` file. Your code needs to:
* Set the dependencies.
* Enable the request body parsing middleware.
* Implement the endpoint.
* Launch the API server.
This is our sample implementation:
```javascript lines theme={null}
// set dependencies
const express = require('express');
const app = express();
const jwt = require('express-jwt');
const jwksRsa = require('jwks-rsa');
const bodyParser = require('body-parser');
// enable the use of request body parsing middleware
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true
}));
// create timesheets upload API endpoint
app.post('/timesheets/upload', function(req, res){
res.status(201).send({message: "This is the POST /timesheets/upload endpoint"});
})
// launch the API Server at localhost:8080
app.listen(8080);
```
Launch your API server using `node server` and make an HTTP POST request to `localhost:8080/timesheets/upload`. You should see a JSON response with a message `This is the POST /timesheets/upload endpoint`.
So now we have our endpoint but anyone can call it. Continue to the next paragraph to see how we can fix this.
## Step 2. Secure the API endpoint
In order to validate our token we will use the `jwt` function, provided by the [express-jwt middleware](https://github.com/auth0/express-jwt#usage), and the `jwks-rsa` package to retrieve the public key from Auth0. The libraries do the following:
1. `express-jwt` will decode the token and pass the request, the header and the payload to `jwksRsa.expressJwtSecret`.
2. `jwks-rsa` will then download all signing keys from the JWKS endpoint and see if a one of the signing keys matches the `kid` in the header of the JWT. If none of the signing keys match the incoming `kid`, an error will be thrown. If we have a match, we will pass the right signing key to `express-jwt`.
3. `express-jwt` will continue its own logic to validate the signature of the token, the expiration, `audience` and the `issuer`.
The steps we will follow in our code are:
* Create the middleware function to validate the access token.
* Enable the use of the middleware in our routes.
This is also a good time for you to implement the logic to save the timesheet entries to a local database, or whatever other storage mechanism you may prefer. This is our sample implementation (some code is omitted for brevity):
If we launch our server now and do an HTTP POST to `localhost:8080/timesheets/upload` we should get the error message `Missing or invalid token` (which is perfectly fine since we didn’t send an access token in our request).
In order to test the working scenario as well we need to:
* Get an access token. For details on how to do so refer to: [Get an Access Token](/docs/get-started/architecture-scenarios/server-application-api#get-an-access-token)
* Invoke the API while adding an `Authorization` header to our request with the value `Bearer ACCESS_TOKEN` (where `ACCESS_TOKEN` is the value of the token we retrieved in the first step).
## Step 3. Check the Client permissions
In this step we will add to our implementation the ability to check if the client has permissions (or `scope`) to use our endpoint in order to upload a timesheet. In particular we want to ensure that the token has the correct scope, which is `batch:upload`.
In order to do this we will make use of the `express-jwt-authz` Node.js package, so go ahead and add that to your project:
```bash lines theme={null}
npm install express-jwt-authz --save
```
Now it is as simple as adding a call to `jwtAuthz(...)` to your middleware to ensure that the JWT contains a particular scope in order to execute a particular endpoint. This is our sample implementation (some code is omitted for brevity):
```javascript lines theme={null}
// set dependencies - some code omitted
const jwtAuthz = require('express-jwt-authz');
// Create middleware for checking the JWT
// Enable the use of request body parsing middleware
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true
}));
// Batch upload endpoint
app.post('/timesheets/upload', checkJwt, jwtAuthz(['batch:upload']), function(req, res){
var timesheet = req.body;
// Save the timesheet entry to the database...
//send the response
res.status(201).send(timesheet);
});
// launch the API Server at localhost:8080 - code omitted
```
If we invoke our API with a token that does not include this scope we should get the error message Forbidden with the HTTP status code `403`. You can test this by removing this scope from your API.
That's it! You are done!
# Server Apps + API: Python Implementation for the Cron Job
Source: https://auth0.com/docs/get-started/architecture-scenarios/server-application-api/cron-implementation-python
The Python implementation of the server cron job for the Server Client + API architecture scenario
As part of the [Server + API Architecture Scenario](/docs/get-started/architecture-scenarios/server-application-api), we will explain how to implement the server process in Python. Please refer to the [Server + API Architecture Scenario](/docs/get-started/architecture-scenarios/server-application-api) document for information on the implemented solution.
Full source code for the Python implementation of the server process can be found in [this GitHub repository](https://github.com/auth0-samples/auth0-pnp-exampleco-timesheets/tree/master/timesheets-cron/python).
## Get an access token
In order to make the HTTP request to the Auth0 `/oauth/token` API endpoint we will use the libraries `json`, `urllib` and `urllib2`.
This is our sample implementation:
To test this modify your code to print the `access_token` variable and run the process using `python cron.py`.
## Invoke the API
The steps we follow in our implementation are:
* Build a JSON object containing timesheet data and assign it to a `timesheet` variable.
* Add the API URL and the `timesheet` variable contents to the request body using `urllib2.Request`.
* Add the `Authorization` header to the request.
* Set the `Content-Type` header to `application/json`.
* Invoke the API using `urllib2.urlopen` and add some error handling. Retrieve the response using `json.loads` and print it in the console.
This is our sample implementation (some code is omitted for brevity):
```python lines expandable theme={null}
def main():
# import libraries - code omitted
# Configuration Values - code omitted
# Get an Access Token from Auth0 - code omitted
#Post new timesheet to API
timesheet = {'user_id': '007',
'date': '2017-05-10T17:40:20.095Z',
'project': 'StoreZero',
'hours': 5}
req = urllib2.Request(api_url, data = json.dumps(timesheet))
req.add_header('Authorization', 'Bearer ' + access_token)
req.add_header('Content-Type', 'application/json')
try:
response = urllib2.urlopen(req)
res = json.loads(response.read())
print 'Created timesheet ' + str(res['id']) + ' for employee ' + str(res['user_id'])
except urllib2.HTTPError, e:
print 'HTTPError = ' + str(e.code) + ' ' + str(e.reason)
except urllib2.URLError, e:
print 'URLError = ' + str(e.reason)
except httplib.HTTPException, e:
print 'HTTPException'
except Exception, e:
print 'Generic Exception' + str(e)
# Standard boilerplate to call the main() function - code omitted
```
To test this make sure your API is running and run the process using `python cron.py`.
That's it! You are done!
# Solution Overview (Server Apps + API)
Source: https://auth0.com/docs/get-started/architecture-scenarios/server-application-api/part-1
Solutions Overview for the Server + API architecture scenario
In order to ensure that only authorized users and applications are allowed access to the Timesheets API, ExampleCo has decided to make use of the [OAuth 2.0 authorization framework](https://tools.ietf.org/html/rfc6749). The framework provides the flexibility the company wants since the different grants can allow them to easily authorize the various types of applications which need to communicate with the Timesheets API.
## OAuth 2.0
By using the OAuth 2.0 authorization framework, ExampleCo’s Regular Web application and the third-party application for external contractors can have limited access to the Timesheets API. Using Auth0, ExampleCo can easily support different [grant types](/docs/get-started/authentication-and-authorization-flow/which-oauth-2-0-flow-should-i-use) or authentication flows without worrying about the OAuth 2.0/OpenID Connect (OIDC) specification, or the many other technical aspects of API authorization.
In any OAuth 2.0 flow we can identify the following roles:
* **Resource Owner**: the entity that can grant access to a protected resource. Typically this is the end-user.
* **Resource Server**: the server hosting the protected resources. This is the API you want to access.
* **Client**: an application requesting access to a protected resource on behalf of the Resource Owner.
* **Authorization Server**: the server that authenticates the Resource Owner, and issues Access Tokens after getting proper authorization. In this case, Auth0's Authentication API.
[Grants types (or flows)](/docs/get-started/authentication-and-authorization-flow/which-oauth-2-0-flow-should-i-use) determine how these participants interact to grant to the applications limited access to the APIs you are building. As a result, the app will obtain an access token that can be used to call the API on behalf of the user.
### Client Credentials Grant
OAuth 2 provides several grant types for different use cases. In this particular use case where a cron job will be uploading timesheets via an API, there is no interactive user (or resource owner) to grant permissions to the cron job to access the API.
The cron job is also not making the API calls on behalf of any user. Instead the application (the cron job) uses machine-to-machine authorization makes calls to the Resource Server (the API) on its own behalf.
For situations like this where there is no user interaction involved, the [Client Credentials Grant](/docs/get-started/authentication-and-authorization-flow/client-credentials-flow) is ideal. With the Client Credentials Grant (defined in [RFC 6749, section 4.4](https://tools.ietf.org/html/rfc6749#section-4.4)), an application can directly request an access token from the Authorization Server by using its client credentials (a Client ID and a Client Secret). Instead of identifying a Resource Owner, this token will represent the application itself.
1. The application authenticates with the Authorization Server using its Client ID and Client Secret.
2. The Authorization Server validates this information and returns an access token.
3. The application can use the access token to call the Resource Server on behalf of itself.
## API Authentication and Authorization
An API is a way to expose functionality of your application to other applications. Other applications can make a request to an API endpoint and receive a response. Similarly, the external application ExampleCo’s contractors use can communicate with the Timesheet API as well as the Regular Web Application ExampleCo built for internal employees.
Since the Timesheets API handles sensitive information (such as PII and financial information), ExampleCo needs to ensure only authorized users and applications can call its' endpoints.
### Access tokens and scopes
APIs can be secured or unsecured. When an application wants to access protected endpoints on an API, it needs to provide an access token (also referred to as `access_token`) as proof that it has the required permissions.
An access token is an opaque string representing an authorization issued to the application and is obtained by authenticating the user with an Authorization Server. The user can then, in turn, authorize the application to access the API on their behalf. To learn more, read [Access Tokens](/docs/secure/tokens/access-tokens).
An API like the Timesheets API can enforce fine-grained control over who can access the various endpoints exposed by the API. These permissions are expressed as scopes.
When ExampleCo’s Regular Web Application or the third-party application authenticates with Auth0 to get an access token, the authentication request includes the list of requested scopes the application requires. If those scopes are allowed, then the access token will contain a list of authorized scopes granted to the application.
The Regular Web App or third-party application includes the access token from the Authorization Server when making requests to the Timesheets API, and the Timesheets API inspects the scope claim to ensure that the required permissions were granted in order to call the particular endpoint.
For example, the timesheet API may accept four different levels of authorization: reading timesheets (scope `read:timesheets`), creating timesheets (scope `create:timesheets`), deleting timesheets (scope `delete:timesheets`) and approving timesheets (scope `approve:timesheets`).
For more information on scopes refer to [Scopes](/docs/get-started/apis/scopes).
When the Regular Web App sends a request to the Timesheets API to create a new timesheet entry, the access token must contain the `create:timesheets` scope or the request will be denied. Similarly, to delete existing timesheets, the access token must contain the `delete:timesheets` scope.
To learn more, read [Scopes](/docs/get-started/apis/scopes).
# Auth0 Configuration (Server Apps + API)
Source: https://auth0.com/docs/get-started/architecture-scenarios/server-application-api/part-2
Auth0 Configuration for the Server + API architecture scenario
In this section, we will review ExampleCo's configurations using the [Auth0 Dashboard](https://manage.auth0.com/#).
## Configure the API
To protect an API, you must register an API using the Auth0 Dashboard. Follow instructions on [Register APIs](/docs/get-started/auth0-overview/set-up-apis) to configure the Timesheets API.
### JSON Web Token Profile
OAuth 2.0 defines the type of profiles, or dialects, for an access token. Auth0 supports two different profiles:
* Auth0 token profile
* RFC 9068 profile
The default is the Auth0 profile. The main difference between these two profiles is the difference in claim names. The Auth0 profile uses `azp` rather than `client_id`. You can learn more about the differences by reading [Access Token Profiles](/docs/secure/tokens/access-tokens/access-token-profiles).
### Signing Algorithms
When you create an API, you must select the algorithm with which your tokens will be signed. The signature is used to verify that the sender of the JWT is who it says it is and to ensure that the message hasn't been changed along the way.
The signature is part of a JWT. If you are unfamiliar with JWT structure, please see [JSON Web Token Structure](/docs/secure/tokens/json-web-tokens/json-web-token-structure).
To create the signature, you must take the encoded header, the encoded payload, a secret, the algorithm specified in the header, and sign that. That algorithm, which is part of the JWT header, is the one you select for your API: `HS256,` `RS256,` or `PS256`.
The most secure practice, and our recommendation, is to use **RS256**. Some of the reasons are:
* With RS256, you are sure that only the holder of the private key (Auth0) can sign tokens, while anyone can check if the token is valid using the public key.
* Under HS256, if the private key is compromised you would have to re-deploy the API with the new secret. With RS256, you can request a token that is valid for multiple audiences.
* With RS256, you can implement key rotation without having to re-deploy the API with the new secret.
## Configure the Scopes
In the settings for your API, you will need to configure the Scopes that applications can request during authorization. Navigate to the Permissions tab.
In this section, you can add all four of the scopes discussed before: `batch:upload`, `read:timesheets`, `create:timesheets`, `delete:timesheets`, and `approve:timesheets`. Also add an additional scope: `batch:upload`.
For the purpose of this document, we will only be concerned with the `batch:upload` scope because that is all that is required by the cron job. However, for the sake of completeness, we are adding the necessary scopes which will be required by future applications.
## Create the Application
When creating an API in the Auth0 Dashboard, a test application for the API will automatically be generated. In the Auth0 Dashboard, navigate to the [Application Section](https://manage.auth0.com/#/applications), and you will see the test application for the Timesheets API.
Go to the settings for the application by selecting the menu option at the end. Rename the application to `Timesheets Import Job`.
For the cron job, you will need a Machine-to-Machine Application. The test application that was generated when the API was created was automatically configured as a Machine-to-Machine Application.
## Configure Application's access to the API
Finally, you must allow the application access to the Timesheets API. Go back to the configuration of the API, and select the Machine to Machine Application tab.
You will see the **Timesheets Import Job** application listed, and it should have access to API as can be seen from the switch to the right of the application name which indicates a value of `Authorized`. If it does not indicate that the application is authorized, simply toggle the value of the switch from `Unauthorized` to `Authorized`.
You will also need to specify which scopes will be included in access tokens that are issued to the application when the application authorizes with Auth0.
Expand the settings for the application by clicking on the down arrow to the far right, and you will see the list of available scopes. The cron job will only require the `batch:upload` scope as it will simply create new timesheets based on the timesheet entries in the external system.
Once you have selected the `batch:upload` scope, save the settings by clicking the **Update** button.
Now that we have designed our solution and discussed the configurations needed on Auth0's side, we can proceed with the implementation.
# Application Implementation (Server Apps + API)
Source: https://auth0.com/docs/get-started/architecture-scenarios/server-application-api/part-3
Application Implementation for the Server + API architecture scenario
In this section of the tutorial, we will take an in-depth look into our API and its associated Machine-to-Machine Application. To start at the beginning, read [Server Applications with API](/docs/get-started/architecture-scenarios/server-application-api).
For simplicity, we will keep our implementation solely focused on authentication and authorization. As you will see in the samples, the input timesheet entry will be hard-coded, and the API will not persist the timesheet entry. Instead, it will simply echo back some of the info.
## Define the API endpoints
An **API endpoint** is a static URI that represents a resource (collection of data).
For example, a restaurant API might have endpoints such as `/orders` and `/customers`. An application that connects to this API can perform CRUD (create, read, update, delete) operations by calling an API endpoint with the associated HTTP method (`POST`, `GET`, `PUT`, `PATCH`, or `DELETE`).
For ExampleCo's Timesheets API, you will need to configure an endpoint to create timesheet entries.
| HTTP method | API endpoint | Description |
| - | - | - |
| `POST` | `/timesheets/upload` | Creates a new timesheet entry |
```json lines theme={null}
{
'user_id': '007',
'date': '2017-05-10T17:40:20.095Z',
'project': 'StoreZero',
'hours': 5
}
```
If the API processes the request successfully, it sends a response with an `HTTP 201 Created` status code and the body containing a JSON object with a message property that describes the newly-created timesheet:
```json lines theme={null}
{
"message": "Created timesheet 14 for employee 007."
}
```
See the implementation in [Node.js](/docs/get-started/architecture-scenarios/server-application-api/api-implementation-nodejs#1-define-the-api-endpoint).
### Secure the API endpoints
To secure your API endpoint(s), you need to implement a middleware function within your API application to handle tokens. This function checks if a token was included with the API request, validates the token, and then confirms if the scope(s) required to perform the requested action are present.
If all criteria are satisfied, the API application responds with the message mentioned previously. If there are any issues with the provided access token (or it’s not provided at all), the API application sends a response with the `HTTP 401 Unauthorized` status code.
**See the implementation in** [**Node.js**](/docs/get-started/architecture-scenarios/server-application-api/api-implementation-nodejs#2-secure-the-api-endpoint)**.**
#### Get an access token
To get an access token without using our application sample implementation, call the Auth0 Authentication API's [Get Token](https://auth0.com/docs/api/authentication#get-token54) endpoint with the following payload:
```json lines theme={null}
{
audience: "{yourApiIdentifier}",
grant_type: "client_credentials",
client_id: "${account.client_id}",
client_secret: "${account.client_secret}"
}
```
## Check the application permissions
Now we have secured our API's endpoint with an access token, but we still haven't ensured that the process calling the API has the rights to post a new timesheet entry.
As discussed earlier, each access token may include a list of the permissions that have been granted to the application. These permissions are defined using the `scope` request parameter. To learn how to configure this, see the [Configure the Scopes](/docs/get-started/architecture-scenarios/server-application-api/part-3#configure-the-scopes) paragraph.
For our endpoint, we will require the scope `batch:upload`.
**See the implementation in** [**Node.js**](/docs/get-started/architecture-scenarios/server-application-api/api-implementation-nodejs#3-check-the-client-permissions)**.**
### Implement the Machine-to-Machine Application
In this section, we will see how we can implement a Machine-to-Machine Application for our scenario.
### Get an access token
We will start by invoking the Auth0 `/oauth/token` API endpoint to get an access token.
To do so, we will need the following configuration values you can find in your [application settings](https://manage.auth0.com/#/applications):
* **Domain**: Auth0 Domain and also your tenant identifier. This value will be a part of the API URL: `https://{yourTenant}/oauth/token`.
* **Audience**: API identifier.
* **Client ID**: Auth0 Application's Client ID.
* **Client Secret**: Auth0 application's Client Secret.
Our implementation should perform a `POST` operation to the `https://{yourDomain}/oauth/token` endpoint with a payload in the following format:
```json lines theme={null}
{
"audience": "{yourApiIdentifier}",
"grant_type": "client_credentials",
"client_id": "${account.client_id}",
"client_secret": "${account.client_secret}"
}
```
To learn more, see [Call Your API Using the Client Credentials Flow](/docs/get-started/authentication-and-authorization-flow/client-credentials-flow/call-your-api-using-the-client-credentials-flow).
**See the implementation in** [**Python**](/docs/get-started/architecture-scenarios/server-application-api/cron-implementation-python#get-an-access-token).
## Invoke the API
Now that we have an access token that includes the valid scopes, we can invoke our API.
To do so, we will:
* Build a hard-coded timesheet entry in JSON format.
* Add the access token as an `Authorization` header to our request.
* Make the HTTP `POST` request.
* Parse the response, and print it in the terminal (optional).
**See the implementation in** [**Python**](/docs/get-started/architecture-scenarios/server-application-api/cron-implementation-python#invoke-the-api).
# Conclusion (Server Apps + API)
Source: https://auth0.com/docs/get-started/architecture-scenarios/server-application-api/part-4
Conclusion for the Server + API architecture scenario
In the [Server + API Architecture Scenario](/docs/get-started/architecture-scenarios/server-application-api), we covered a simple, machine-to-machine scenario: an API, used to import timesheet entries in ExampleCo's systems, and a cron job, used by external contractors to send in their timesheets using this API.
We learned about the Client Credentials Grant and access tokens, how to configure an API in Auth0, how to configure a Machine-to-Machine Application to communicate securely with this API, how to define and secure our API endpoints, how to use the provided libraries to validate the access token and how to retrieve a new one from Auth0.
We used Node.js for the API implementation and Python for the non-interactive server process. We hope this examples empowers you to build your own implementation with your preferred technologies.
# Single-Page Applications (SPA) with API
Source: https://auth0.com/docs/get-started/architecture-scenarios/spa-api
Explains the architecture scenario where a single-page application (SPA) talks to an API using OpenID Connect (OIDC), and the OAuth 2.0 Implicit Grant Flow, to authenticate users with Auth0.
In this scenario, we will build a timesheet API for a fictitious company named ExampleCo. The API will allow adding timesheet entries for an employee or a contractor.
We will also be building a single-page application (SPA) which will be used to log timesheet entries and send them to the centralized timesheet database using the API.
### TL;DR
* Auth0 provides API Authentication and Authorization as a means to secure access to API endpoints (see [API Authentication and Authorization](/docs/get-started/architecture-scenarios/spa-api/part-1#api-authentication-and-authorization))
* For authorizing a user of a SPA, Auth0 supports the Implicit Grant (see [Implicit Grant](/docs/get-started/architecture-scenarios/spa-api/part-1#implicit-grant))
* Both the SPA and the API must be configured in the Auth0 Dashboard (see [Auth0 Configuration](/docs/get-started/architecture-scenarios/spa-api/part-2#auth0-configuration))
* User Permissions can be enforced using the Authorization Extension (see [Configure the Authorization Extension](/docs/get-started/architecture-scenarios/spa-api/part-2#configure-the-authorization-extension))
* The API will be secured by ensuring that a valid Access Token is passed in the HTTP Authorization header when calls are made to the API (see [Implement the API](/docs/get-started/architecture-scenarios/spa-api/part-3#implement-the-api))
* The Auth0.js library can be used to authorize the user of the SPA and obtain a valid Access Token which can be used to call the API (see [Authorize the User](/docs/get-started/architecture-scenarios/spa-api/part-3#authorize-the-user))
* The SPA can pass the Access Token in the HTTP Authorization header when making calls to the API (see [Call the API](/docs/get-started/architecture-scenarios/spa-api/part-3#call-the-api))
* The SPA can display UI elements conditionally based on scopes granted to user (see [Display UI Elements Conditionally Based on Scope](/docs/get-started/architecture-scenarios/spa-api/part-3#display-ui-elements-conditionally-based-on-scope))
## The Premise
ExampleCo is a consulting startup company. Currently, they have approximately 100 employees and they also outsource several activities to external contractors. All employees and external contractors are required to fill in their timesheets every week.
The company has built a timesheets application, a scenario we covered in [Single Sign-On for Regular Web Apps](/docs/get-started/architecture-scenarios/sso-for-regular-web-apps). The internal employees use this web app to fill in their timesheets but the company wants to replace it with a SPA. The app will be used to log timesheet entries and send the data to the centralized timesheet database using the API. The app will also allow managers to approve timesheet entries.
## Goals & Requirements
ExampleCo wants to build a flexible solution. At the moment only a SPA is required to capture timesheet entries but in the future, the company plans on launching more applications, like a mobile app to accommodate their sales teams. Hence the company has decided to develop a single Timesheets API which will be used to log time not only by this server process but by all future applications as well. They want to put in place a security architecture that is flexible enough to accommodate this. ExampleCo wants to ensure that a large part of the code and business logic for the application can be shared across the different applications.
It is required that only authorized users and applications are allowed access to the Timesheets API.
Two kinds of users will use this SPA: employees and managers. The employees should be able to read, create and delete their own timesheet entries, while the managers should be able to approve timesheets as well.
## Learn more
* [Solution Overview (SPAs + API)](/docs/get-started/architecture-scenarios/spa-api/part-1)
* [Auth0 Configuration (SPAs + API)](/docs/get-started/architecture-scenarios/spa-api/part-2)
* [API and SPA Configuration (SPAs + API)](/docs/get-started/architecture-scenarios/spa-api/part-3)
* [Node.js API Implementation (SPAs + API)](/docs/get-started/architecture-scenarios/spa-api/api-implementation-nodejs)
* [SPA Angular 2 Implementation (SPAs + API)](/docs/get-started/architecture-scenarios/spa-api/spa-implementation-angular2)
* [Conclusion (SPAs + API)](/docs/get-started/architecture-scenarios/spa-api/part-4)
# Solution Overview (SPAs + API)
Source: https://auth0.com/docs/get-started/architecture-scenarios/spa-api/part-1
Solution overview for the SPA + API architecture scenario
In order to ensure that only authorized users and applications are allowed access to the Timesheets API, ExampleCo has decided to make use of the [OAuth 2.0 authorization framework](https://tools.ietf.org/html/rfc6749). The framework provides the flexibility the company wants since the different grants can allow them to easily authorize the various types of applications which need to communicate with the Timesheets API.
## API Authentication and Authorization
An API is a way to expose functionality of your application to other applications. An application can make a request by sending a message to an endpoint on an API and receive information as a response.
An API endpoint can be secured or not. In our case, since the timesheets are sensitive information that affect reviews and payments, it is important to ensure that only authorized users and applications can call the endpoints on our API. When a client application wants to access protected endpoints on an API, it needs to present an Access Token as proof that it has the required permissions for making the call to the endpoint.
An Access Token is obtained by authenticating the user with an Authorization Server and the user can then, in turn, authorize the application to access the API on their behalf.
An Access Token (also referred to as `access_token`) is an opaque string representing an authorization issued to the application. It may denote an identifier used to retrieve the authorization information or may self-contain the authorization information (for example, the user's identity, permissions, and so forth) in a verifiable manner.
It is quite common for Access Tokens to be implemented as [JSON Web Tokens](/docs/secure/tokens/json-web-tokens).
For more information on Auth0 Access Tokens refer to [Access Token](/docs/secure/tokens/access-tokens).
An API can enforce fine-grained control over who can access the various endpoints exposed by the API. These permissions are expressed as scopes.
When a user authorizes a client application, the application can also indicate which permissions it requires. The user is then allowed to review and grant these permissions. These permissions are then included in the Access Token as part of the `scope` claim.
Subsequently, when the client passes along the Access Token when making requests to the API, the API can inspect the `scope` claim to ensure that the required permissions were granted in order to call the particular API endpoint.
Each Access Token may include a list of the permissions that have been granted to the client. When a client authenticates with Auth0, it will specify the list of scopes (or permissions) it is requesting. If those scopes are authorized, then the Access Token will contain a list of authorized scopes.
For example, the timesheet API may accept four different levels of authorization: reading timesheets (scope `read:timesheets`), creating timesheets (scope `create:timesheets`), deleting timesheets (scope `delete:timesheets`) and approving timesheets (scope `approve:timesheets`).
When a client asks the API to create a new timesheet entry, then the Access Token should contain the `create:timesheets` scope. In a similar fashion, in order to delete existing timesheets, the Access Token should contain the `delete:timesheets` scope.
For more information on scopes refer to [Scopes](/docs/get-started/apis/scopes).
By using the OAuth 2.0 authorization framework, you can give your own applications or third-party applications limited access to your APIs on behalf of the application itself. Using Auth0, you can easily support different flows in your own APIs without worrying about the OAuth 2.0/OpenID Connect (OIDC) specification, or the many other technical aspects of API authorization.
In any OAuth 2.0 flow we can identify the following roles:
* **Resource Owner**: the entity that can grant access to a protected resource. Typically this is the end-user.
* **Resource Server**: the server hosting the protected resources. This is the API you want to access.
* **Client**: an application requesting access to a protected resource on behalf of the Resource Owner.
* **Authorization Server**: the server that authenticates the Resource Owner, and issues Access Tokens after getting proper authorization. In this case, Auth0's Authentication API.
[Grants types (or flows)](/docs/get-started/authentication-and-authorization-flow/which-oauth-2-0-flow-should-i-use) determine how these participants interact to grant to the applications limited access to the APIs you are building. As a result, the app will obtain an access token that can be used to call the API on behalf of the user.
## Implicit Grant
OAuth 2.0 provides several **grant types** for different use cases. In this particular use case, we want to access the API from a [client-side app](/docs/quickstart/spa).
The SPA will use the [Implicit Flow (Implicit Grant)](/docs/get-started/authentication-and-authorization-flow/implicit-flow-with-form-post) to do so.
The Implicit Grant (defined in [RFC 6749, section 4.1](https://tools.ietf.org/html/rfc6749#section-4.2)) is similar to the grant used in the [Authorization Code Flow](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow), but the main difference is that the application receives an Access Token directly, without the need for an `authorization_code`. This happens because the application, which is typically a JavaScript app running within a browser, is less trusted than a web app running on the server, hence cannot be trusted with the `client_secret` (which is required in the Authorization Code Grant).
Once the user authenticates, the application receives the ID Token and Access Token in the hash fragment of the URI. The application can now use the ID Token to obtain information about the user, and Access Token to call the API on behalf of the user.
1. The app initiates the flow and redirects the browser to Auth0 (specifically to the [/authorize endpoint](https://auth0.com/docs/api/authentication#implicit-grant)), so the user can authenticate.
2. Auth0 authenticates the user. The first time the user goes through this flow, and if the application is a third party application, a consent page will be shown where the permissions, that will be given to the Client, are listed (for example, post messages, list contacts, and so forth).
3. Auth0 redirects the user to the app with an Access Token (and optionally an ID Token) in the hash fragment of the URI. The app can now extract the tokens from the hash fragment.
4. The app can use the Access Token to call the API on behalf of the user.
## Authorization Extension
The [Auth0 Authorization Extension](/docs/customize/extensions/authorization-extension) allows you to configure Roles, Groups, and Permissions, and assign them to Users.
* The Permissions are actions that someone can do. For ExampleCo's business needs, we will configure four Permissions: read, create, delete and approve timesheets.
* The Roles are collections of Permissions. ExampleCo's timesheets app will be used by two kinds of users (employees and managers), with different permissions each, so we will configure two Roles: employee and manager.
Since this covers our business case we will not create any Groups.
The Authorization Extension will create a [Rule](/docs/customize/rules) which will read the Roles, Groups, and Permissions assigned to a user and add this information to the [User profile](/docs/customize/rules#rule-syntax) during the authentication flow. We can use this information to ensure that the Access Token issued to a user only contains scopes which are allowed. We can later on proceed to customize our app, like disabling the Approve Timesheets functionality if the user does not have the required permission to do so.
# Regular Web Applications with Single Sign-On
Source: https://auth0.com/docs/get-started/architecture-scenarios/sso-for-regular-web-apps
Regular web app scenario which needs to authenticate users using OpenID Connect (OIDC) single sign-on.
In this scenario, we will build a web application for a fictitious company named ExampleCo. The app is meant to be used by ExampleCo's employees and contractors. Employees will use their existing corporate directory (Active Directory), while contractors will be managed in a separate user store.
### TL;DR
* Auth0 supports open standards such as OAuth 2.0 and OpenID Connect (OIDC) for authentication and authorization (see [Which protocol to use](/docs/get-started/architecture-scenarios/sso-for-regular-web-apps/part-1#which-protocol-to-use))
* OIDC supports several different authorization flows - the most appropriate one for Web Applications being the Authorization Code Flow (see [Authentication Flow](/docs/get-started/architecture-scenarios/sso-for-regular-web-apps/part-1#authentication-flow))
* Your application will be configured in Auth0 as an application (see [Application](/docs/get-started/architecture-scenarios/sso-for-regular-web-apps/part-2#application))
* Identity Providers will be configured in Auth0 as a Connection (see [Connections](/docs/get-started/architecture-scenarios/sso-for-regular-web-apps/part-2#connections))
* Auth0 provides a Lock widget, which allow users to log in to the application (see [User Login](/docs/get-started/architecture-scenarios/sso-for-regular-web-apps/part-3#user-login))
* The web application needs to manage session state to keep track of the fact that the user is logged in. Along with this, Auth0 and the Identity Provider is also managing session information. (see [Session Management](/docs/get-started/architecture-scenarios/sso-for-regular-web-apps/part-3#session-management))
* Conversely, logging a user out also involves three layers of session management (see [User Logout](/docs/get-started/architecture-scenarios/sso-for-regular-web-apps/part-3#user-logout))
* Access Control can be managed with the Auth0 Authorization Extension (see [Access Control](/docs/get-started/architecture-scenarios/sso-for-regular-web-apps/part-3#access-control))
By Regular Web App, we mean an app that uses primarily server side, page `GET`, `POST`, and cookies for maintaining state. This is contrast with a Web SPA (Single-Page App), that heavily relies on client side JavaScript code calling an API.
## The Premise
ExampleCo is a consulting startup company. Currently they have approximately 100 employees and they also outsource several activities to external contractors. Most of the employees work from the company's main office, but there are some teams that work remotely. Additionally, some employees frequently travel to customer locations and work from mobile devices.
All employees and external contractors are required to fill in their timesheets every week using spreadsheets. The current system is inefficient and the company decided that they need to move to a better and more automated solution.
The company evaluated several of the available timesheets application and concluded that it would be more cost-effective to build their own in-house solution, since they are looking for a very simple application at the moment. The app will be built using ASP.NET Core, since their developers are already using this technology and they can have the app ready in a week or so.
### Goals & Requirements
ExampleCo wants to launch the new solution quickly so they chose to start simple and build into it as they gather feedback from their employees.
The application should be available to logged in users only. Each user will have a role, and based on this role, they should be able to perform certain actions and view specific data.
### Authentication vs Authorization
ExampleCo wants to **authenticate** and **authorize** each user. Authentication has to do with identity: verifying that the user is indeed who they claim to be. Authorization is about deciding which resources a user should have access to, and what they should be allowed to do with those resources.
ExampleCo's timesheets app needs to support two roles: User and Admin:
* Someone with the User role can add timesheet entries, by specifying the date, the application and the hours worked. The Admin role also has this same right.
* Those with the User role should have access only to their own timesheets entries.
* Someone with the Admin role can additionally:
* Approve or reject timesheet entries of other users.
* Edit the application drop-down list of values (add, edit, delete).
Each user will be required to fill in their timesheets by the end of the week. They can either choose to register daily their timesheets or add the entries for the whole week together. The timesheets will have to be reviewed and approved by an Admin. The rejected entries will have to be updated by each employee and re-submitted for approval.
The company uses Active Directory for all employees and employees will sign into the Timesheet application using their Active Directory credentials. The external contractors can sign in with a username and password. Contractors are not on ExampleCo's corporate directory.
ExampleCo wants to minimize user login burden, but wants to maintain a level of security depending on the operation: submitting timesheet entries is lower risk than approving them. However the approved timesheets are used for customer charging so security is definitely a requirement. The authentication strategy should be flexible so it can adapt as the company grows. For example, they should easily be able to add additional authentication requirements, like multi-factor authentication, for Admins.
The solution should be available both to the employees with a physical presence in the company office, as well as to those working remotely, without the overhead of a VPN connection, hence the app should be deployed on a cloud provider like Heroku or Microsoft Azure.
## Learn more
* [Solution Overview (Web Apps + SSO)](/docs/get-started/architecture-scenarios/sso-for-regular-web-apps/part-1)
* [Auth0 Configuration (Web Apps + SSO)](/docs/get-started/architecture-scenarios/sso-for-regular-web-apps/part-2)
* [Application Implementation (Web Apps + SSO)](/docs/get-started/architecture-scenarios/sso-for-regular-web-apps/part-3)
* [ASP.NET Core Implementation (Web Apps + SSO)](/docs/get-started/architecture-scenarios/sso-for-regular-web-apps/implementation-aspnetcore)
* [Conclusion (Web Apps + SSO)](/docs/get-started/architecture-scenarios/sso-for-regular-web-apps/part-4)
# ASP.NET Core Implementation (Web Apps + SSO)
Source: https://auth0.com/docs/get-started/architecture-scenarios/sso-for-regular-web-apps/implementation-aspnetcore
The ASP.NET Core implementation for the Single Sign-on (SSO) for Regular Web Apps architecture scenario
Full source code for the ASP.NET Core implementation can be found in [this GitHub repository](https://github.com/auth0-samples/auth0-pnp-webapp-oidc).
## Configure the Cookie and OIDC Middleware
For the purposes this guide we will be using a simple hosted login. You can use the standard cookie and OIDC middleware which is available with ASP.NET Core, so ensure that you install the NuGet packages.
```bash lines theme={null}
Install-Package Microsoft.AspNetCore.Authentication.Cookies
Install-Package Microsoft.AspNetCore.Authentication.OpenIdConnect
```
Then configure the cookie and OIDC middleware inside your application's middleware pipeline.
As you can see in the code above, we have configured two different types of authentication middleware.
The first is the cookie middleware which was registered with the call to `UseCookieAuthentication`. The second is the OIDC middleware which is done with the call to `UseOpenIdConnectAuthentication`.
Once the user has signed in to Auth0 using the OIDC middleware, their information will automatically be stored inside a session cookie. All you need to do is to configure the middleware as above and it will take care of managing the user session.
The OpenID Connect (OIDC) middleware will also extract all the claims from the ID Token, which is sent from Auth0 once the user has authenticated, and add them as claims on the `ClaimsIdentity`.
## Implement the Logout
You can control both the application session and the Auth0 session using the `SignOutAsync` method of the `AuthenticationManager` class, and passing along the authentication scheme from which you want to sign out.
As an example to sign out of the cookie middleware, and thereby clearing the authentication cookie for your application, you can make the following call:
```csharp wrap lines theme={null}
await HttpContext.Authentication.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
```
Similarly you can log the user out from Auth0 by making a call to the `SignOutAsync` method and passing along `Auth0` as the authentication scheme to sign out of.
```csharp lines theme={null}
await HttpContext.Authentication.SignOutAsync("Auth0");
```
For the above to work you will however also need to add extra configuration when registering the OIDC middleware by handling the `OnRedirectToIdentityProviderForSignOut` event. Inside the event you will need to redirect to the [Auth0 logout endpoint](https://auth0.com/docs/api/authentication/reference#logout) which will clear the Auth0 cookie.
```csharp lines theme={null}
app.UseOpenIdConnectAuthentication(new OpenIdConnectOptions("Auth0")
{
// Some code omitted for brevity
Events = new OpenIdConnectEvents
{
OnRedirectToIdentityProviderForSignOut = context =>
{
context.Response.Redirect($"https://{auth0Settings.Value.Domain}/v2/logout?client_id={auth0Settings.Value.ClientId}&returnTo={context.Request.Scheme}://{context.Request.Host}/");
context.HandleResponse();
return Task.FromResult(0);
}
}
});
```
You will also need to ensure that you add your application's URL to the **Allowed Logout URLs** for your application inside the Auth0 dashboard. For more information refer to [Logout](/docs/authenticate/login/logout).
## Implement Admin permissions
The easiest way to integrate the groups into an ASP.NET Core application is to use the built-in [Role-based Authorization](https://docs.asp.net/en/latest/security/authorization/roles.html) available in ASP.NET Core. In order to achieve this we will need to add a Claim of type
```http lines theme={null}
http://schemas.microsoft.com/ws/2008/06/identity/claims/role
```
for each of the groups a user is assigned to.
Once the claims has been added we can easily ensure that a specific action is available only to `Admin` users by decorating the claim with the `[Authorize(Roles = "Admin")]` attribute. You can also check whether a user is in a specific role from code by making a call to `User.IsInRole("Admin")` from inside your controller.
The ASP.NET OIDC middleware will automatically add all claims returned in the JWT as claims to the `ClaimsIdentity`. We would therefore need to extract the information from the `authorization` claim, deserialize the JSON body of the claim, and for each of the groups add a `http://schemas.microsoft.com/ws/2008/06/identity/claims/role` claim to the `ClaimsIdentity`.
```csharp lines expandable theme={null}
app.UseOpenIdConnectAuthentication(new OpenIdConnectOptions("Auth0")
{
// Some configuration omitted for brevity
Events = new OpenIdConnectEvents
{
OnTicketReceived = context =>
{
var options = context.Options as OpenIdConnectOptions;
// Get the ClaimsIdentity
var identity = context.Principal.Identity as ClaimsIdentity;
if (identity != null)
{
// Add the groups as roles
var authzClaim = context.Principal.FindFirst(c => c.Type == "authorization");
if (authzClaim != null)
{
var authorization = JsonConvert.DeserializeObject(authzClaim.Value);
if (authorization != null)
{
foreach (var group in authorization.Groups)
{
identity.AddClaim(new Claim(ClaimTypes.Role, group, ClaimValueTypes.String, options.Authority));
}
}
}
}
return Task.FromResult(0);
}
}
});
```
And subsequently we can add an action which allows Administrators to approve timesheets:
```csharp lines theme={null}
[Authorize(Roles = "Admin")]
public IActionResult TimesheetApproval()
{
return View();
}
```
# Solution Overview (Web Apps + SSO)
Source: https://auth0.com/docs/get-started/architecture-scenarios/sso-for-regular-web-apps/part-1
Regular web app scenario solution overview.
In this section, we'll cover the solution we're implementing, including details on identity management, protocols to use, and the authentication flow required.
## Identity Management
ExampleCo decided to use Auth0 as their Identity as a Service (IDaaS) provider. The reasoning behind this decision was that the company did not want to commit resources on training, implementation and maintenance of identity and access management. Furthermore, the company plans on building into this solution in the future, possibly adding a mobile native app and an API to push approved timesheets to their internal systems. Auth0 provides the flexibility to incorporate such changes in their architecture with minimum effort.
Identity-as-Service ("IDaaS") is a cloud-based service for identity and access management. The offered services often include Single Sign-on (SSO), federated identity, password management, and more.
## Which protocol to use
The next decision has to do with which protocol to use, OAuth 2.0 with OpenID Connect (OIDC) or SAML.
Auth0 implements proven, common and popular identity protocols, both for consumer oriented web products (OAuth 2.0, OAuth 1.0, OpenID) and for enterprise deployments (SAML, WS-Federation, LDAP). You have complete freedom to use the one that best meets your business needs.
**OpenID Connect** is an authentication protocol, based on the OAuth 2.0 family of specifications. It uses simple JSON identity tokens (JWT) delivered via the OAuth 2.0 protocol.
### OAuth vs OpenID Connect (OIDC)
OAuth 2.0 and OpenID Connect (OIDC) are often mistaken for the same thing, but this is not exact.
**OAuth 2.0** is a protocol that lets you authorize one website (the consumer or application) to access your data from another website (the resource server or provider). For example, you want to authorize a website to access some files from your Dropbox account. The website will redirect you to Dropbox which will ask you whether it should provide access to your files. If you agree the website will be authorized to access your files from Dropbox. At the core, OAuth 2.0 is about resource access and sharing.
**OpenID Connect**, on the other hand, is a simple identity layer built on top of the OAuth 2.0 protocol. It gives you one login for multiple sites. Each time you need to log in to a website using OIDC, you are redirected to your OpenID site where you login, and then taken back to the website. At the core, OIDC is concerned with user authentication.
**SAML** is an XML-based protocol, that provides both authentication and authorization between trusted parties.
Compared to SAML, OpenID Connect is lighter weight and simpler to deal with. SAML is proven, powerful and flexible, but for the requirements of this app, that flexibility and power is not required. Identity federation (one of the most compelling reasons for adopting SAML) is not required here either, And if it ever became a requirement, it can be easily handled by Auth0, in the same way it deals with AD (that uses LDAP).
For these reasons, ExampleCo will use OpenID Connect for their implementation.
## Authentication Flow
OpenID Connect supports more than one flow for authentication. Since our scenario involves a regular web app we will use the Authorization Code Flow.
The flow goes as follows:
1. The web app (called the Client in OIDC terms) initiates the authentication request by redirecting the user-agent (browser) to Auth0 (the Authorization Server in OIDC terms).
2. Auth0 authenticates the user (via the user-agent). The first time the user goes through this flow a consent page will be shown where the permissions that will be given to the Application are listed (for example, post messages, list contacts). The user logs in to the service (unless they are already logged in) and authorizes the application access.
3. Assuming the user grants access, Auth0 redirects the user-agent back to the Application, along with an authorization code in the query string.
4. The Application sends the authorization code to Auth0, along with the application credentials (client\_id and client\_secret), and asks for a token.
5. Auth0 authenticates the Application (using the client\_id and client\_secret) and validates the authorization code. If valid, Auth0 responds back with an ID Token.
### Form Post Response Mode
Another option is to use the **OAuth 2.0 Form Post Response Mode** with `response_type=id_token&response_mode=form_post`. Due to the `response_type=id_token` request parameter, the response contains the ID Token directly, instead of the authorization code, while the `response_mode=form_post` encodes the ID Token with the rest of the Authorization Response parameters as HTML form values that are auto-submitted in the User Agent. This way you can have an optimized authentication flow (no need to exchange the code for an ID Token), however you have to make sure that it is supported by the technology you are using to implement your app (ASP .NET Core middleware does support it). For more details refer to the [OAuth 2.0 Form Post Response Mode specification](https://openid.net/specs/oauth-v2-form-post-response-mode-1_0.html).
The **ID Token** (usually referred to as `id_token` in code samples) is a **JSON Web Token (JWT)** that contains identity data. It is consumed by the application and used to get user information like the user's name, email, and so forth, typically used for UI display.
### More on tokens
Tokens are alphanumeric strings used in token-based authentication. They allow users to authenticate with a username and password once and get a token in return which they can use from that point on. They have a limited lifetime duration.
**JSON Web Tokens (JWTs)** are tokens that conform to the [JSON Web Token Standard](https://tools.ietf.org/html/rfc7519) and contain information about an identity in the form of claims. They are self-contained in that it is not necessary for the recipient to call a server to validate the token. JWTs can be signed using a secret (with the **HMAC** algorithm) or a public/private key pair using **RSA**. You can find more information on JWT [here](/docs/secure/tokens/json-web-tokens).
The ID Token, which is a JWT, conforms to an industry standard (IETF [RFC 7519](https://tools.ietf.org/html/rfc7519)) and contains three parts: A header, a body and a signature.
* The header contains the type of token and the hash algorithm used on the contents of the token.
* The body, also called the payload, contains identity claims about a user. There are some claims with registered names, for things like the issuer of the token, the subject of the token (who the claims are about), and the time of issuance. Any number of additional claims with other names can be added, though care must be taken to keep the JWT within the browser size limitations for URLs.
* The signature is used by the recipient of a JWT to validate the integrity of the information conveyed in the JWT.
### How to validate an ID Token
The validation of an ID Token requires several steps:
1. If the ID Token is encrypted, decrypt it using the keys and algorithms that the Application specified.
2. The Issuer Identifier for the OpenID Provider must match the value of the `iss` (issuer) claim.
3. The `aud` (audience) claim should contain the Application's `client_id` value. The ID Token must be rejected if the ID Token does not list the Application as a valid audience, or if it contains additional audiences not trusted by the Application.
4. If the ID Token contains multiple audiences, the Application should verify that an `azp` claim is present.
5. If an `azp` (authorized party) claim is present, the Application should verify that its `client_id` is the claim value.
6. The Application must validate the signature of ID Tokens according to JWS using the algorithm specified in the JWT `alg` header parameter. The Application must use the keys provided by the Issuer.
7. The `alg` value should be the default of `RS256` or the algorithm sent by the Application in the `id_token_signed_response_alg` parameter during registration.
8. If the JWT `alg` header parameter uses a MAC based algorithm such as `HS256`, `HS384`, or `HS512`, the octets of the UTF-8 representation of the `client_secret` corresponding to the `client_id` contained in the `aud` (audience) claim are used as the key to validate the signature. For MAC based algorithms, the behavior is unspecified if the `aud` is multi-valued or if an `azp` value is present that is different than the `aud` value.
9. The current time must be before the time represented by the `exp` claim.
10. The `iat` claim can be used to reject tokens that were issued too far away from the current time, limiting the amount of time that nonces need to be stored to prevent attacks. The acceptable range is Application specific.
11. If a `nonce` value was sent in the Authentication Request, a `nonce` claim must be present and its value checked to verify that it is the same value as the one that was sent in the Authentication Request. The Application should check the `nonce` value for replay attacks. The precise method for detecting replay attacks is Application specific.
12. If the `acr` claim was requested, the Application should check that the asserted claim value is appropriate.
13. If the `auth_time` claim was requested, either through a specific request for this claim or by using the `max_age` parameter, the Application should check the `auth_time` claim value and request re-authentication if it determines too much time has elapsed since the last End-User authentication.
If you store ID Tokens on your server, you must do so securely.
# Auth0 Configuration (Web Apps + SSO)
Source: https://auth0.com/docs/get-started/architecture-scenarios/sso-for-regular-web-apps/part-2
Regular web app scenario configuration for Auth0
In this section, we will review all the configurations we need to apply using the [Auth0 Dashboard](https://manage.auth0.com/#).
## Application
The Auth0 configuration part starts with registering the timesheets app at the Auth0 dashboard as an **application**. An application is making protected resource requests on behalf of the resource owner (end-user).
The term "application" does not imply any particular implementation characteristics. An application can be a web app, a mobile app or an SPA. In the case of ExampleCo it is a ASP.NET Core web app.
The main characteristics of an application in Auth0 are:
* **Name**: The canonical name of the application. This is used to identify the application at the portal, emails, logs, and more.
* **Client ID** (read-only): The unique identifier for the application. This is the ID used in the application when setting up authentication with Auth0. It is an auto-generated alphanumeric string.
* **Client secret** (read-only): A string used to sign and validate tokens which will be used in the different authentication flows. It is auto-generated and it must be kept confidential.
* **Domain**: The domain name assigned to the Auth0 account. The format of the domain is `{account-name}.auth0.com` or `{account-name}.{location}.auth0.com`, for example `ExampleCo.auth0.com`.
* **Callback URL**: The URL where the user is redirected after they authenticate.
### Create an Application
ExampleCo's scenario involves only one application: the timesheets web app. Hence we have to configure one Application at Auth0 side.
To register a database connection, go to the [Dashboard](https://manage.auth0.com/#) and in the side navigation select [Applications](https://manage.auth0.com/#/applications).
Click on the button **+ Create Application**. You will be prompted for the name and the type of the application. We will name our application `Timesheet-App` and select `Regular Web Applications` as the application type.
When you click **Create** you will be navigated to the [Quick Start view](https://manage.auth0.com/#/applications/\{yourClientId}/quickstart). Here you can pick the technology you plan on using to build your app and the relevant how-to quickstart will be displayed.
The other available views are:
* [Settings](https://manage.auth0.com/#/applications/\{yourClientId}/settings)
* [Addons](https://manage.auth0.com/#/applications/\{yourClientId}/addons)
* [Connections](https://manage.auth0.com/#/applications/\{yourClientId}/connections)
### Configure Callback URLs
The **Allowed Callback URLs** field contains the URL(s) where Auth0 will redirect to after the user has authenticated in order for the OpenID Connect (OIDC) to complete the authentication process. You can specify multiple valid URLs by comma-separating them. You can use the star symbol as a wildcard for subdomains, for example `*.google.com`. Make sure to specify the protocol, `http://` or `https://`, otherwise the callback may fail in some cases.
The Callback URL for our sample project is `http://localhost:5000/signin-auth0`. Go ahead and set this value to the **Allowed Callback URLs** field if you plan on using our sample, otherwise add the URL you chose to deploy your application to.
## Connections
The next step is to configure the identity providers that will be used for authentication at the web app. Each identity provides maps to a **connection** in Auth0. Each application needs at least one connection, and each connection can be used for more than one application.
ExampleCo needs to configure two connections: one Active Directory connection for the internal employees, and one Database connection for external parties.
### Supported identity providers
Auth0 supports a vast variety of protocols and identity providers:
* Social: Allow your users to log in using Google, Facebook, LinkedIn, Github, and many more.
* Enterprise: Allow your users to log in using Active Directory, ADFS, LDAP, SAML-P, and many more.
* Database connections: Create your own user store by configuring a new database connection, and authenticate your users using email/username and password. The credentials can be securely stored either in the Auth0 user store, or in your own database.
* Passwordless authentication: Allow your users to login without the need to remember a password and use an authentication channel like SMS or email.
### Create a database connection
To register a database connection, follow the steps below:
1. On the [Dashboard](https://manage.auth0.com/#), navigate to **Authentication > Database**.
2. Select **+ Create DB Connection**. On the prompt, enter a name for the connection and configure additional requirements as needed.
3. Review the prompt for accuracy, then select **Create**.
After you create the database connection, you must enable your applications for the connection. An application must be enabled for the connection in order for users to access that application using the connection. To enable your applications, navigate to the Applications tab of the new connection and enable the toggle for each application that requires use of the connection.
For more information on database connections refer to [Database Identity Providers](/docs/authenticate/database-connections).
### Create an Active Directory / LDAP Connection
Next, configure your Active Directory / LDAP connection. On the [Auth0 Dashboard](https://manage.auth0.com/#), navigate to **Authentication > Enterprise**.
There you need to create the AD / LDAP connection and install the AD Connector. You can find details in these documents:
* [How to connect your Active Directory with Auth0](/docs/authenticate/identity-providers/enterprise-identity-providers/active-directory-ldap)
* [How to install the Active Directory/LDAP Connector](/docs/authenticate/identity-providers/enterprise-identity-providers/active-directory-ldap/ad-ldap-connector)
The AD/LDAP Connector, is a bridge between your Active Directory and the Auth0 Service. This bridge is necessary because AD is typically locked down to your internal network, and Auth0 is a cloud service running on a completely different context. [More information](/docs/authenticate/identity-providers/enterprise-identity-providers/active-directory-ldap/ad-ldap-connector)
Once you have configured the connection and the connector, be sure to enable your application to use this AD / LDAP connection:
### Kerberos support
The AD/LDAP connector supports Kerberos to make it easer for your users to authenticate when they are on a domain-joined machine within the corporate network. To activate Kerberos on an Active Directory you have to simply enable the option in the dashboard. After enabling Kerberos you'll also be able to configure the **IP Ranges**. When users originate from these IP address ranges this information will be exposed in the SSO endpoint which means client-side SDKs like auth0.js and the Lock will be able to detect Kerberos support and allow Integrated Windows Authentication.
[More information](/docs/authenticate/identity-providers/enterprise-identity-providers/active-directory-ldap/ad-ldap-connector/configure-ad-ldap-connector-with-kerberos)
If you enable Kerberos then you need to make some changes to the AD/LDAP's configuration file. For details refer to: [Modify the AD/LDAP Connector Settings](/docs/authenticate/identity-providers/enterprise-identity-providers/active-directory-ldap/ad-ldap-connector/ad-ldap-connector-to-auth0).
Now that we have designed our solution and discussed the configurations needed on Auth0 side, we can proceed with integrating Auth0 with our timesheets web app.
# Application Implementation (Web Apps + SSO)
Source: https://auth0.com/docs/get-started/architecture-scenarios/sso-for-regular-web-apps/part-3
Regular web app scenario application implementation
Let's walk through the implementation of our regular web application. We used ASP .NET Core for the implementation, you can find the code in [this GitHub repository](https://github.com/auth0-samples/auth0-pnp-webapp-oidc).
The sample contains an application which uses Active Directory integration to authenticate company employees and an Auth0 database connection for external contractors. Authorization is implemented using rules and claims as we will see in detail in this paragraph.
## User Login
Auth0 provides a Lock widget which serves as a login component for your application, meaning that you do not have to implement your own login screen. The Lock widget seamlessly integrates with all of the connections you configure inside your Auth0 dashboard, whether they be database, social or enterprise connections.
There are a number of different ways in which you can implement a Login screen using a web application and Auth0:
* **Hosted Lock**: Use an instance of the Lock widget which is hosted on the Auth0 infrastructure.
* **Embedded Lock**: Embed the Lock widget inside a web page of your application. You have some customization options for the actual Lock widget and full control over the rest of the HTML on the page.
* **Custom UI**: Develop a completely custom web page for the login screen. The custom HTML form will post back to your server which will, in turn, authenticate the user using the Authentication API. For more information on when to use a Custom UI, refer to [Customize Classic Login Pages with Lock or SDK](/docs/customize/login-pages/classic-login/customize-with-lock-sdk).
### Automate Home Realm Discovery (HRD)
By default, Lock will display all the connections available for login. Selecting the appropriate Identity Providers from multiple options is called Home Realm Discovery (HRD). In our case, the options are either authenticating with Active Directory (for company employees) or using email/password for our database connection (external contractors).
You may however want to avoid that first step, where the user needs to choose the Identity Provider (IdP), and have the system identify it instead of asking every time. Lock offers you the following options:
* **Identify the IdP programmatically**: When you initiate an authentication transaction with Auth0 you can optionally send a `connection` parameter. This value maps directly with any connection defined in your dashboard. When using the Hosted version of Lock by calling the `/authorize` endpoint, you can pass along a `connection` query string parameter containing the name of the connection. Alternatively, if you are using Embedded Lock, this is as simple as writing `auth0.show({connections: ['{yourConnection}']});`.
* There are multiple practical ways of getting the `connection` value. One of them is to use **vanity URLs**: for example, company employees will use `https://internal.yoursite.com`, while external contractors will use `https://external.yoursite.com`.
* **Use email domains**: Lock can use email domains as a way of routing authentication requests. Enterprise connections in Auth0 can be mapped to `domains`. If a connection has this setup, then the password textbox gets disabled automatically when typing an email with a mapped domain. Note that you can associate multiple domains to a single connection.
For additional information on this topic refer to [Select from Multiple Connection Options](/docs/libraries/lock/selecting-from-multiple-connection-options).
## Session Management
When talking about managing sessions, there are typically three layers of sessions we need to consider:
* **Application Session**: The first is the session inside the application. Even though your application uses Auth0 to authenticate users, you will still need to keep track of the fact that the user has logged in to your application. In a normal web application this is achieved by storing information inside a cookie.
* **Auth0 session**: Next, Auth0 will also keep a session and store the user's information inside a cookie. Next time when a user is redirected to the Auth0 Lock screen, the user's information will be remembered.
* **Identity Provider session**: The last layer is the Identity Provider, for example Facebook or Google. When you allow users to sign in with any of these providers, and they are already signed into the provider, they will not be prompted to sign in. They may simply be required to give permissions to share their information with Auth0 and in turn your application.
When developing a web application, you will therefore need to keep track of the fact that the user has logged in to your Web application. You can do this by making use of a cookie-based session to keep track of the fact that the user has signed in, and also store any of the user related information or tokens.
### How do I control the duration of the user's local application session? Can I drive that from Auth0?
The web app has full control over the user's local application session. How this is done usually depends on the web stack being used (for example, ASP.NET). Regardless, all approaches ultimately use one or more cookies to control the session. The developer can choose to use the expiration of the JWT ID Token returned by Auth0 to control their session duration or ignore it completely. Some developers store the ID Token itself in session state and end the user's session when it has expired.
The reason why you would use the expiration of the token to determine the expiration of the local session is because it gives you centralized control of the duration of a user session from the Auth0 Dashboard.
The login flow is as follows:
1. **Initiate OIDC Authentication Flow**: The user's browser will send a request to Auth0 to initiate the OIDC flow.
2. **Set SSO Cookie**: Auth0 will set a cookie to store the user's information.
3. **Code exchange and return ID Token**: Auth0 will make a request back to the web server and return the code. The web server will exchange the code for an ID Token.
4. **Set auth cookie and send response**: The web server will send a response back to the browser and set the application authentication cookie to store the user's session information.
5. **Auth cookie sent with every subsequent request**: The application authentication cookie will be sent on every subsequent request as proof that the user is authenticated.
### How does Auth0's SSO session impact the application's session?
Auth0 manages its own single-sign-on session. Applications can choose to honor or ignore that SSO session when it comes to maintaining their own local session. The Lock widget even has a special feature where it can detect if an Auth0 SSO session exists and ask the user if they wish to log in again as that same user.

If they do so, they are signed in without having to re-enter their credentials with the actual IDP. Even though the user didn't authenticate, the application still performs an authentication flow with Auth0 and obtains a new ID Token, which can be used to then manage the new local application session.
**See the implementation in** [**ASP.NET Core**](/docs/get-started/architecture-scenarios/sso-for-regular-web-apps/implementation-aspnetcore#configure-the-cookie-and-oidc-middleware).
## User Logout
When logging the user out, you will once again need to think about the three layers of sessions which we spoke about before:
* **Application Session**: You need to log out the user from your Web Application, by clearing their session.
* **Auth0 session**: You need to log out the user from Auth0. To do this you redirect the user to `https://{yourDomain}/v2/logout`. Redirecting the user to this URL clears all single sign-on cookies set by Auth0 for the user.
* **Identity Provider session**: Although this is not common practice, you can force the user to log out from the Identity Provider used, for example Facebook or Google. To do this add a `federated` query string parameter to the logout URL: `https://{yourDomain}/v2/logout?federated`.
To redirect a user after logout, add a `returnTo` query string parameter with the target URL as the value: `https://{yourDomain}/v2/logout?returnTo=http://www.example.com`. Note, that you will need to add the `returnTo` URL as an **Allowed Logout URLs**. For more information on how to implement this refer to: [Logout](/docs/authenticate/login/logout).
The logout flow (not including federated logout) is as follows:
1. **Initiate Logout Flow**: The logout flow will be initiated from the browser, for example by the user clicking a **Logout** link. A request will be made to the web server.
2. **Clear user’s local session**: The user's Application Session / Cookie will be cleared.
3. **Redirect browser to Auth0 Logout**: The user's browser will be redirected to the Auth0 Logout URL.
4. **Clear SSO Cookie**: Auth0 will clear the user's SSO Cookie.
5. **Redirect to post-logout URL**: Auth0 will return a redirect response and redirect the user's browser to the `returnTo` query string parameter.
**See the implementation in** [**ASP.NET Core**](/docs/get-started/architecture-scenarios/sso-for-regular-web-apps/implementation-aspnetcore#implement-the-logout).
## Access Control
Authorization refers to the process of determining what actions a user can perform inside your application.
You can either implement authorization directly inside your application, independently of Auth0, or use one of the available ways to retrieve the user authorization levels, put them as authorization claims inside the ID Token and validate these claims inside your application, once you retrieve the token, to control access.
There are various ways in which you can retrieve and set the user authorization claims when using Auth0:
* By configuring and using the [Auth0 Authorization Extension](/docs/customize/extensions/authorization-extension).
* By using Active Directory groups. These can be used in combination with the Authorization Extension by mapping Active Directory Groups to Groups you define using the Authorization extension.
* Add metadata to the user's profile by making use of [rules](/docs/customize/rules).
* By calling an external services from inside a rule.
Since in our case the company has already Active Directory set up, we will enforce access control using the Authorization Extension in combination with Active Directory groups.
At this point in time the authorization extension is primarily designed to enforce coarse-grained authorization, for example to control access to an application based on a user's group membership. It is not necessarily designed to control fine-grained access (such as whether a user can perform a specific action inside the application), even though this is how we are utilizing it in this instance.
All users will implicitly be regular users, but timesheet administrators will be assigned to an `Admin` group which will allow them to approve timesheets. The Authorization Extension allows for mapping groups to existing group membership.
All timesheet administrators will be assigned to the `Timesheet Administrators` group on Active Directory, which will be automatically mapped to the `Admin` group inside the Timesheet Application.
When you install the Authorization Extension, it creates a rule in the background, which does the following:
1. Determine the user's group membership.
2. Store the user's group membership info as part of the `app_metadata`.
3. Add the user's group membership to the outgoing token.
4. Verify that the user has been granted access to the current application.
### Install the Authorization Extension
To install the Authorization extension navigate to the [Extensions](https://manage.auth0.com/#/extensions) view of your Auth0 Dashboard, and select and install the Auth0 Authorization extension.
Once installed, you will see the app listed under Installed Extensions.
When you click on the link to open the extension for the first time, you will be prompted to provide permission for the extension to access your Auth0 account. If you do so, you will be redirected to the Authorization Dashboard.
Once on the Authorization Dashboard, navigate to Groups in the navigation menu, and create a new group called Admin.
After the group has been added you can click on the new group to go to the group management section. Go to the Group Mappings tab and add a new group mapping which will map all Active Directory users in the `Timesheet Admins` groups to the `Admin` group you just created.
Once you click **Save** you can see the new mapping listed.
With the mapping configured you only need to maintain membership to the `Timesheet Admins` group in Active Directory, and those users will be automatically mapped to the `Admin` group inside our application.
For more information refer to the [Authorization Extension documentation](/docs/customize/extensions/authorization-extension).
### Enforce permissions in your application
When you installed the Authorization Extension, it also created an Auth0 rule which will add an `authorization` claim with all the authorization related settings for a particular user. The groups for a user will be added as a sub-claim of the `authorization` claim called `groups` and all the groups a user belongs to will be added as an array to this claim. This is an example of what JSON payload of a ID Token may look like with the groups listed:
```json lines theme={null}
{
"sub": "1234567890",
"name": "John Doe",
"authorization": {
"groups": ["Admin"]
}
}
```
In your application you will therefore need to decode the ID Token returned when a user is authenticated, and extract the groups which a user belongs to from the `authorization` claim. You can then store these groups, along with other user information inside the user's session, and subsequently query these to determine whether a user has permissions to perform a certain action based on their group membership.
See the implementation in [ASP.NET Core](/docs/get-started/architecture-scenarios/sso-for-regular-web-apps/implementation-aspnetcore#implement-admin-permissions).
# Conclusion (Web Apps + SSO)
Source: https://auth0.com/docs/get-started/architecture-scenarios/sso-for-regular-web-apps/part-4
Regular web app scenario conclusion
In this tutorial we covered a simple scenario: a regular web app, hosted in the cloud, using Auth0 for authentication, while utilizing the existing Active Directory user store. We learned what OpenID Connect (OIDC) offers and why it was preferable for this business case, how the Authentication Flow works, what an ID Token is and how to validate and manipulate it, how to configure applications and connections on Auth0 dashboard, how to implement user login and logout using Lock, and how session management and access control works.
We started by describing the business case and the requirements and went on explaining how each requirement can be met and the thought process behind each choice that was made.
We used ASP .NET Core for the sample web app implementation, hopefully though after going through this document you are able to build such a web app using the framework you prefer.
# Authentication and Authorization Flows
Source: https://auth0.com/docs/get-started/authentication-and-authorization-flow
Learn about the various flows used for authentication and authorization of applications and APIs.
Auth0 uses the [OpenID Connect (OIDC) Protocol](/docs/authenticate/protocols/openid-connect-protocol) and [OAuth 2.0 Authorization Framework](/docs/authenticate/protocols/oauth) to authenticate users and get their authorization to access protected resources. With Auth0, you can easily support different flows in your own applications and APIs without worrying about OIDC/OAuth 2.0 specifications or other technical aspects of [authentication and authorization](/docs/get-started/identity-fundamentals/authentication-and-authorization).
We support scenarios for server-side, mobile, desktop, client-side, machine-to-machine, and device applications.
If you're not sure which flow to use, we can help you decide. To learn more, read [Which OAuth 2.0 Flow Should I Use?](/docs/get-started/authentication-and-authorization-flow/which-oauth-2-0-flow-should-i-use).
During the execution of several flows, your application must also authenticate to the Authorization Server. To learn more about application authentication, read [Application Credentials](/docs/secure/application-credentials).
Depending on the application API access policies you configure for an API, you may need to create the corresponding client grants for your application. To learn more, read [Application Access to APIs: Policies and Client Grants](/docs/get-started/applications/application-access-to-apis-client-grants).
## Authorization Code Flow
Because regular web apps are server-side apps where the source code is not publicly exposed, they can use the Authorization Code Flow, which exchanges an Authorization Code for a token.
* [Authorization Code Flow](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow)
* [Add Login Using the Authorization Code Flow](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow/add-login-auth-code-flow)
* [Call API Using the Authorization Code Flow](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow/call-your-api-using-the-authorization-code-flow)
## Authorization Code Flow with Proof Key for Code Exchange (PKCE)
During authentication, mobile and native applications can use the Authorization Code Flow, but they require additional security. Additionally, single-page apps have special challenges. To mitigate these, OAuth 2.0 provides a version of the Authorization Code Flow which makes use of a Proof Key for Code Exchange (PKCE).
* [Authorization Code Flow with Proof Key for Code Exchange (PKCE)](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow-with-pkce)
* [Add Login Using the Authorization Code Flow with PKCE](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow-with-pkce/add-login-using-the-authorization-code-flow-with-pkce)
* [Call API Using the Authorization Code Flow with PKCE](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow-with-pkce/call-your-api-using-the-authorization-code-flow-with-pkce)
## Authorization Code Flow with enhanced privacy protection
During the authentication and authorization process, some use cases such as [transactional authorization](/docs/secure/highly-regulated-identity/transactional-authorization-with-authorization-code-flow) exchange contextual information, which may contain sensitive data. To protect data and sensitive information, you can use different protocol improvements for the authorization code flow:
* [Authorization Code Flow with Rich Authorization Requests (RAR)](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow/authorization-code-flow-with-rar)
* [Authorization Code Flow with Pushed Authorization Requests (PAR)](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow/authorization-code-flow-with-par)
* [Authorization Code Flow with JWT-Secured Authorization Requests (JAR)](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow/authorization-code-flow-with-jar)
* [JSON Web Encryption (JWE)](/docs/secure/tokens/access-tokens/json-web-encryption)
## Implicit Flow with Form Post
As an alternative to the Authorization Code Flow, OAuth 2.0 provides the Implicit Flow, which is intended for Public Clients, or applications which are unable to securely store Client Secrets. While this is no longer considered a best practice for requesting Access Tokens, when used with Form Post response mode, it does offer a streamlined workflow if the application needs only an ID token to perform user authentication.
* [Implicit Flow with Form Post](/docs/get-started/authentication-and-authorization-flow/implicit-flow-with-form-post)
* [Add Login Using the Implicit Flow with Form Post](/docs/get-started/authentication-and-authorization-flow/implicit-flow-with-form-post/add-login-using-the-implicit-flow-with-form-post)
* [Authenticate SPAs with Cookies](/docs/manage-users/cookies/spa-authenticate-with-cookies)
## Hybrid Flow
Applications that are able to securely store Client Secrets may benefit from the use of the Hybrid Flow, which combines features of the Authorization Code Flow and Implicit Flow with Form Post to allow your application to have immediate access to an ID token while still providing for secure and safe retrieval of access and refresh tokens. This can be useful in situations where your application needs to immediately access information about the user, but must perform some processing before gaining access to protected resources for an extended period of time.
* [Hybrid Flow](/docs/get-started/authentication-and-authorization-flow/hybrid-flow)
* [Call API Using the Hybrid Flow](/docs/get-started/authentication-and-authorization-flow/hybrid-flow/call-api-hybrid-flow)
## Client Credentials Flow
With machine-to-machine (M2M) applications, such as CLIs, daemons, or services running on your back-end, the system authenticates and authorizes the app rather than a user. For this scenario, typical authentication schemes like identifier + password or social logins don't make sense. Instead, M2M apps use the Client Credentials Flow (defined in OAuth 2.0 RFC 6749, section 4.4).
* [Client Credentials Flow](/docs/get-started/authentication-and-authorization-flow/client-credentials-flow)
* [Call API Using the Client Credentials Flow](/docs/get-started/authentication-and-authorization-flow/client-credentials-flow/call-your-api-using-the-client-credentials-flow)
## Device Authorization Flow
With input-constrained devices that connect to the internet, rather than authenticate the user directly, the device asks the user to go to a link on their computer or smartphone and authorize the device. This avoids a poor user experience for devices that do not have an easy way to enter text. To do this, device apps use the Device Authorization Flow (drafted in OAuth 2.0). For use with mobile/native applications.
* [Device Authorization Flow](/docs/get-started/authentication-and-authorization-flow/device-authorization-flow)
* [Call API Using the Device Authorization Flow](/docs/get-started/authentication-and-authorization-flow/device-authorization-flow/call-your-api-using-the-device-authorization-flow)
## Resource Owner Password Flow
Though we do not recommend it, highly-trusted applications can use the Resource Owner Password Flow, which requests that users provide credentials (identifier and password), typically using an interactive form. The Resource Owner Password Flow should only be used when redirect-based flows (like the [Authorization Code Flow](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow)) cannot be used.
* [Resource Owner Password Flow](/docs/get-started/authentication-and-authorization-flow/resource-owner-password-flow)
* [Call API Using the Resource Owner Password Flow](/docs/get-started/authentication-and-authorization-flow/resource-owner-password-flow/call-your-api-using-resource-owner-password-flow)
## Client-Initiated Backchannel Authentication Flow
With the Client-Initiated Backchannel Authentication Flow (CIBA), rather than authenticate the user directly, the client application backend initiates an authentication flow to challenge the user for authentication. The authentication itself is performed on a separate authentication device, typically a smartphone running a custom app.
* [Client-Initiated Backchannel Authentication Flow](/docs/get-started/authentication-and-authorization-flow/client-initiated-backchannel-authentication-flow)
* [User Authentication with CIBA](/docs/get-started/authentication-and-authorization-flow/client-initiated-backchannel-authentication-flow/user-authentication-with-ciba)
* [User Authorization with CIBA](/docs/get-started/authentication-and-authorization-flow/client-initiated-backchannel-authentication-flow/user-authorization-with-ciba)
## Custom Token Exchange
Custom Token Exchange (CTE) enables applications to exchange pre-existing identity tokens for Auth0 tokens by invoking the `/oauth/token` endpoint, as defined in [RFC 8693](https://datatracker.ietf.org/doc/html/rfc8693). For example, you can use the Custom Token Exchange to exchange Auth0 tokens to access another audience on the user’s behalf. To learn more about Custom Token Exchange use cases, read [Example Use Cases](/docs/authenticate/custom-token-exchange/cte-example-use-cases).
By associating a [Custom Token Exchange Profile](/docs/authenticate/custom-token-exchange/configure-custom-token-exchange) with an Action that contains custom logic, you can implement highly customized identity workflows by exchanging one security token for another, all while maintaining control over the authorization logic.
# Authenticate with mTLS
Source: https://auth0.com/docs/get-started/authentication-and-authorization-flow/authenticate-with-mtls
Learn how mutual TLS (mTLS) secures OAuth flows by replacing shared client secrets with X.509 certificates and optionally binding access tokens to the client.
## mTLS in OAuth/OIDC
Default OAuth/OIDC flows are not always secure because of the following issues:
* The use of a shared Client Secret as a form of client authentication.
* The ability for an access token to be used by unintended parties.
In 2020, the Internet Engineering Task Force (IETF) released [RFC 8705](https://www.rfc-editor.org/rfc/rfc8705) Mutual-TLS (mTLS) client authentication to address these issues. With mTLS authentication, the client certificate with a private key functions like a Client Secret in an OAuth/OIDC flow to verify the client’s identity. If a client is already authenticated at the network layer, there’s no need for a Client Secret at the application layer. Additionally, client certificates can be used with multiple servers to prove a client’s identity to a resource server. Note there are other approaches to solve the above issues, namely [Private Key JWT](/docs/get-started/authentication-and-authorization-flow/authenticate-with-private-key-jwt) and [DPoP](https://datatracker.ietf.org/doc/html/rfc9449) respectively.
To secure an OAuth flow with mTLS, clients send a mTLS certificate to the TLS termination point on the customer edge network when the TLS connection is being established. Before the authorization server processes the request, it must first verify the client’s mTLS certificate.
Optionally, mTLS can also be used to ensure an access token is used only by the intended party, known as Sender Constraining or Token Binding. When the client calls the `/oauth/token` endpoint on the authorization server using an mTLS connection, the resulting access token contains information that the resource server uses to verify that the client’s TLS certificate matches that of the access token.
**Note**: mTLS client authentication and mTLS Token Binding can be used independently of each other. mTLS client authentication can be used without mTLS Token Binding, and mTLS Token Binding can be used with other forms of client authentication such as Client Secret or Private Key JWT. Even if other forms of client authentication are used, the client still sends the client certificate to the authorization server for mTLS Token Binding.
## mTLS at Auth0
mTLS for Auth0 builds on [custom domains](/docs/customize/custom-domains) and leverages the customer’s existing mTLS infrastructure to perform certificate provisioning and verification.
Authenticated client calls to Auth0 that normally require a Client Secret are first sent to the customer edge. This already happens for custom domains that use customer-managed certificates. The customer edge performs the mTLS handshake with the client and validates the client certificate. Once the client certificate is verified, the request is then forwarded to the tenant’s edge domain at Auth0, including the validated client certificate in an HTTP header along with the correct `cname-api-key` as per the custom domains functionality.
## Call the authorization server
Since mTLS serves both client authentication and access token binding, the client must know whether these features are enabled on the authorization server. In addition, an authorization server’s mTLS endpoints and non-mTLS endpoints may be exposed on different domains.
To get configuration details about the authorization server, the client sends a GET request to the [OpenID Connect Discovery](https://openid.net/specs/openid-connect-discovery-1_0.html) endpoint: `https:///.well-known/openid-configuration`
A successful response returns the OIDC discovery document, or a JSON object listing the authorization server’s properties and endpoints, including those related to mTLS.
If mTLS client authentication is enabled, the OIDC discovery document includes the `token_endpoint_auth_methods_supported` property, which contains either `tls_client_auth` or `self_signed_tls_client_auth`:
```json lines theme={null}
{
...
"token_endpoint_auth_methods_supported": ["tls_client_auth"]
...
}
```
If mTLS Token Binding is enabled, the OIDC discovery document sets the `tls_client_certificate_bound_access_tokens` property to `true:`
```json lines theme={null}
{
...
"tls_client_certificate_bound_access_tokens": true
...
}
```
Environments that support mTLS endpoint aliases expose a new property, `mtls_endpoint_aliases`, that contains a list of endpoints that support mTLS. For clients that support mTLS, the endpoints listed under `mtls_endpoint_aliases` take precedence over the same endpoints exposed outside of `mtls_endpoint_aliases`.
In the following code sample, the `token_endpoint` property is exposed twice. The endpoint to use for mTLS calls is listed under `mtls_endpoint_aliases`, or `https://mtls.auth.bank.com/oauth/token`:
```json lines theme={null}
{
...
"mtls_endpoint_aliases": {
"token_endpoint": "https://mtls.auth.bank.com/oauth/token"
},
"token_endpoint": "https://auth.bank.com/oauth/token",
"pushed_authorization_request_endpoint": "https://auth.bank.com/oauth/par",
...
}
```
If an endpoint is not listed under `mtls_endpoint_aliases`, use the same endpoint listed outside of `mtls_endpoint_aliases`. In the example above, `pushed_authorization_request_endpoint` is not listed under `mtls_endpoint_aliases`. As a result, use the `pushed_authorization_request_endpoint` exposed outside of `mtls_endpoint_aliases`, or `https://auth.bank.com/oauth/par`.
For more information, see RFC 8705’s [section on endpoint aliases](https://www.rfc-editor.org/rfc/rfc8705#name-metadata-for-mutual-tls-end).
## Call the resource server
Once a client receives an access token, it can access protected resources on a resource server. If mTLS Token Binding is enabled, the authorization server returns the OIDC discovery document that contains the `tls_client_certificate_bound_access_tokens` property.
When the client calls the resource server with a mTLS-bound access token, the resource server requests a mTLS certificate from the client during the TLS handshake. The resource server should reject requests with an access token that does not match that client certificate with a 401 HTTP status code and an `invalid_token` error code. To learn more, read [Configure Resource Server for Sender Constraining](/docs/secure/sender-constraining/configure-sender-constraining/configure-resource-server-for-sender-constraining).
## Learn more
* [Configure mTLS Authentication](/docs/get-started/applications/configure-mtls)
# Authenticate with Private Key JWT
Source: https://auth0.com/docs/get-started/authentication-and-authorization-flow/authenticate-with-private-key-jwt
Describes how to build an assertion to use Private Key JWT Authentication.
You need to create a new application in Auth0 Dashboard or convert an existing application before you continue. To learn more, read [Configure Private Key JWT Authentication](/docs/get-started/applications/configure-private-key-jwt).
You need to complete two steps when authenticating with `private_key_jwt:`
1. Build the client assertion. This assertion is a JWT signed by the private key when you generated the key pair. To learn how to generate a key pair, read [Configure Private Key JWT Authentication](/docs/get-started/applications/configure-private-key-jwt).
2. Use the assertion to authenticate against Auth0.
## Build the assertion
You can use one of Auth0’s SDKs to build an assertion automatically for you. If you don’t use our SDKs, you will need to construct the assertion yourself.
The assertion is a JSON Web Token (JWT) that should contain the following properties and claims:
All claims are required unless otherwise stated. To learn more about JWT claims, read [JSON Web Token Claims](/docs/secure/tokens/json-web-tokens/json-web-token-claims).
* Header
* `alg`: The algorithm used to sign the assertion. The algorithm must match the algorithm specified when you created your application credential.
* `kid`**:** (optional) The Auth0 generated `kid` of the credential. The `kid` is created when you created the credential.
* Payload
* `iss`**:** Your application's Client ID. You can find this value in your application settings under [Auth0 Dashboard > Applications > Applications](https://manage.auth0.com/dashboard/#/applications/) and select the **Settings** tab.
* `sub`**:** Your application's Client ID. You also can find this value in your application settings. You can find this value in your application settings under [Auth0 Dashboard > Applications > Applications](https://manage.auth0.com/dashboard/#/applications/) and select the **Settings** tab.
* `aud`**:** The URL of the Auth0 tenant or custom domain that receives the assertion. For example: `https://{yourTenant}.auth0.com/`**.** Include the trailing slash.
If you have configured a custom domain for your Auth0 tenant, this can be used as the `aud` claim. We recommend using the custom domain in this case.
* `iat` (optional), `nbf` (optional), and `exp`: Issued At, Not Before, and Expiration claims set to the correct timestamps. A clock skew of up to 10 seconds is allowed for `iat` and `nbf` (if present) to support inter-operability. The client assertion is a one-time use token, and we recommend the shortest possible expiry time. Auth0 supports a maximum of 5 minutes for the lifetime of a token.
* `jti`: A unique claim ID created by the client. We recommend using the Universally Unique Identifier (UUID) format.
This JWT is a one-time use only token and should be considered as such by having a short expiry. We recommend setting a maximum of 1 minute.
The token must then be signed with the private key you generated when you created or configured your application for Private Key JWT Authentication. To learn how, review the [JSON Web Token specification](https://www.rfc-editor.org/rfc/rfc7519#section-7.1).
We recommend you construct the token using standard tooling or third party libraries that support this functionality out of the box, rather than implementing from scratch yourself. To learn more about supporting libraries, read the listing at [JWT.io](https://jwt.io/libraries).
### Example
In the example below, the Node.js script uses a [jose package](https://github.com/panva/jose) to generate the assertion:
```javascript lines expandable theme={null}
const { SignJWT } = require('jose')
const crypto = require("crypto");
const uuid = require("uuid");
async function main() {
const privateKeyPEM = crypto.createPrivateKey(/**
Read the content of your private key here. We recommend to store your private key
in a secure infrastructure.
*/);
const jwt = await new SignJWT({})
.setProtectedHeader({
alg: 'RS256', // or RS384 or PS256
kid: '(OPTIONAL) KID_GENERATED_BY_AUTH0'
})
.setIssuedAt()
.setIssuer('CLIENT_ID')
.setSubject('CLIENT_ID')
.setAudience('https://YOUR_TENANT.auth0.com/') // or your CUSTOM_DOMAIN
.setExpirationTime('1m')
.setJti(uuid.v4())
.sign(privateKeyPEM);
console.log(jwt)
}
main();
```
Example client assertion signed with a private key:
Corresponds to:
```json lines theme={null}
{
"alg": "RS256",
"kid": "my kid"
}
{
"iat": 1626684584,
"iss": "my client id",
"sub": "my client id",
"aud": "https://mytenant.auth0.com/",
"exp": 1626684644,
"jti": "e4dc8ed1-b108-4901-8bbc-c07a791817e7"
}
```
After you generate the JWT with the required information, you are ready to authenticate your application against Auth0.
## Exchange assertion for access tokens
The following example uses the [Client Credential Flow](/docs/get-started/authentication-and-authorization-flow/client-credentials-flow). Private Key JWT authentication can be used for other grant types that also allow replacing `client_secret` with `client_assertion`.
To exchange the JWT assertion for an access token, call the Authentication API [token endpoint](https://auth0.com/docs/api/authentication#authenticate-user) with the following parameters:
* `$client_assertion`: JWT assertion
* `$resource_server_identifier`: resource server identifier. To learn more, read [Register APIs](/docs/get-started/auth0-overview/set-up-apis).
```bash lines theme={null}
curl --location --request POST 'https://$tenant/oauth/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=client_credentials' \
--data-urlencode 'client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer' \
--data-urlencode 'client_assertion=$client_assertion' \
--data-urlencode 'audience=$resource_server_idenifier'
```
## Supported endpoints
In addition to the [https://\$tenant/oauth/token](https://auth0.com/docs/api/authentication#get-token) endpoint, the following Auth0 Authentication API endpoints support `private_key_jwt` authentication for configured applications:
* [POST /oauth/revoke](https://auth0.com/docs/api/authentication#revoke-refresh-token)
* [POST /mfa/challenge](https://auth0.com/docs/api/authentication#challenge-request)
* [POST /passwordless/start](https://auth0.com/docs/api/authentication#get-code-or-link)
## Assertion limits
The maximum length of the JWT assertion is 2048 bytes.
Claims within the assertion have the following limits:
* `iss`: 64 characters
* `sub`: 64 characters
* `jti`: 64 characters
* `alg`: 16 characters
## Learn more
* [Configure Private Key JWT Authentication](/docs/get-started/applications/configure-private-key-jwt)
* [Private Key JWT Client Authentication for Okta and OIDC Connections](/docs/authenticate/enterprise-connections/private-key-jwt-client-auth)
# Authorization Code Flow
Source: https://auth0.com/docs/get-started/authentication-and-authorization-flow/authorization-code-flow
Learn how the Authorization Code flow works and why you should use it for regular web apps.
The Authorization Code Flow (defined in [OAuth 2.0 RFC 6749, section 4.1](https://tools.ietf.org/html/rfc6749#section-4.1)), involves exchanging an authorization code for a token.
This flow can only be used for confidential applications (such as Regular Web Applications) because the application's authentication methods are included in the exchange and must be kept secure.
## How Authorization Code Flow works
1. User selects **Login** within application.
2. Auth0's SDK redirects user to Auth0 Authorization Server ([`/authorize`](https://auth0.com/docs/api/authentication/authorization-code-flow/authorize-application) endpoint).
3. Auth0 Authorization Server redirects user to login and authorization prompt.
4. User authenticates using one of the configured login options, and may see a consent prompt listing the permissions Auth0 will give to the application.
5. Auth0 Authorization Server redirects user back to application with single-use authorization code.
6. Auth0's SDK sends authorization code, application's client ID, and application's credentials, such as client secret or Private Key JWT, to Auth0 Authorization Server ([`/oauth/token`](https://auth0.com/docs/api/authentication/authorization-code-flow/get-token) endpoint).
7. Auth0 Authorization Server verifies authorization code, application's client ID, and application's credentials.
8. Auth0 Authorization Server responds with an ID token and access token (and optionally, a refresh token).
9. Application can use the access token to call an API to access information about the user.
10. API responds with requested data.
## How to implement Authorization Code Flow
The easiest way to implement the Authorization Code Flow is to follow our [Regular Web App Quickstarts](/docs/quickstart/webapp).
Alternatively, you can use the Authentication API to implement the Authorization Code Flow. For more information, read [Add Login Using the Authorization Code Flow](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow/add-login-auth-code-flow) or [Call Your API Using the Authorization Code Flow](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow/call-your-api-using-the-authorization-code-flow).
If a browser application, with an Origin header, makes a `POST` request to the `/oauth/token` endpoint, Auth0 doesn’t issue refresh tokens, even if the application has [Allow Refresh Token Rotation](/docs/secure/tokens/refresh-tokens/configure-refresh-token-rotation) enabled and sends the [offline\_access](/docs/secure/tokens/refresh-tokens/configure-refresh-token-rotation#configure-with-the-auth0-spa-sdk) scope.
## Learn more
* [Auth0 Rules](/docs/customize/rules)
* [Auth0 Hooks](/docs/customize/hooks)
* [Tokens](/docs/secure/tokens)
* [Token Best Practices](/docs/secure/tokens/token-best-practices)
* [Which OAuth 2.0 Flow Should I Use?](/docs/get-started/authentication-and-authorization-flow/which-oauth-2-0-flow-should-i-use)
# Authorization Code Flow with Proof Key for Code Exchange (PKCE)
Source: https://auth0.com/docs/get-started/authentication-and-authorization-flow/authorization-code-flow-with-pkce
Learn how the Authorization Code flow with Proof Key for Code Exchange (PKCE) works and why you should use it for native and mobile apps.
Key Concepts
* Learn about the OAuth 2.0 grant type, Authorization Code Flow with Proof Key for Code Exchange (PKCE).
* Use this grant type for applications that cannot store a client secret, such as native or single-page apps.
* Review different implementation methods with Auth0 SDKs.
When public clients (e.g., native and single-page applications) request access tokens, some additional security concerns are posed that are not mitigated by the Authorization Code Flow alone. This is because:
**Native apps**
* Cannot securely store a Client Secret. Decompiling the app will reveal the Client Secret, which is bound to the app and is the same for all users and devices.
* Are vulnerable to authorization code interception and injection attacks. Without a client secret, an attacker who intercepts the authorization code can exchange it for tokens.
* May make use of a custom URL scheme to capture redirects (e.g., MyApp\://) potentially allowing malicious applications to receive an Authorization Code from your Authorization Server. Because of this risk, **Auth0 strongly discourages the use of custom URI schemes**. To learn more, read [Measures Against Application Impersonation](/docs/secure/security-guidance/measures-against-app-impersonation).
**Single-page apps**
* Cannot securely store a Client Secret because their entire source is available to the browser.
Given these situations, OAuth 2.0 provides a version of the Authorization Code Flow which makes use of a Proof Key for Code Exchange (PKCE) (defined in [OAuth 2.0 RFC 7636](https://tools.ietf.org/html/rfc7636)).
The PKCE-enhanced Authorization Code Flow introduces a secret created by the calling application that can be verified by the authorization server; this secret is called the Code Verifier. Additionally, the calling app creates a transform value of the Code Verifier called the Code Challenge and sends this value over HTTPS to retrieve an Authorization Code. This way, a malicious attacker can only intercept the Authorization Code, and they cannot exchange it for a token without the Code Verifier.
## How it works
Because the PKCE-enhanced Authorization Code Flow builds upon the [standard Authorization Code Flow](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow), the steps are very similar.
1. The user clicks **Login** within the application.
2. Auth0's SDK creates a cryptographically-random `code_verifier` and from this generates a `code_challenge`.
3. Auth0's SDK redirects the user to the Auth0 Authorization Server ([`/authorize` endpoint](/docs/api/authentication#authorization-code-grant-pkce-)) along with the `code_challenge`.
4. Your Auth0 Authorization Server redirects the user to the login and authorization prompt.
5. The user authenticates using one of the configured login options and may see a consent page listing the permissions Auth0 will give to the application.
6. Your Auth0 Authorization Server stores the `code_challenge` and redirects the user back to the application with an authorization `code`, which is good for one use.
7. Auth0's SDK sends this `code` and the `code_verifier` (created in step 2) to the Auth0 Authorization Server `(`[`/oauth/token` endpoint](/docs/api/authentication?http#authorization-code-flow-with-pkce44)).
8. Your Auth0 Authorization Server verifies the `code_challenge` and `code_verifier`.
9. Your Auth0 Authorization Server responds with an ID token and access token (and optionally, a refresh token).
10. Your application can use the access token to call an API to access information about the user.
11. The API responds with requested data.
If you have [Refresh Token Rotation](/docs/secure/tokens/refresh-tokens/refresh-token-rotation) enabled, a new Refresh Token is generated with each request and issued along with the Access Token. When a Refresh Token is exchanged, the previous Refresh Token is invalidated but information about the relationship is retained by the authorization server.
## How to implement it
The easiest way to implement the Authorization Code Flow with PKCE is to [follow our Native Quickstarts](/docs/quickstart/native) or [follow our Single-Page Quickstarts](/docs/quickstart/spa).
Depending on your application type, you can also use our mobile or single-page app SDKs:
**Mobile**
* [Auth0 Swift SDK](/docs/libraries/auth0-swift)
* [Auth0 Android SDK](/docs/libraries/auth0-android)
**Single-page**
* [Auth0 Single-Page App SDK](/docs/libraries/auth0-single-page-app-sdk)
* [Auth0 React SDK](/docs/libraries/auth0-react)
Recent advancements in user privacy controls in browsers adversely impact the user experience by preventing access to third-party cookies; therefore, browser-based flows must use [Refresh Token Rotation](/docs/secure/tokens/refresh-tokens/refresh-token-rotation), which provides a secure method for using refresh tokens in SPAs while providing end-users with seamless access to resources without the disruption in UX caused by browser privacy technology like ITP.
You can follow our tutorials to use our API endpoints to [Add Login Using the Authorization Code Flow with PKCE](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow-with-pkce/add-login-using-the-authorization-code-flow-with-pkce) or [Call Your API Using the Authorization Code Flow with PKCE](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow-with-pkce/call-your-api-using-the-authorization-code-flow-with-pkce).
## Learn more
* [Auth0 Rules](/docs/customize/rules)
* [Auth0 Hooks](/docs/customize/hooks)
* [Tokens](/docs/secure/tokens)
* [Token Best Practices](/docs/secure/tokens/token-best-practices)
* [Which OAuth 2.0 Flow Should I Use?](/docs/get-started/authentication-and-authorization-flow/which-oauth-2-0-flow-should-i-use)
# Add Login Using the Authorization Code Flow with PKCE
Source: https://auth0.com/docs/get-started/authentication-and-authorization-flow/authorization-code-flow-with-pkce/add-login-using-the-authorization-code-flow-with-pkce
Learn how to add login to your native, mobile, or single-page application using the Authorization Code Flow with Proof Key for Code Exchange (PKCE).
You can add login to your native, mobile, or single-page app using the Authorization Code Flow with PKCE. To learn how the flow works and why you should use it, read [Authorization Code Flow with Proof Key for Code Exchange (PKCE)](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow-with-pkce). To learn how to call your API from a native, mobile, or single-page app, read [Call Your API Using Authorization Code Flow with PKCE](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow-with-pkce/call-your-api-using-the-authorization-code-flow-with-pkce).
To implement the Authorization Code Flow with Proof Key for Code Exchange (PKCE), you can use the following resources:
* [Auth0 Mobile SDKs](/docs/libraries) and [Auth0 Single-Page App SDK](/docs/libraries/auth0-single-page-app-sdk): The easiest way to implement the flow, which will do most of the heavy lifting for you. Our [Mobile Quickstarts](/docs/quickstart/native) and [Single-Page App Quickstarts](/docs/quickstart/spa) will walk you through the process.
* [Authentication API](https://auth0.com/docs/api/authentication): If you prefer to build your own solution, keep reading to learn how to call our API directly.
Following successful login, your application will have access to the user's ID token and access token. The ID token will contain basic user profile information, and the access token can be used to call the Auth0 `/userinfo` endpoint or your own protected APIs. To learn more about ID tokens, read [ID Tokens](/docs/secure/tokens/id-tokens). To learn more about access tokens, read [Access Tokens](/docs/secure/tokens/access-tokens).
## Prerequisites
Register your app with Auth0. To learn more, read [Register Native Applications](/docs/get-started/auth0-overview/create-applications/native-apps) or [Register Single-Page Web Applications](/docs/get-started/auth0-overview/create-applications/single-page-web-apps).
* Select an **Application Type** of **Native** or **Single-Page App**, depending on your application type.
* Add an **Allowed Callback URL** of `YOUR_CALLBACK_URL`. Your callback URL format will vary depending on your application type and platform. For details about the format for your application type and platform, see our [Native/Mobile Quickstarts](/docs/quickstart/native) and [Single-Page App Quickstarts](/docs/quickstart/spa).
* Make sure your application's **Grant Types** include **Authorization Code**. To learn more, read [Update Grant Types](/docs/get-started/applications/update-grant-types).
## Create code verifier
Create a `code_verifier`, which is a cryptographically-random, Base64-encoded key that will eventually be sent to Auth0 to request tokens.
To learn more about the algorithm to create the `code_verifier`, read section [4.1 Client Creates a Code Verifier](https://datatracker.ietf.org/doc/html/rfc7636#section-4.1) of the OAuth Proof Key for Code Exchange spec.
### Javascript sample
```javascript lines theme={null}
// Dependency: Node.js crypto module
// https://nodejs.org/api/crypto.html#crypto_crypto
function base64URLEncode(str) {
return str.toString('base64')
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=/g, '');
}
var verifier = base64URLEncode(crypto.randomBytes(32));
```
### Java sample
```javascript lines theme={null}
// Dependency: Apache Commons Codec
// https://commons.apache.org/proper/commons-codec/
// Import the Base64 class.
// import org.apache.commons.codec.binary.Base64;
SecureRandom sr = new SecureRandom();
byte[] code = new byte[32];
sr.nextBytes(code);
String verifier = Base64.getUrlEncoder().withoutPadding().encodeToString(code);
```
### Android sample
```javascript lines theme={null}
// Dependency: Apache Commons Codec
// https://commons.apache.org/proper/commons-codec/
// Import the Base64 class.
// import org.apache.commons.codec.binary.Base64;
SecureRandom sr = new SecureRandom();
byte[] code = new byte[32];
sr.nextBytes(code);
String verifier = Base64.encodeToString(code, Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING);
```
### Swift 5 sample
```javascript lines theme={null}
var buffer = [UInt8](repeating: 0, count: 32)
_ = SecRandomCopyBytes(kSecRandomDefault, buffer.count, &buffer)
let verifier = Data(buffer).base64EncodedString()
.replacingOccurrences(of: "+", with: "-")
.replacingOccurrences(of: "/", with: "_")
.replacingOccurrences(of: "=", with: "")
```
### Objective-C sample
```objc lines theme={null}
NSMutableData *data = [NSMutableData dataWithLength:32];
int result __attribute__((unused)) = SecRandomCopyBytes(kSecRandomDefault, 32, data.mutableBytes);
NSString *verifier = [[[[data base64EncodedStringWithOptions:0]
stringByReplacingOccurrencesOfString:@"+" withString:@"-"]
stringByReplacingOccurrencesOfString:@"/" withString:@"_"]
stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"="]];
```
## Create code challenge
Generate a `code_challenge` from the `code_verifier` that will be sent to Auth0 to request an `authorization_code`.
To learn more about how the `code_challenge` is derived from the `code_verifier`, read section [4.2 Client Creates the Code Challenge](https://datatracker.ietf.org/doc/html/rfc7636#section-4.) of the OAuth Proof Key for Code Exchange spec.
### Javascript sample
```javascript lines theme={null}
// Dependency: Node.js crypto module
// https://nodejs.org/api/crypto.html#crypto_crypto
function sha256(buffer) {
return crypto.createHash('sha256').update(buffer).digest();
}
var challenge = base64URLEncode(sha256(verifier));
```
### Java sample
```java lines theme={null}
// Dependency: Apache Commons Codec
// https://commons.apache.org/proper/commons-codec/
// Import the Base64 class.
// import org.apache.commons.codec.binary.Base64;
byte[] bytes = verifier.getBytes("US-ASCII");
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(bytes, 0, bytes.length);
byte[] digest = md.digest();
String challenge = Base64.encodeBase64URLSafeString(digest);
```
### Swift 5 sample
```swift lines theme={null}
import CommonCrypto
// ...
guard let data = verifier.data(using: .utf8) else { return nil }
var buffer = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH))
_ = data.withUnsafeBytes {
CC_SHA256($0.baseAddress, CC_LONG(data.count), &buffer)
}
let hash = Data(buffer)
let challenge = hash.base64EncodedString()
.replacingOccurrences(of: "+", with: "-")
.replacingOccurrences(of: "/", with: "_")
.replacingOccurrences(of: "=", with: "")
```
### Objective-C sample
```objc lines theme={null}
// Dependency: Apple Common Crypto library
// http://opensource.apple.com//source/CommonCrypto
u_int8_t buffer[CC_SHA256_DIGEST_LENGTH * sizeof(u_int8_t)];
memset(buffer, 0x0, CC_SHA256_DIGEST_LENGTH);
NSData *data = [verifier dataUsingEncoding:NSUTF8StringEncoding];
CC_SHA256([data bytes], (CC_LONG)[data length], buffer);
NSData *hash = [NSData dataWithBytes:buffer length:CC_SHA256_DIGEST_LENGTH];
NSString *challenge = [[[[hash base64EncodedStringWithOptions:0]
stringByReplacingOccurrencesOfString:@"+" withString:@"-"]
stringByReplacingOccurrencesOfString:@"/" withString:@"_"]
stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"="]];
```
## Authorize user
Request the user's authorization and redirect back to your app with an `authorization_code`.
Once you've created the `code_verifier` and the `code_challenge`, you must get the user's authorization. This is technically the beginning of the authorization flow, and this step may include one or more of the following processes:
\* Authenticating the user;
\* Redirecting the user to an Identity Provider to handle authentication;
\* Checking for active [Single Sign-on (SSO)](/docs/authenticate/single-sign-on) sessions;
\* Obtaining user consent for the requested permission level, unless consent has been previously given.
To authorize the user, your app must send the user to the [authorization URL](https://auth0.com/docs/api/authentication#authorization-code-grant-pkce-), including the `code_challenge` you generated in the previous step and the method you used to generate the `code_challenge`.
### Authorization URL example
### Parameters
| Parameter Name | Description |
| - | - |
| `response_type` | Denotes the kind of credential that Auth0 will return (`code` or `token`). For this flow, the value must be `code`. |
| `code_challenge` | Generated challenge from the `code_verifier`. |
| `code_challenge_method` | Method used to generate the challenge (e.g., S256). The PKCE spec defines two methods, `S256` and `plain`, the former is used in this example and is the **only** one supported by Auth0 since the latter is discouraged. |
| `client_id` | Your application's Client ID. You can find this value in your [Application Settings](https://manage.auth0.com/#/Applications/\{yourClientId}/settings). |
| `redirect_uri` | The URL to which Auth0 will redirect the browser after authorization has been granted by the user. The Authorization Code will be available in the `code` URL parameter. You must specify this URL as a valid callback URL in your [Application Settings](https://manage.auth0.com/#/Applications/\{yourClientId}/settings).
**Warning:** Per the [OAuth 2.0 Specification](https://tools.ietf.org/html/rfc6749#section-3.1.2), Auth0 removes everything after the hash and does *not* honor any fragments. |
| `scope` | Specifies the [scopes](/docs/get-started/apis/scopes) for which you want to request authorization, which dictate which claims (or user attributes) you want returned. These must be separated by a space. To get an ID Token in the response, you need to specify a scope of at least `openid`. If you want to return the user's full profile, you can request `openid profile`. You can request any of the [standard OpenID Connect (OIDC) scopes](https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims) about users, such as `email`, or [custom claims](/docs/secure/tokens/json-web-tokens/json-web-token-claims#custom-claims) conforming to a [namespaced format](/docs/secure/tokens/json-web-tokens/create-custom-claims). Include `offline_access` to get a [Refresh Token](/docs/glossary?term=Refresh+Token) (make sure that the **Allow Offline Access** field is enabled in the [Application Settings](https://manage.auth0.com/#/applications)). |
| `state` | (recommended) An opaque arbitrary alphanumeric string your app adds to the initial request that Auth0 includes when redirecting back to your application. To see how to use this value to prevent cross-site request forgery (CSRF) attacks, see [Mitigate CSRF Attacks With State Parameters](/docs/secure/attack-protection/state-parameters). |
| `connection` | (optional) Forces the user to sign in with a specific connection. For example, you can pass a value of `github` to send the user directly to GitHub to log in with their GitHub account. When not specified, the user sees the Auth0 Lock screen with all configured connections. You can see a list of your configured connections on the **Connections** tab of your application. |
| `organization` | (optional) ID of the organization to use when authenticating a user. When not provided, if your application is configured to **Display Organization Prompt**, the user will be able to enter the organization name when authenticating. |
| `invitation` | (optional) Ticket ID of the organization invitation. When [inviting a member to an Organization](/docs/manage-users/organizations/configure-organizations/invite-members), your application should handle invitation acceptance by forwarding the `invitation` and `organization` key-value pairs when the user accepts the invitation. |
As an example, your HTML snippet for your authorization URL when adding login to your app might look like:
### Response
If all goes well, you'll receive an `HTTP 302` response. The authorization code is included at the end of the URL:
```http lines theme={null}
HTTP/1.1 302 Found
Location: {yourCallbackUrl}?code={authorizationCode}&state=xyzABC123
```
## Request tokens
Exchange your `authorization_code` and `code_verifier` for tokens.
Now that you have an Authorization Code, you must exchange it for tokens. Using the extracted Authorization Code (`code`) from the previous step, you will need to `POST` to the [token URL](https://auth0.com/docs/api/authentication#authorization-code-pkce-) sending along the `code_verifier`.
### POST to token URL example
```bash cURL theme={null}
curl --request POST \
--url 'https://{yourDomain}/oauth/token' \
--header 'content-type: application/x-www-form-urlencoded' \
--data grant_type=authorization_code \
--data 'client_id={yourClientId}' \
--data 'code_verifier={yourGeneratedCodeVerifier}' \
--data 'code={yourAuthorizationCode}' \
--data 'redirect_uri={https://yourApp/callback}'
```
```csharp C# theme={null}
var client = new RestClient("https://{yourDomain}/oauth/token");
var request = new RestRequest(Method.POST);
request.AddHeader("content-type", "application/x-www-form-urlencoded");
request.AddParameter("application/x-www-form-urlencoded", "grant_type=authorization_code&client_id={yourClientId}&code_verifier=%7ByourGeneratedCodeVerifier%7D&code=%7ByourAuthorizationCode%7D&redirect_uri={https://yourApp/callback}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```
```go Go theme={null}
package main
import (
"fmt"
"strings"
"net/http"
"io/ioutil"
)
func main() {
url := "https://{yourDomain}/oauth/token"
payload := strings.NewReader("grant_type=authorization_code&client_id={yourClientId}&code_verifier=%7ByourGeneratedCodeVerifier%7D&code=%7ByourAuthorizationCode%7D&redirect_uri={https://yourApp/callback}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("content-type", "application/x-www-form-urlencoded")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := ioutil.ReadAll(res.Body)
fmt.Println(res)
fmt.Println(string(body))
}
```
```java Java theme={null}
HttpResponse response = Unirest.post("https://{yourDomain}/oauth/token")
.header("content-type", "application/x-www-form-urlencoded")
.body("grant_type=authorization_code&client_id={yourClientId}&code_verifier=%7ByourGeneratedCodeVerifier%7D&code=%7ByourAuthorizationCode%7D&redirect_uri={https://yourApp/callback}")
.asString();
```
```javascript Node.JS theme={null}
var axios = require("axios").default;
var options = {
method: 'POST',
url: 'https://{yourDomain}/oauth/token',
headers: {'content-type': 'application/x-www-form-urlencoded'},
data: new URLSearchParams({
grant_type: 'authorization_code',
client_id: '{yourClientId}',
code_verifier: '{yourGeneratedCodeVerifier}',
code: '{yourAuthorizationCode}',
redirect_uri: '{https://yourApp/callback}'
})
};
axios.request(options).then(function (response) {
console.log(response.data);
}).catch(function (error) {
console.error(error);
});
```
```php PHP theme={null}
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://{yourDomain}/oauth/token",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "grant_type=authorization_code&client_id={yourClientId}&code_verifier=%7ByourGeneratedCodeVerifier%7D&code=%7ByourAuthorizationCode%7D&redirect_uri={https://yourApp/callback}",
CURLOPT_HTTPHEADER => [
"content-type: application/x-www-form-urlencoded"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
```
```python Python theme={null}
import http.client
conn = http.client.HTTPSConnection("")
payload = "grant_type=authorization_code&client_id={yourClientId}&code_verifier=%7ByourGeneratedCodeVerifier%7D&code=%7ByourAuthorizationCode%7D&redirect_uri={https://yourApp/callback}"
headers = { 'content-type': "application/x-www-form-urlencoded" }
conn.request("POST", "/{yourDomain}/oauth/token", payload, headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
```
```ruby Ruby theme={null}
require 'uri'
require 'net/http'
require 'openssl'
url = URI("https://{yourDomain}/oauth/token")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
request = Net::HTTP::Post.new(url)
request["content-type"] = 'application/x-www-form-urlencoded'
request.body = "grant_type=authorization_code&client_id={yourClientId}&code_verifier=%7ByourGeneratedCodeVerifier%7D&code=%7ByourAuthorizationCode%7D&redirect_uri={https://yourApp/callback}"
response = http.request(request)
puts response.read_body
```
### Parameters
| Parameter Name | Description |
| - | - |
| `grant_type` | Set this to "authorization\_code". |
| `code_verifier` | The cryptographically-random key that was generated in the first step of this tutorial. |
| `code` | The `authorization_code` retrieved in the previous step of this tutorial. |
| `client_id` | Your application's Client ID. You can find this value in your [Application Settings](https://manage.auth0.com/#/Applications/\{yourClientId}/settings). |
| `redirect_uri` | The valid callback URL set in your Application settings. This must exactly match the `redirect_uri` passed to the authorization URL in the previous step of this tutorial. Note that this must be URL encoded. |
### Response
If all goes well, you'll receive an HTTP 200 response with a payload containing `access_token`, `refresh_token`, `id_token`, and `token_type` values:
```json lines theme={null}
{
"access_token":"eyJz93a...k4laUWw",
"refresh_token":"GEbRxBN...edjnXbL",
"id_token":"eyJ0XAi...4faeEoQ",
"token_type":"Bearer",
"expires_in":86400
}
```
Validate your tokens before saving them. To learn how, read [Validate ID Tokens](/docs/secure/tokens/id-tokens/validate-id-tokens) and [Validate Access Tokens](/docs/secure/tokens/access-tokens/validate-access-tokens).
[ID tokens](/docs/secure/tokens/id-tokens) contain user information that must be decoded and extracted.
[Access tokens](/docs/secure/tokens/access-tokens) are used to call the [Auth0 Authentication API's /userinfo endpoint](https://auth0.com/docs/api/authentication#get-user-info) or another API. If you are calling your own API, the first thing your API will need to do is [verify the Access token](/docs/secure/tokens/access-tokens/validate-access-tokens).
[Refresh tokens](/docs/secure/tokens/refresh-tokens) are used to obtain a new access token or ID token after the previous one has expired. The `refresh_token` will only be present in the response if you included the `offline_access` scope and enabled **Allow Offline Access** for your API in the Dashboard.
Refresh tokens must be stored securely since they allow a user to remain authenticated essentially forever.
## Use cases
### Basic authentication request
This example shows the most basic request you can make when authorizing the user in step 1. It displays the Auth0 login screen and allows the user to sign in with any of your configured connections:
Now, when you request tokens, your ID Token will contain the most basic claims. When you decode the ID Token, it will look similar to:
```json lines theme={null}
{
"iss": "https://auth0pnp.auth0.com/",
"sub": "auth0|581...",
"aud": "xvt9...",
"exp": 1478112929,
"iat": 1478076929
}
```
### Request user's name and profile picture
In addition to the usual user authentication, this example shows how to request additional user details, such as name and picture.
To request the user's name and picture, you need to add the appropriate scopes when authorizing the user:
Now, when you request tokens, your ID token will contain the requested name and picture claims. When you decode the ID token, it will look similar to:
```json lines theme={null}
{
"name": "auth0user@...",
"picture": "https://example.com/profile-pic.png",
"iss": "https://auth0user.auth0.com/",
"sub": "auth0|581...",
"aud": "xvt...",
"exp": 1478113129,
"iat": 1478077129
}
```
### Request user log in with GitHub
In addition to the usual user authentication, this example shows how to send users directly to a social identity provider, such as GitHub. For this example to work, you need to go to [Auth0 Dashboard > Authentication > Social](https://manage.auth0.com/#/connections/social) and configure the appropriate connection. Get the connection name from the **Settings** tab.
To send users directly to the GitHub login screen, you need to pass the `connection` parameter and set its value to the connection name (in this case, `github`) when authorizing the user:
Now, when you request tokens, your ID token will contain a `sub` claim with the user's unique ID returned from GitHub. When you decode the ID token, it will look similar to:
```json lines theme={null}
{
"name": "John Smith",
"picture": "https://avatars.example.com",
"email": "jsmith@...",
"email_verified": true,
"iss": "https://auth0user.auth0.com/",
"sub": "github|100...",
"aud": "xvt...",
"exp": 1478114742,
"iat": 1478078742
}
```
## Learn more
* [OAuth 2.0 Authorization Framework](/docs/authenticate/protocols/oauth)
* [OpenID Connect Protocol](/docs/authenticate/protocols/openid-connect-protocol)
* [Tokens](/docs/secure/tokens)
# Call Your API Using the Authorization Code Flow with PKCE
Source: https://auth0.com/docs/get-started/authentication-and-authorization-flow/authorization-code-flow-with-pkce/call-your-api-using-the-authorization-code-flow-with-pkce
Learn how to call your API from a native, mobile, or single-page application using the Authorization Code flow using Proof Key for Code Exchange (PKCE).
This tutorial helps you call your own API from a native, mobile, or single-page app using the Authorization Code Flow with PKCE. To learn how the flow works and why you should use it, read [Authorization Code Flow with Proof Key for Code Exchange (PKCE)](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow-with-pkce). To learn to add login to your native, mobile, or single-page app, read [Add Login Using Authorization Code Flow with PKCE](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow-with-pkce/add-login-using-the-authorization-code-flow-with-pkce).
Auth0 makes it easy for your app to implement the Authorization Code Flow with Proof Key for Code Exchange (PKCE) using:
* [Auth0 Mobile SDKs](/docs/libraries) and [Auth0 Single-Page App SDK](/docs/libraries/auth0-single-page-app-sdk): The easiest way to implement the flow, which will do most of the heavy-lifting for you. Our [Mobile Quickstarts](/docs/quickstart/native) and [Single-Page App Quickstarts](/docs/quickstart/spa) will walk you through the process.
* [Authentication API](https://auth0.com/docs/api/authentication): If you prefer to build your own solution, keep reading to learn how to call our API directly.
## Prerequisites
**Before beginning this tutorial:**
* [Register the Application with Auth0](/docs/get-started/auth0-overview/create-applications/native-apps).
* Select an **Application Type** of **Native** or **Single-Page App**, depending on your application type.
* Add an **Allowed Callback URL** of `{yourCallbackUrl}`. Your callback URL format will vary depending on your application type and platform. For details about the format for your application type and platform, see our [Native/Mobile Quickstarts](/docs/quickstart/native) and [Single-Page App Quickstarts](/docs/quickstart/spa).
* Make sure the Application's **Grant Types** include **Authorization Code**. To learn how, read [Update Grant Types](/docs/get-started/applications/update-grant-types).
* If you want your Application to be able to use Refresh Tokens, make sure the Application's **Grant Types** include **Refresh Token**. To learn how, read [Update Grant Types](/docs/get-started/applications/update-grant-types). To learn more about Refresh Tokens, read [Refresh Tokens](/docs/secure/tokens/refresh-tokens).
* [Register your API with Auth0](/docs/get-started/architecture-scenarios/mobile-api/part-2#create-the-api)
* If you want your API to receive Refresh Tokens to allow it to obtain new tokens when the previous ones expire, enable **Allow Offline Access**.
## Steps
1. [Create code verifier](#create-code-verifier):
Generate a `code_verifier` that will be sent to Auth0 to request tokens.
2. [Create code challenge](#create-code-challenge):
Generate a `code_challenge` from the `code_verifier` that will be sent to Auth0 to request an `authorization_code`.
3. [Authorize user](#authorize-user):
Request the user's authorization and redirect back to your app with an `authorization_code`.
4. [Request tokens](#request-tokens):
Exchange your `authorization_code` and `code_verifier` for tokens.
5. [Call API](#call-api):
Use the retrieved Access Token to call your API.
6. [Refresh tokens](#refresh-tokens):
Use a Refresh Token to request new tokens when the existing ones expire.
Optional: [Explore sample use cases](#sample-use-cases).
### Create code verifier
Create a `code_verifier`, which is a cryptographically-random, Base64-encoded key that will eventually be sent to Auth0 to request tokens.
#### Javascript sample
```javascript lines theme={null}
// Dependency: Node.js crypto module
// https://nodejs.org/api/crypto.html#crypto_crypto
function base64URLEncode(str) {
return str.toString('base64')
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=/g, '');
}
var verifier = base64URLEncode(crypto.randomBytes(32));
```
#### Java sample
```java lines theme={null}
// Dependency: Apache Commons Codec
// https://commons.apache.org/proper/commons-codec/
// Import the Base64 class.
// import org.apache.commons.codec.binary.Base64;
SecureRandom sr = new SecureRandom();
byte[] code = new byte[32];
sr.nextBytes(code);
String verifier = Base64.getUrlEncoder().withoutPadding().encodeToString(code);
```
#### Android sample
```kotlin lines theme={null}
// See https://developer.android.com/reference/android/util/Base64
// Import the Base64 class
// import android.util.Base64;
SecureRandom sr = new SecureRandom();
byte[] code = new byte[32];
sr.nextBytes(code);
String verifier = Base64.encodeToString(code, Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING);
```
#### Swift 5 sample
```swift lines theme={null}
var buffer = [UInt8](repeating: 0, count: 32)
_ = SecRandomCopyBytes(kSecRandomDefault, buffer.count, &buffer)
let verifier = Data(buffer).base64EncodedString()
.replacingOccurrences(of: "+", with: "-")
.replacingOccurrences(of: "/", with: "_")
.replacingOccurrences(of: "=", with: "")
```
#### Objective-C sample
```objc lines theme={null}
NSMutableData *data = [NSMutableData dataWithLength:32];
int result __attribute__((unused)) = SecRandomCopyBytes(kSecRandomDefault, 32, data.mutableBytes);
NSString *verifier = [[[[data base64EncodedStringWithOptions:0]
stringByReplacingOccurrencesOfString:@"+" withString:@"-"]
stringByReplacingOccurrencesOfString:@"/" withString:@"_"]
stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"="]];
```
### Create code challenge
Generate a `code_challenge` from the `code_verifier` that will be sent to Auth0 to request an `authorization_code`.
#### Javascript sample
```javascript lines theme={null}
// Dependency: Node.js crypto module
// https://nodejs.org/api/crypto.html#crypto_crypto
function sha256(buffer) {
return crypto.createHash('sha256').update(buffer).digest();
}
var challenge = base64URLEncode(sha256(verifier));
```
#### Java sample
```java lines theme={null}
// Dependency: Apache Commons Codec
// https://commons.apache.org/proper/commons-codec/
// Import the Base64 class.
// import org.apache.commons.codec.binary.Base64;
byte[] bytes = verifier.getBytes("US-ASCII");
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(bytes, 0, bytes.length);
byte[] digest = md.digest();
String challenge = Base64.encodeBase64URLSafeString(digest);
```
#### Swift 5 sample
```swift lines theme={null}
import CommonCrypto
// ...
guard let data = verifier.data(using: .utf8) else { return nil }
var buffer = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH))
_ = data.withUnsafeBytes {
CC_SHA256($0.baseAddress, CC_LONG(data.count), &buffer)
}
let hash = Data(buffer)
let challenge = hash.base64EncodedString()
.replacingOccurrences(of: "+", with: "-")
.replacingOccurrences(of: "/", with: "_")
.replacingOccurrences(of: "=", with: "")
```
#### Objective-C sample
```objc lines theme={null}
// Dependency: Apple Common Crypto library
// http://opensource.apple.com//source/CommonCrypto
u_int8_t buffer[CC_SHA256_DIGEST_LENGTH * sizeof(u_int8_t)];
memset(buffer, 0x0, CC_SHA256_DIGEST_LENGTH);
NSData *data = [verifier dataUsingEncoding:NSUTF8StringEncoding];
CC_SHA256([data bytes], (CC_LONG)[data length], buffer);
NSData *hash = [NSData dataWithBytes:buffer length:CC_SHA256_DIGEST_LENGTH];
NSString *challenge = [[[[hash base64EncodedStringWithOptions:0]
stringByReplacingOccurrencesOfString:@"+" withString:@"-"]
stringByReplacingOccurrencesOfString:@"/" withString:@"_"]
stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"="]];
```
### Authorize user
Once you've created the `code_verifier` and the `code_challenge`, you must get the user's authorization. This is technically the beginning of the authorization flow, and this step may include one or more of the following processes:
\* Authenticating the user;
\* Redirecting the user to an Identity Provider to handle authentication;
\* Checking for active [Single Sign-on (SSO)](/docs/authenticate/single-sign-on) sessions;
\* Obtaining user consent for the requested permission level, unless consent has been previously given.
To authorize the user, your app must send the user to the [authorization URL](https://auth0.com/docs/api/authentication#authorization-code-grant-pkce-), including the `code_challenge` you generated in the previous step and the method you used to generate the `code_challenge`.
#### Example authorization URL
##### Parameters
Note that for authorizing a user when calling a custom API, you:
* must include an audience parameter
* can include additional scopes supported by the target API
| Parameter Name | Description |
| - | - |
| `response_type` | Denotes the kind of credential that Auth0 will return (`code` or `token`). For this flow, the value must be `code`. |
| `code_challenge` | Generated challenge from the `code_verifier`. |
| `code_challenge_method` | Method used to generate the challenge (e.g., S256). The PKCE spec defines two methods, `S256` and `plain`, the former is used in this example and is the **only** one supported by Auth0 since the latter is discouraged. |
| `client_id` | Your application's Client ID. You can find this value in your [Application Settings](https://manage.auth0.com/#/Applications/\{yourClientId}/settings). |
| `redirect_uri` | The URL to which Auth0 will redirect the browser after authorization has been granted by the user. The Authorization Code will be available in the `code` URL parameter. You must specify this URL as a valid callback URL in your [Application Settings](https://manage.auth0.com/#/Applications/\{yourClientId}/settings).
**Warning:** Per the [OAuth 2.0 Specification](https://tools.ietf.org/html/rfc6749#section-3.1.2), Auth0 removes everything after the hash and does *not* honor any fragments. |
| `scope` | The [scopes](/docs/get-started/apis/scopes) for which you want to request authorization. These must be separated by a space. You can request any of the [standard OpenID Connect (OIDC) scopes](https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims) about users, such as `profile` and `email`, [custom claims](/docs/secure/tokens/json-web-tokens/json-web-token-claims#custom-claims) conforming to a [namespaced format](/docs/secure/tokens/json-web-tokens/create-custom-claims), or any scopes supported by the target API (e.g., `read:contacts`). Include `offline_access` to get a [Refresh Token](/docs/glossary?term=Refresh+Token) (make sure that the **Allow Offline Access** field is enabled in the [Application Settings](https://manage.auth0.com/#/apis)). |
| `audience` | The unique identifier of the API your mobile app wants to access. Use the **Identifier** value on the [Settings](https://manage.auth0.com/#/apis) tab for the API you created as part of the prerequisites for this tutorial. |
| `state` | (recommended) An opaque arbitrary alphanumeric string your app adds to the initial request that Auth0 includes when redirecting back to your application. To see how to use this value to prevent cross-site request forgery (CSRF) attacks, see [Mitigate CSRF Attacks With State Parameters](/docs/secure/attack-protection/state-parameters). |
| `organization` | (optional) ID of the organization to use when authenticating a user. When not provided, if your application is configured to **Display Organization Prompt**, the user will be able to enter the organization name when authenticating. |
| `invitation` | (optional) Ticket ID of the organization invitation. When [inviting a member to an Organization](/docs/manage-users/organizations/configure-organizations/invite-members), your application should handle invitation acceptance by forwarding the `invitation` and `organization` key-value pairs when the user accepts the invitation. |
As an example, your HTML snippet for your authorization URL when calling an API might look like:
#### Response
If all goes well, you'll receive an `HTTP 302` response. The authorization code is included at the end of the URL:
```http lines theme={null}
HTTP/1.1 302 Found
Location: {yourCallbackUrl}?code={authorizationCode}&state=xyzABC123
```
### Request tokens
Now that you have an Authorization Code, you must exchange it for tokens. Using the extracted Authorization Code (`code`) from the previous step, you will need to `POST` to the [token URL](https://auth0.com/docs/api/authentication#authorization-code-pkce-) sending along the `code_verifier`.
#### Example POST to token URL
```bash cURL theme={null}
curl --request POST \
--url 'https://{yourDomain}/oauth/token' \
--header 'content-type: application/x-www-form-urlencoded' \
--data grant_type=authorization_code \
--data 'client_id={yourClientId}' \
--data 'code_verifier={yourGeneratedCodeVerifier}' \
--data 'code={yourAuthorizationCode}' \
--data 'redirect_uri={https://yourApp/callback}'
```
```csharp C# theme={null}
var client = new RestClient("https://{yourDomain}/oauth/token");
var request = new RestRequest(Method.POST);
request.AddHeader("content-type", "application/x-www-form-urlencoded");
request.AddParameter("application/x-www-form-urlencoded", "grant_type=authorization_code&client_id={yourClientId}&code_verifier=%7ByourGeneratedCodeVerifier%7D&code=%7ByourAuthorizationCode%7D&redirect_uri={https://yourApp/callback}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```
```go Go theme={null}
package main
import (
"fmt"
"strings"
"net/http"
"io/ioutil"
)
func main() {
url := "https://{yourDomain}/oauth/token"
payload := strings.NewReader("grant_type=authorization_code&client_id={yourClientId}&code_verifier=%7ByourGeneratedCodeVerifier%7D&code=%7ByourAuthorizationCode%7D&redirect_uri={https://yourApp/callback}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("content-type", "application/x-www-form-urlencoded")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := ioutil.ReadAll(res.Body)
fmt.Println(res)
fmt.Println(string(body))
}
```
```java Java theme={null}
HttpResponse response = Unirest.post("https://{yourDomain}/oauth/token")
.header("content-type", "application/x-www-form-urlencoded")
.body("grant_type=authorization_code&client_id={yourClientId}&code_verifier=%7ByourGeneratedCodeVerifier%7D&code=%7ByourAuthorizationCode%7D&redirect_uri={https://yourApp/callback}")
.asString();
```
```javascript Node.JS theme={null}
var axios = require("axios").default;
var options = {
method: 'POST',
url: 'https://{yourDomain}/oauth/token',
headers: {'content-type': 'application/x-www-form-urlencoded'},
data: new URLSearchParams({
grant_type: 'authorization_code',
client_id: '{yourClientId}',
code_verifier: '{yourGeneratedCodeVerifier}',
code: '{yourAuthorizationCode}',
redirect_uri: '{https://yourApp/callback}'
})
};
axios.request(options).then(function (response) {
console.log(response.data);
}).catch(function (error) {
console.error(error);
});
```
```php PHP theme={null}
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://{yourDomain}/oauth/token",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "grant_type=authorization_code&client_id={yourClientId}&code_verifier=%7ByourGeneratedCodeVerifier%7D&code=%7ByourAuthorizationCode%7D&redirect_uri={https://yourApp/callback}",
CURLOPT_HTTPHEADER => [
"content-type: application/x-www-form-urlencoded"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
```
```python Python theme={null}
import http.client
conn = http.client.HTTPSConnection("")
payload = "grant_type=authorization_code&client_id={yourClientId}&code_verifier=%7ByourGeneratedCodeVerifier%7D&code=%7ByourAuthorizationCode%7D&redirect_uri={https://yourApp/callback}"
headers = { 'content-type': "application/x-www-form-urlencoded" }
conn.request("POST", "/{yourDomain}/oauth/token", payload, headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
```
```ruby Ruby theme={null}
require 'uri'
require 'net/http'
require 'openssl'
url = URI("https://{yourDomain}/oauth/token")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
request = Net::HTTP::Post.new(url)
request["content-type"] = 'application/x-www-form-urlencoded'
request.body = "grant_type=authorization_code&client_id={yourClientId}&code_verifier=%7ByourGeneratedCodeVerifier%7D&code=%7ByourAuthorizationCode%7D&redirect_uri={https://yourApp/callback}"
response = http.request(request)
puts response.read_body
```
##### Parameters
| Parameter Name | Description |
| - | - |
| `grant_type` | Set this to "authorization\_code". |
| `code_verifier` | The cryptographically-random key that was generated in the first step of this tutorial. |
| `code` | The `authorization_code` retrieved in the previous step of this tutorial. |
| `client_id` | Your application's Client ID. You can find this value in your [Application Settings](https://manage.auth0.com/#/Applications/\{yourClientId}/settings). |
| `redirect_uri` | The valid callback URL set in your Application settings. This must exactly match the `redirect_uri` passed to the authorization URL in the previous step of this tutorial. Note that this must be URL encoded. |
#### Response
If all goes well, you'll receive an HTTP 200 response with a payload containing `access_token`, `refresh_token`, `id_token`, and `token_type` values:
```json lines theme={null}
{
"access_token":"eyJz93a...k4laUWw",
"refresh_token":"GEbRxBN...edjnXbL",
"id_token":"eyJ0XAi...4faeEoQ",
"token_type":"Bearer",
"expires_in":86400
}
```
Validate your tokens before saving them. To learn how, read [Validate ID Tokens](/docs/secure/tokens/id-tokens/validate-id-tokens) and [Validate Access Tokens](/docs/secure/tokens/access-tokens/validate-access-tokens).
[ID tokens](/docs/secure/tokens/id-tokens) contain user information that must be decoded and extracted.
[Access tokens](/docs/secure/tokens/access-tokens) are used to call the [Auth0 Authentication API's /userinfo endpoint](https://auth0.com/docs/api/authentication#get-user-info) or another API. If you are calling your own API, the first thing your API will need to do is [verify the Access token](/docs/secure/tokens/access-tokens/validate-access-tokens).
[Refresh tokens](/docs/secure/tokens/refresh-tokens) are used to obtain a new access token or ID token after the previous one has expired. The `refresh_token` will only be present in the response if you included the `offline_access` scope and enabled **Allow Offline Access** for your API in the Dashboard.
Refresh tokens must be stored securely since they allow a user to remain authenticated essentially forever.
### Call API
To call your API from a native/mobile application, the application must pass the retrieved Access Token as a Bearer token in the Authorization header of your HTTP request.
```bash cURL lines theme={null}
curl --request GET \
--url https://myapi.com/api \
--header 'authorization: Bearer {accessToken}' \
--header 'content-type: application/json'
```
```csharp C# lines theme={null}
var client = new RestClient("https://myapi.com/api");
var request = new RestRequest(Method.GET);
request.AddHeader("content-type", "application/json");
request.AddHeader("authorization", "Bearer {accessToken}");
IRestResponse response = client.Execute(request);
```
```go Go lines expandable theme={null}
package main
import (
"fmt"
"net/http"
"io/ioutil"
)
func main() {
url := "https://myapi.com/api"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("content-type", "application/json")
req.Header.Add("authorization", "Bearer {accessToken}")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := ioutil.ReadAll(res.Body)
fmt.Println(res)
fmt.Println(string(body))
}
```
```java Java lines theme={null}
HttpResponse response = Unirest.get("https://myapi.com/api")
.header("content-type", "application/json")
.header("authorization", "Bearer {accessToken}")
.asString();
```
```javascript Node.JS lines theme={null}
var axios = require("axios").default;
var options = {
method: 'GET',
url: 'https://myapi.com/api',
headers: {'content-type': 'application/json', authorization: 'Bearer {accessToken}'}
};
axios.request(options).then(function (response) {
console.log(response.data);
}).catch(function (error) {
console.error(error);
});
```
```php PHP lines expandable theme={null}
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://myapi.com/api",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"authorization: Bearer {accessToken}",
"content-type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
```
```python Python lines theme={null}
import http.client
conn = http.client.HTTPSConnection("myapi.com")
headers = {
'content-type': "application/json",
'authorization': "Bearer {accessToken}"
}
conn.request("GET", "/api", headers=headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
```
```ruby Ruby lines theme={null}
require 'uri'
require 'net/http'
require 'openssl'
url = URI("https://myapi.com/api")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
request = Net::HTTP::Get.new(url)
request["content-type"] = 'application/json'
request["authorization"] = 'Bearer {accessToken}'
response = http.request(request)
puts response.read_body
```
### Refresh tokens
You have already received a [refresh token](/docs/secure/tokens/refresh-tokens) if you've been following this tutorial and completed the following:
* configured your API to allow offline access
* included the `offline_access` scope when you initiated the authentication request through the [authorize endpoint](https://auth0.com/docs/api/authentication/reference#authorize-application).
You can use the Refresh Token to get a new access token. Usually, a user will need a new access token only after the previous one expires or when gaining access to a new resource for the first time. It's bad practice to call the endpoint to get a new access token every time you call an API, and Auth0 maintains rate limits that will throttle the amount of requests to the endpoint that can be executed using the same token from the same IP.
To refresh your token, make a `POST` request to the `/oauth/token` endpoint in the Authentication API, using `grant_type=refresh_token`.
#### Example POST to token URL
```bash cURL theme={null}
curl --request POST \
--url 'https://{yourDomain}/oauth/token' \
--header 'content-type: application/x-www-form-urlencoded' \
--data grant_type=refresh_token \
--data 'client_id={yourClientId}' \
--data 'refresh_token={yourRefreshToken}'
```
```csharp C# theme={null}
var client = new RestClient("https://{yourDomain}/oauth/token");
var request = new RestRequest(Method.POST);
request.AddHeader("content-type", "application/x-www-form-urlencoded");
request.AddParameter("application/x-www-form-urlencoded", "grant_type=refresh_token&client_id={yourClientId}&refresh_token=%7ByourRefreshToken%7D", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```
```go Go theme={null}
package main
import (
"fmt"
"strings"
"net/http"
"io/ioutil"
)
func main() {
url := "https://{yourDomain}/oauth/token"
payload := strings.NewReader("grant_type=refresh_token&client_id={yourClientId}&refresh_token=%7ByourRefreshToken%7D")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("content-type", "application/x-www-form-urlencoded")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := ioutil.ReadAll(res.Body)
fmt.Println(res)
fmt.Println(string(body))
}
```
```java Java theme={null}
HttpResponse response = Unirest.post("https://{yourDomain}/oauth/token")
.header("content-type", "application/x-www-form-urlencoded")
.body("grant_type=refresh_token&client_id={yourClientId}&refresh_token=%7ByourRefreshToken%7D")
.asString();
```
```javascript Node.JS theme={null}
var axios = require("axios").default;
var options = {
method: 'POST',
url: 'https://{yourDomain}/oauth/token',
headers: {'content-type': 'application/x-www-form-urlencoded'},
data: new URLSearchParams({
grant_type: 'refresh_token',
client_id: '{yourClientId}',
refresh_token: '{yourRefreshToken}'
})
};
axios.request(options).then(function (response) {
console.log(response.data);
}).catch(function (error) {
console.error(error);
});
```
```php PHP theme={null}
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://{yourDomain}/oauth/token",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "grant_type=refresh_token&client_id={yourClientId}&refresh_token=%7ByourRefreshToken%7D",
CURLOPT_HTTPHEADER => [
"content-type: application/x-www-form-urlencoded"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
```
```python Python theme={null}
import http.client
conn = http.client.HTTPSConnection("")
payload = "grant_type=refresh_token&client_id={yourClientId}&refresh_token=%7ByourRefreshToken%7D"
headers = { 'content-type': "application/x-www-form-urlencoded" }
conn.request("POST", "/{yourDomain}/oauth/token", payload, headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
```
```ruby Ruby theme={null}
require 'uri'
require 'net/http'
require 'openssl'
url = URI("https://{yourDomain}/oauth/token")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
request = Net::HTTP::Post.new(url)
request["content-type"] = 'application/x-www-form-urlencoded'
request.body = "grant_type=refresh_token&client_id={yourClientId}&refresh_token=%7ByourRefreshToken%7D"
response = http.request(request)
puts response.read_body
```
##### Parameters
| Parameter Name | Description |
| - | - |
| `grant_type` | Set this to `refresh_token`. |
| `client_id` | Your application's Client ID. You can find this value in your [Application Settings](https://manage.auth0.com/#/Applications/\{yourClientId}/settings). |
| `refresh_token` | The refresh token to use. |
| `scope` | (optional) A space-delimited list of requested scope permissions. If not sent, the original scopes will be used; otherwise you can request a reduced set of scopes. Note that this must be URL encoded. |
#### Response
If all goes well, you'll receive an `HTTP 200` response with a payload containing a new `access_token`, its lifetime in seconds (`expires_in`), granted `scope` values, and `token_type`. If the scope of the initial token included `openid`, then the response will also include a new `id_token`:
```json lines theme={null}
{
"access_token": "eyJ...MoQ",
"expires_in": 86400,
"scope": "openid offline_access",
"id_token": "eyJ...0NE",
"token_type": "Bearer"
}
```
Validate your tokens before saving them. To learn how, read [Validate ID Tokens](/docs/secure/tokens/id-tokens/validate-id-tokens) and [Validate Access Tokens](/docs/secure/tokens/access-tokens/validate-access-tokens).
### Sample use cases
#### Customize tokens
You can use Actions to change the returned scopes of Access Tokens and/or add claims to Access and ID Tokens. (To learn more about Actions, read [Auth0 Actions](/docs/customize/actions). ) To do so, add the following Action, which will run after the user authenticates:
```js lines theme={null}
exports.onExecutePostLogin = async (event, api) => {
// Add custom claims to Access Token and ID Token
api.accessToken.setCustomClaim('https://foo/bar', 'value');
api.idToken.setCustomClaim('https://fiz/baz', 'some other value');
// Modify the scope of the Access Token
api.accessToken.addScope('foo');
api.accessToken.addScope('bar');
};
```
Scopes will be available in the token after the Action has run.
Auth0 returns profile information in a structured claim format as defined by the [OpenID Connect (OIDC) specification](https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims). This means that custom claims added to ID tokens or access tokens must [conform to guidelines and restrictions](/docs/secure/tokens/json-web-tokens/create-custom-claims) to avoid possible collisions.
#### View Sample Application: Mobile App + API
For a sample implementation, see the [Mobile + API](/docs/get-started/architecture-scenarios/mobile-api) architecture scenario. This series of tutorials is accompanied by a [code sample that you can access in GitHub](https://github.com/auth0-samples/auth0-pnp-exampleco-timesheets).
## Learn more
* [OAuth 2.0 Authorization Framework](/docs/authenticate/protocols/oauth)
* [OpenID Connect Protocol](/docs/authenticate/protocols/openid-connect-protocol)
* [Tokens](/docs/secure/tokens)
# Add Login Using the Authorization Code Flow
Source: https://auth0.com/docs/get-started/authentication-and-authorization-flow/authorization-code-flow/add-login-auth-code-flow
Learn how to add login to your regular web application using the Authorization Code Flow.
You can add login to your regular web application using the Authorization Code Flow. To learn how the flow works and why you should use it, read [Authorization Code Flow](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow). To call your API from a regular web app, read [Call Your API Using the Authorization Code Flow](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow/call-your-api-using-the-authorization-code-flow).
To implement the Authorization Code Flow, Auth0 provides the following resources:
* [Regular Web App Quickstarts](/docs/quickstart/webapp): The easiest way to implement the flow.
* [Authentication API](https://auth0.com/docs/api/authentication): If you prefer to build your own solution, keep reading to learn how to call our API directly.
Following a successful login, your application will have access to the user's ID token and access token. The ID token contains basic user profile information, and the access token can be used to call the Auth0 `/userinfo` endpoint or your own protected APIs. To learn more about ID tokens, read [ID Tokens](/docs/secure/tokens/id-tokens). To learn more about access tokens, read [Access Tokens](/docs/secure/tokens/access-tokens).
You will request the user's authorization and redirect back to your app with an `authorization_code`. Then you will exchange the code for tokens.
## Prerequisites
Register your app with Auth0. To learn more, read [Register Regular Web Applications](/docs/get-started/auth0-overview/create-applications/regular-web-apps).
* Select **Regular Web App** as the **Application Type**.
* Add an **Allowed Callback URL** of `{https://yourApp/callback}`.
* Make sure your application's **Grant Types** include **Authorization Code**. To learn more, read [Update Grant Types](/docs/get-started/applications/update-grant-types).
## Authorize user
To begin the flow, you'll need to get the user's authorization. This step may include one or more of the following processes:
* Authenticating the user;
* Redirecting the user to an Identity Provider to handle authentication;
* Obtaining user consent for the requested permission level, unless consent has been previously given.
To authorize the user, your app must send the user to the [authorization URL](https://auth0.com/docs/api/authentication#authorization-code-flow).
### Authorization URL example
### Parameters
| Parameter Name | Description |
| - | - |
| `response_type` | Denotes the kind of credential that Auth0 will return (`code` or `token`). For this flow, the value must be `code`. |
| `client_id` | Your application's Client ID. You can find this value in your [Application Settings](https://manage.auth0.com/#/Applications/\{yourClientId}/settings). |
| `redirect_uri` | The URL to which Auth0 will redirect the browser after authorization has been granted by the user. The Authorization Code will be available in the `code` URL parameter. You must specify this URL as a valid callback URL in your [Application Settings](https://manage.auth0.com/#/Applications/\{yourClientId}/settings).
**Warning:** Per the [OAuth 2.0 Specification](https://tools.ietf.org/html/rfc6749#section-3.1.2), Auth0 removes everything after the hash and does *not* honor any fragments. |
| `scope` | Specifies the [scopes](/docs/get-started/apis/scopes) for which you want to request authorization, which dictate which claims (or user attributes) you want returned. These must be separated by a space. To get an ID Token in the response, you need to specify a scope of at least `openid`. If you want to return the user's full profile, you can request `openid profile`. You can request any of the [standard OpenID Connect (OIDC) scopes](https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims) about users, such as `email`, or [custom claims](/docs/secure/tokens/json-web-tokens/json-web-token-claims#custom-claims) conforming to a [namespaced format](/docs/secure/tokens/json-web-tokens/create-custom-claims). Include `offline_access` to get a [Refresh Token](/docs/glossary?term=Refresh+Token) (make sure that the **Allow Offline Access** field is enabled in the [Application Settings](https://manage.auth0.com/#/applications)). |
| `state` | (recommended) An opaque arbitrary alphanumeric string your app adds to the initial request that Auth0 includes when redirecting back to your application. To see how to use this value to prevent cross-site request forgery (CSRF) attacks, see [Mitigate CSRF Attacks With State Parameters](/docs/secure/attack-protection/state-parameters). |
| `connection` | (optional) Forces the user to sign in with a specific connection. For example, you can pass a value of `github` to send the user directly to GitHub to log in with their GitHub account. When not specified, the user sees the Auth0 Lock screen with all configured connections. You can see a list of your configured connections on the **Connections** tab of your application. |
| `organization` | (optional) ID of the organization to use when authenticating a user. When not provided, if your application is configured to **Display Organization Prompt**, the user will be able to enter the organization name when authenticating. |
| `invitation` | (optional) Ticket ID of the organization invitation. When [inviting a member to an Organization](/docs/manage-users/organizations/configure-organizations/invite-members), your application should handle invitation acceptance by forwarding the `invitation` and `organization` key-value pairs when the user accepts the invitation. |
| `login_hint` | (optional) Populates the username/email field for the login or signup page when redirecting to Auth0. Supported by the Universal Login experience. |
As an example, your HTML snippet for your authorization URL when adding login to your app might look like:
### Response
If all goes well, you'll receive an `HTTP 302` response. The authorization code is included at the end of the URL:
```http lines theme={null}
HTTP/1.1 302 Found
Location: {https://yourApp/callback}?code={authorizationCode}&state=xyzABC123
```
## Request tokens
Now that you have an Authorization Code, you must exchange it for tokens. Using the extracted Authorization Code (`code`) from the previous step, you will need to `POST` to the [token URL](https://auth0.com/docs/api/authentication#authorization-code).
### POST to token URL example
```bash cURL theme={null}
curl --request POST \
--url 'https://{yourDomain}/oauth/token' \
--header 'content-type: application/x-www-form-urlencoded' \
--data grant_type=authorization_code \
--data 'client_id={yourClientId}' \
--data 'client_secret={yourClientSecret}' \
--data 'code=yourAuthorizationCode}' \
--data 'redirect_uri={https://yourApp/callback}'
```
```csharp C# theme={null}
var client = new RestClient("https://{yourDomain}/oauth/token");
var request = new RestRequest(Method.POST);
request.AddHeader("content-type", "application/x-www-form-urlencoded");
request.AddParameter("application/x-www-form-urlencoded", "grant_type=authorization_code&client_id={yourClientId}&client_secret=%7ByourClientSecret%7D&code=yourAuthorizationCode%7D&redirect_uri={https://yourApp/callback}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```
```go Go theme={null}
package main
import (
"fmt"
"strings"
"net/http"
"io/ioutil"
)
func main() {
url := "https://{yourDomain}/oauth/token"
payload := strings.NewReader("grant_type=authorization_code&client_id={yourClientId}&client_secret=%7ByourClientSecret%7D&code=yourAuthorizationCode%7D&redirect_uri={https://yourApp/callback}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("content-type", "application/x-www-form-urlencoded")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := ioutil.ReadAll(res.Body)
fmt.Println(res)
fmt.Println(string(body))
}
```
```java Java theme={null}
HttpResponse response = Unirest.post("https://{yourDomain}/oauth/token")
.header("content-type", "application/x-www-form-urlencoded")
.body("grant_type=authorization_code&client_id={yourClientId}&client_secret=%7ByourClientSecret%7D&code=yourAuthorizationCode%7D&redirect_uri={https://yourApp/callback}")
.asString();
```
```javascript Node.JS theme={null}
var axios = require("axios").default;
var options = {
method: 'POST',
url: 'https://{yourDomain}/oauth/token',
headers: {'content-type': 'application/x-www-form-urlencoded'},
data: new URLSearchParams({
grant_type: 'authorization_code',
client_id: '{yourClientId}',
client_secret: '{yourClientSecret}',
code: 'yourAuthorizationCode}',
redirect_uri: '{https://yourApp/callback}'
})
};
axios.request(options).then(function (response) {
console.log(response.data);
}).catch(function (error) {
console.error(error);
});
```
```php PHP theme={null}
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://{yourDomain}/oauth/token",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "grant_type=authorization_code&client_id={yourClientId}&client_secret=%7ByourClientSecret%7D&code=yourAuthorizationCode%7D&redirect_uri={https://yourApp/callback}",
CURLOPT_HTTPHEADER => [
"content-type: application/x-www-form-urlencoded"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
```
```python Python theme={null}
import http.client
conn = http.client.HTTPSConnection("")
payload = "grant_type=authorization_code&client_id={yourClientId}&client_secret=%7ByourClientSecret%7D&code=yourAuthorizationCode%7D&redirect_uri={https://yourApp/callback}"
headers = { 'content-type': "application/x-www-form-urlencoded" }
conn.request("POST", "/{yourDomain}/oauth/token", payload, headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
```
```ruby Ruby theme={null}
require 'uri'
require 'net/http'
require 'openssl'
url = URI("https://{yourDomain}/oauth/token")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
request = Net::HTTP::Post.new(url)
request["content-type"] = 'application/x-www-form-urlencoded'
request.body = "grant_type=authorization_code&client_id={yourClientId}&client_secret=%7ByourClientSecret%7D&code=yourAuthorizationCode%7D&redirect_uri={https://yourApp/callback}"
response = http.request(request)
puts response.read_body
```
### Parameters
| Parameter Name | Description |
| - | - |
| `grant_type` | Set this to `authorization_code`. |
| `code` | The `authorization_code` retrieved in the previous step of this tutorial. |
| `client_id` | Your application's Client ID. You can find this value in your [Application Settings](https://manage.auth0.com/#/Applications/\{yourClientId}/settings). |
| `client_secret` | Your application's Client Secret. You can find this value in your [Application Settings](https://manage.auth0.com/#/Applications/\{yourClientId}/settings). To learn more about available application authentication methods, read [Application Credentials](/docs/secure/application-credentials). |
| `redirect_uri` | The valid callback URL set in your Application settings. This must exactly match the `redirect_uri` passed to the authorization URL in the previous step of this tutorial. Note that this must be URL encoded. |
### Response
If all goes well, you'll receive an HTTP 200 response with a payload containing `access_token`, `refresh_token`, `id_token`, and `token_type` values:
```json lines theme={null}
{
"access_token": "eyJz93a...k4laUWw",
"refresh_token": "GEbRxBN...edjnXbL",
"id_token": "eyJ0XAi...4faeEoQ",
"token_type": "Bearer"
}
```
Validate your tokens before saving them. To learn how, read [Validate ID Tokens](/docs/secure/tokens/id-tokens/validate-id-tokens) and [Validate Access Tokens](/docs/secure/tokens/access-tokens/validate-access-tokens).
[ID tokens](/docs/secure/tokens/id-tokens) contain user information that must be decoded and extracted.
[Access tokens](/docs/secure/tokens/access-tokens) are used to call the [Auth0 Authentication API's /userinfo endpoint](https://auth0.com/docs/api/authentication#get-user-info) or another API. If you are calling your own API, the first thing your API will need to do is [verify the Access token](/docs/secure/tokens/access-tokens/validate-access-tokens).
[Refresh tokens](/docs/secure/tokens/refresh-tokens) are used to obtain a new access token or ID token after the previous one has expired. The `refresh_token` will only be present in the response if you included the `offline_access` scope and enabled **Allow Offline Access** for your API in the Dashboard.
Refresh tokens must be stored securely since they allow a user to remain authenticated essentially forever.
## Use cases
### Basic authentication request
This example shows the most basic request you can make when authorizing the user in step 1. It displays the Auth0 login screen and allows the user to sign in with any of your configured connections:
Now, when you request tokens, your ID Token will contain the most basic claims. When you decode the ID Token, it will look similar to:
```json lines theme={null}
{
"iss": "https://auth0pnp.auth0.com/",
"sub": "auth0|581...",
"aud": "xvt9...",
"exp": 1478112929,
"iat": 1478076929
}
```
### Request user's name and profile picture
In addition to the usual user authentication, this example shows how to request additional user details, such as name and picture.
To request the user's name and picture, you need to add the appropriate scopes when authorizing the user:
Now, when you request tokens, your ID token will contain the requested name and picture claims. When you decode the ID token, it will look similar to:
```json lines theme={null}
{
"name": "jerrie@...",
"picture": "https://s.gravatar.com/avatar/6222081fd7dcea7dfb193788d138c457?s=480&r=pg&d=https%3A%2F%2Fcdn.auth0.com%2Favatars%2Fje.png",
"iss": "https://auth0pnp.auth0.com/",
"sub": "auth0|581...",
"aud": "xvt...",
"exp": 1478113129,
"iat": 1478077129
}
```
### Request user log in with GitHub
In addition to the usual user authentication, this example shows how to send users directly to a social identity provider, such as GitHub. You will first need to configure the appropriate connection in [Auth0 Dashboard > Authentication > Social](https://manage.auth0.com/#/connections/social) and get the connection name from the **Settings** tab.
To send users directly to the GitHub login screen, you need to pass the `connection` parameter and set its value to the connection name (in this case, `github`) when authorizing the user in step 1:
Now, when you request tokens, your ID Token will contain a `sub` claim with the user's unique ID returned from GitHub. When you decode the ID token, it will look similar to:
```json lines theme={null}
{
"name": "Jerrie Pelser",
"nickname": "jerriep",
"picture": "https://avatars.githubusercontent.com/u/1006420?v=3",
"iss": "https://auth0pnp.auth0.com/",
"sub": "github|100...",
"aud": "xvt...",
"exp": 1478114742,
"iat": 1478078742
}
```
## Learn more
* [OAuth 2.0 Authorization Framework](/docs/authenticate/protocols/oauth)
* [OpenID Connect Protocol](/docs/authenticate/protocols/openid-connect-protocol)
* [Tokens](/docs/secure/tokens)
* [Register Regular Web Applications](/docs/get-started/auth0-overview/create-applications/regular-web-apps)
* [Update Grant Types](/docs/get-started/applications/update-grant-types)
# Authorization Code Flow with JWT-Secured Authorization Requests (JAR)
Source: https://auth0.com/docs/get-started/authentication-and-authorization-flow/authorization-code-flow/authorization-code-flow-with-jar
Learn how to use JWT-Secured Authorization Requests (JAR) with the Authorization Code Flow.
To use Highly Regulated Identity features, you must have an Enterprise Plan with the Highly Regulated Identity add-on. Refer to [Auth0 Pricing](https://auth0.com/pricing/) for details.
[JWT-Secured Authorization Request (JAR)](https://datatracker.ietf.org/doc/html/rfc9101) is an extension of the OAuth 2.0 protocol that protects the integrity and authenticity of authorization request parameters. By wrapping parameters in a signed [JSON Web Token (JWT)](/docs/secure/tokens/json-web-tokens), you prevent intermediaries from tampering with or viewing sensitive request data.
## Prerequisites
Before using JAR, you must:
1. [Generate a RSA key pair](/docs/secure/application-credentials/generate-rsa-key-pair)
2. Register the public key by uploading it to the Auth0 Dashboard as described in [Configure JWT-Secured Authorization Requests](/docs/get-started/applications/configure-jar)
## How it works
Instead of passing parameters like `scope` or `redirect_uri` as plain text in a URL, the client application wraps them into a signed [JSON Web Token (JWT)](/docs/secure/tokens/json-web-tokens) as the request object:
* Signing: The client application signs the JWT using its private key.
* Verification: The Auth0 Authorization Server receives the JWT and verifies the signature using the public key you registered.
* Processing: If valid, the Auth0 Authorization Server extracts the parameters. If a parameter exists in both the JAR and the query string, the value inside the JAR takes precedence.
## Generate the JAR request
Use the [Auth0 JWT library](https://jwt.io/libraries) to generate a JWT in your preferred language.
### Header
The JWT header tells Auth0 which key and algorithm to use for verification. It must have the following parameters:
* `alg`: The algorithm used to sign the JWT. Must be either RS256, RS384, or PS256.
* `typ`: The type of JWT. Must be either `jwt` or `oauth-authz-req+jwt`.
The header may also contain a `kid` field that identifies the key used to sign the JWT. If a `kid` is present, Auth0 will look for a public key registered during [JAR configuration](/docs/get-started/applications/configure-jar) that has a matching key ID and use that key to verify the JWT’s signature.
### Payload
The payload contains the authorization parameters. It must contain the following claims:
* `iss`: This must contain your app’s `client_id`
* `aud`: This must be your tenant’s domain, with the protocol and a trailing forward slash. For example, `https://{YOUR_DOMAIN}.auth0.com/`
The JWT must also contain any mandatory parameters for the call to `/authorize`. For example:
* `client_id`: This must also contain your app’s `client_id`
* `response_type`: Indicates to Auth0 which OAuth 2.0 flow you want to perform. Use `code` for Authorization Code Grant Flow.
The JWT may contain any of the optional parameters for the authorization flow that is being requested, such as `audience`, `scope`, `state`, `redirect_uri`, among others.
In addition, the JWT may contain the following optional claims:
* `iat`: Must be a numeric date.
* `nbf`: Must be a numeric date, representing a time in the past.
* `exp`: Must be a numeric date, representing a time in the future.
* `jti`: Must be a string no longer than 64 bytes.
## Code sample: Generate and sign JAR
The following Node.js example uses the [jsonwebtoken library](https://www.npmjs.com/package/jsonwebtoken?activeTab=readme) to generate and sign a JAR:
```javascript lines expandable theme={null}
const jwt = require('jsonwebtoken');
const crypto = require("crypto");
const fs = require('fs');
const privateKey = fs.readFileSync('{PATH_TO_YOUR_PEM_FILE}');
const client_id = '{YOUR_CLIENT_ID}';
const nonce = crypto.randomBytes(16).toString('hex');
const requestObject = jwt.sign(
{
iss: client_id,
aud: 'https://your_tenant.auth0.com/', // your tenant's domain
client_id,
response_type: "code",
scope: "openid profile",
redirect_uri : "https://myapp.com/callback", // your app's callback URL
nonce
},
privateKey,
{
keyid: '{YOUR_KID}', // optional key id (kid) value from your public key
algorithm: 'RS256',
header: {
typ: 'oauth-authz-req+jwt',
},
});
console.log(requestObject);
```
## Call the authorization endpoint
You can send the JAR to the Auth0 Authorization Server in the following ways:
1. [Standard JAR request](#standard-jar-request): Pass the signed JWT as a URL-encoded string in the request parameter.
2. [Pushed Authorization Request](#pushed-authorization-request): For enhanced security and to avoid URL length constraints, use PAR.
### Standard JAR request
To call the `/authorize` endpoint using a standard JAR request:
1. Open a new browser window.
2. Pass your client ID as the `client_id` parameter and the signed and URL-encoded JWT as the `request` parameter.
```bash lines theme={null}
# MacOS
open "https://{YOUR_DOMAIN}.auth0.com/authorize?client_id={YOUR_CLIENT_ID}&request={URL_ENCODED_JWT}"
# Windows
explorer "https://{YOUR_DOMAIN}.auth0.com/authorize?client_id={YOUR_CLIENT_ID}&request={URL_ENCODED_JWT}"
```
### Pushed Authorization Request
To call the `/authorize` endpoint with a pushed authorization request:
1. Send the JAR to the `/oauth/par` endpoint via a back-channel `POST` request.
2. Auth0 will return a `request_uri`, which you can then use to call the `/authorize` endpoint as in a [regular PAR flow](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow/authorization-code-flow-with-par).
The following cURL request uses PAR and JAR together:
```bash lines theme={null}
curl --location 'https://{YOUR_DOMAIN}.auth0.com/oauth/par' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id={YOUR_CLIENT_ID}' \
--data-urlencode 'client_secret={YOUR_CLIENT_SECRET}' \
--data-urlencode 'request={JWT}'
```
## Learn more
* [Configure JWT-secured Authorization Requests (JAR)](/docs/get-started/applications/configure-jar)
# Authorization Code Flow with Pushed Authorization Requests (PAR)
Source: https://auth0.com/docs/get-started/authentication-and-authorization-flow/authorization-code-flow/authorization-code-flow-with-par
Learn how to use Pushed Authorization Requests (PAR) with the Authorization Code Flow.
To use Highly Regulated Identity features, you must have an Enterprise Plan with the Highly Regulated Identity add-on. Refer to [Auth0 Pricing](https://auth0.com/pricing/) for details.
[Pushed Authorization Request (PAR)](https://datatracker.ietf.org/doc/html/rfc9126) is a backend protocol to push authorization requests directly to the authorization server. It is a technical component of the [Financial-Grade API (FAPI) Security Profile 1.0](https://openid.net/specs/openid-financial-api-part-2-1_0.html) tasked with protecting APIs in high-value scenarios.
## How it works
PAR allows your application to push the parameters for OAuth 2.0 authorization requests directly to the authorization server’s PAR endpoint **(1)**. In response, the authorization server sends a request URI value, `request_uri` **(2)**, to use when you call the `/authorize` endpoint **(3)**. The `request_uri` is a reference to the stored authorization requests at the `/par` endpoint so these requests are not exposed **(4)**. To learn more, read [Configure Push Authorization Requests](/docs/get-started/applications/configure-par).
## Benefits
One benefit of using PAR is early validation. In other OAuth 2.0 flows, such as the [Authorization Code Flow](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow), end users are redirected to the authorization server for validation. In PAR, request parameters are validated at the beginning of the authorization request before the end user is redirected. It is not ideal to redirect users to show them an error page.
PAR also passes authorization requests on the back channel. Front-channel communications rely on an intermediary (e.g. a browser) via appended HTTPS query parameters (GET, POST). Messages are not sent directly. Back-channel communications are passed in the body of an authenticated backend request for a more direct approach.
Push authorization requests travel via the back-channel, which means:
* The authorization server can trust where the request is coming from, and the requests have not been modified by an end user.
* The request details have not been exposed at the browser bar or history and privacy is preserved at that point of the chain.
* Restrictions on URL length are not a constraint.
## Limitations
* Maximum request payload size is limited to 10 KB.
* Public applications are not currently supported. To learn more, read [Public and Confidential Applications](/docs/get-started/applications/confidential-and-public-applications).
## Call the PAR endpoint
### Requirements
To make a call to the PAR endpoint, you must:
* Set the request content type as `application/x-www-form-urlencoded`.
* Use strings for all passed parameters.
* Include an additional parameter for the application authentication method in the request. Only confidential clients support PAR, so the following [application authentication methods](https://auth0.com/docs/api/authentication#authentication-methods) are available: Client Secret, Private Key JWT, and mTLS. You must use the same application authentication method for the `/token` endpoint when retrieving an access token.
### Supported parameters
PAR endpoint only stores and processes:
* Standard OAuth 2.0 parameters and applicable extensions, which we recognize at the authorization endpoint.
* Up to 10 custom authorization parameters prefixed with `ext-` prefix.
PAR ignores additional custom authorization parameters. Custom authorization parameters are not available in [Auth0 Actions](/docs/customize/actions) and [Logs](/docs/deploy-monitor/logs).
If you use custom authorization parameters in Actions, you must prefix them with `ext-`. Otherwise, they will not be available.
### Example PAR request
```bash lines theme={null}
curl --location --request POST https://$tenant/oauth/par \
-H "content-type: application/x-www-form-urlencoded" \
-d "client_id=CLIENT_ID"\
"&client_secret=CLIENT_SECRET"\
"&redirect_uri=https://jwt.io"\
"&audience=urn:my-notes-api"\
"&scope=openid%20profile%20read:notes"\
"&response_type=code"
```
### Example PAR Response
In the following example PAR response:
* The `request_uri` is a reference for the stored authorization requests. The request values pass to the GET `/authorize` endpoint as the `request_uri` parameter.
* The `expires_in` is the number of seconds the `request_uri` is valid. After this time frame, the `request_uri` expires if not used. The thirty-second expiration time is a static value and can’t be configured.
```json lines theme={null}
HTTP/1.1 201 Created
Content-Type: application/json
{
"request_uri":
"urn:ietf:params:oauth:request_uri:6esc_11ACC5bwc014ltc14eY22c",
"expires_in": 30
}
```
### Rate limits
For Essential, Professional, and Enterprise production tenants, calls to the PAR endpoint are included in the standard Authentication API rate limit. For more information, see [Rate Limit Configurations](/docs/troubleshoot/customer-support/operational-policies/rate-limit-policy/rate-limit-configurations) and click your subscription type. Then, click **Authentication API**.
## Call the authorization endpoint
Your application uses the `request_uri` value returned from the `/oauth/par` endpoint in the authorization request and redirects the user agent to the authorization endpoint. To learn more about the `request_uri` parameter, read [Configure Push Authorization Requests](/docs/get-started/applications/configure-par).
The following example directs the user agent to make the following HTTP request:
```http wrap lines theme={null}
GET /authorize?client_id=CLIENT_ID&request_uri=urn%3Aietf%3Aparam...qrwSI HTTP/1.1 Host: TENANT.auth0.com
```
In the case of a valid `request_uri`, the rest of the authorization flow looks the same.
### Validation
* PAR is validated by the authorization server at this stage again like any other authorization request.
* `request_uri` value can be used only one time.
* An expired `request_uri` will be rejected by the authorization server.
* A non-PAR request is rejected if PAR is required either on the tenant or client level.
## Learn more
* [Configure Pushed Authorization Requests (PAR)](/docs/get-started/applications/configure-par)
# Authorization Code Flow with Rich Authorization Requests (RAR)
Source: https://auth0.com/docs/get-started/authentication-and-authorization-flow/authorization-code-flow/authorization-code-flow-with-rar
Learn how to use Rich Authorization Requests (RAR) with the Authorization Code Flow.
Using [Rich Authorization Requests (RAR)](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-rar), clients can request and obtain fine-grained authorization data from resource owners, such as end users. Clients can pass RAR data to the Pushed Authorization Request (PAR) endpoint as part of the Authorization Code Flow. To learn more, read [Configure Pushed Authorization Requests](/docs/get-started/applications/configure-par).
In a traditional OAuth 2.0 flow, when a client requests access to a resource server using [scopes](/docs/get-started/apis/scopes), the resource owner grants the client access to those resources. In a Rich Authorization Request, clients can pass an `authorization_details` parameter to the `/par` endpoint to request more granular permissions than those requested in scopes. This allows for more fine-grained control over resource access for both clients and resource owners, mitigating security risks associated with over-provisioning access.
Because Auth0 only supports validating `authorization_details` types, you must implement validation for the JSON objects in `authorization_details`. To learn more, read [Configure Rich Authorization Requests](/docs/get-started/apis/configure-rich-authorization-requests).
## How it works
In a Rich Authorization Request, the `authorization_details` parameter is a JSON array of objects, each of which must include a `type` field represented as a string. The `type` field determines the customizable object fields. An `authorization_details` array may contain multiple entries of the same type. To learn more about how to register `authorization_details` types, read [Configure Rich Authorization Requests](/docs/get-started/apis/configure-rich-authorization-requests).
Auth0 presents the `authorization_details` to the user to authorize in a custom consent screen. To learn more, read [Set customized consent prompt](/docs/get-started/apis/configure-rich-authorization-requests#set-customized-consent-prompt).
You must pass the `authorization_details` parameter to the `/par` endpoint, which enables the Auth0 Authorization Server to perform early validation of the `type`. The `/par` endpoint passes authorization requests on the back channel to avoid sensitive data leaking in the front channel, such as the browser. Once you’ve passed the authorization request to the `/par` endpoint, the application will redirect to the `/authorize` endpoint and then proceed with the Authorization Code Flow. To learn more, read [Authorization Code Flow with PAR](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow/authorization-code-flow-with-par).
To complete the Authorization Code Flow, exchange the authorization code at the `/oauth/token` endpoint, as in the following example:
```http lines theme={null}
POST https://{YOUR_DOMAIN}.auth0.com/oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&client_id={YOUR_CLIENT_ID}&client_secret={YOUR_CLIENT_SECRET}&code={AUTHORIZATION_CODE}&redirect_uri=https://jwt.io
```
When successful, you should receive a response with the access token and `authorization_details` array:
```json lines theme={null}
{
"access_token": "ey...ZQ",
"expires_in": 86400,
"authorization_details": [
{
"type": "money_transfer",
"instructedAmount": {"amount": 2500, "currency": "USD"},
"sourceAccount": "xxxxxxxxxxx1234",
"destinationAccount": "xxxxxxxxxxx9876",
"beneficiary": "Hanna Herwitz",
"subject": "A Lannister Always Pays His Debts"
}
],
"token_type": "Bearer"
}
```
As part of [JWT best practices](https://datatracker.ietf.org/doc/html/rfc9068#name-privacy-considerations), the client can use `authorization_details` to understand the scope of the authorization granted to it without having to inspect the access token. If the requested audience is an API that requires [JWE access tokens](/docs/secure/tokens/json-web-tokens), the `/oauth/token`endpoint returns a response that omits all object fields except for `type` from `authorization_details`. Access token claims are unaffected in the response.
```json lines theme={null}
{
"iss": "https://my_tenant.auth0.com/",
"sub": "auth0|me",
"aud": "https://myapi.authzero.com",
"iat": 1683661385,
"exp": 1683747785,
"azp": "my_client",
"authorization_details": [
{
"type": "money_transfer",
"instructedAmount": {"amount": 2500, "currency": "USD"},
"sourceAccount": "xxxxxxxxxxx1234",
"destinationAccount": "xxxxxxxxxxx9876",
"beneficiary": "Hanna Herwitz",
"subject": "A Lannister Always Pays His Debts"
}
]
}
```
## Configure RAR for the Authorization Code Flow
Before configuring Rich Authorization Requests for the Authorization Code Flow, you must:
* Create a [custom domain](/docs/customize/custom-domains).
* Create a [custom Universal Login Pages](/docs/customize/login-pages/universal-login/customize-templates) template. To learn how to customize a Universal Login Page template, read the [Page templates API](/docs/customize/login-pages/universal-login/customize-templates#page-templates-api) documentation.
To configure RAR for the Authorization Code Flow, you need to:
* Register `authorization_details` types for a resource server.
* Set the customized consent prompt.
To learn more, read [Configure Rich Authorization Requests](/docs/get-started/apis/configure-rich-authorization-requests).
## Access `authorization_details` in Actions
Auth0 does not support updating RAR using Actions.
Auth0 exposes the `authorization_details` parameter in the [post-login Action](/docs/customize/actions/explore-triggers/signup-and-login-triggers/login-trigger/post-login-event-object) via the `event.transaction.requested_authorization_details` property. You can reference this property in an Action to show transaction details to the user in an [MFA challenge](/docs/secure/highly-regulated-identity/transactional-authorization-with-authorization-code-flow#push-notifications).
## What doesn’t Auth0 support?
Auth0 doesn’t support:
* Updating RAR using Actions.
* Advertising RAR types for clients to discover.
* Validating RAR objects beyond checking that they have a type property that matches allowed types for the API. For more information, see [Configure RAR](/docs/get-started/apis/configure-rich-authorization-requests).
## Learn more
* [Configure Rich Authorization Requests (RAR)](/docs/get-started/apis/configure-rich-authorization-requests)
# Call Your API Using the Authorization Code Flow
Source: https://auth0.com/docs/get-started/authentication-and-authorization-flow/authorization-code-flow/call-your-api-using-the-authorization-code-flow
Learn how to call your own API from regular web apps using the Authorization Code Flow.
This tutorial will help you call your own API using the Authorization Code Flow. If you want to learn how the flow works and why you should use it, see [Authorization Code Flow](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow). If you want to learn to add login to your regular web app, see [Add Login Using the Authorization Code Flow](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow/add-login-auth-code-flow).
Auth0 makes it easy for your app to implement the Authorization Code Flow using:
* [Regular Web App Quickstarts](/docs/quickstart/webapp): The easiest way to implement the flow.
* [Authentication API](https://auth0.com/docs/api/authentication): If you prefer to build your own solution, keep reading to learn how to call our API directly.
## Prerequisites
**Before beginning this tutorial:**
* [Register your Application with Auth0](/docs/get-started/auth0-overview/create-applications/regular-web-apps).
* Select an **Application Type** of **Regular Web Apps**.
* Add an **Allowed Callback URL** of `{https://yourApp/callback}`.
* Make sure your Application's **Grant Types** include **Authorization Code**. To learn how, read [Update Grant Types](/docs/get-started/applications/update-grant-types).
* If you want your Application to be able to use [refresh tokens](/docs/secure/tokens/refresh-tokens), make sure the Application's **Grant Types** include **refresh token**. To learn how, read [Update Grant Types](/docs/get-started/applications/update-grant-types). To learn more about Refresh Tokens, read [refresh tokens](/docs/secure/tokens/refresh-tokens).
* [Register your API with Auth0](/docs/get-started/auth0-overview/set-up-apis)
* If you want your API to receive refresh tokens to allow it to obtain new tokens when the previous ones expire, enable **Allow Offline Access**.
## Steps
This step may include one or more of the following processes:
* Authenticating the user
* Redirecting the user to an Identity Provider to handle authentication
* Checking for active Single Sign-on (SSO) sessions
* Obtaining user consent for the requested permission level, unless consent has been previously given.
To authorize the user, your app must send the user to the [authorization URL](https://auth0.com/docs/api/authentication#authorization-code-grant).
#### Example authorization URL
##### Parameters
Note that for authorizing a user when calling a custom API, you:
* must include an audience parameter
* can include additional scopes supported by the target API
| Parameter Name | Description |
| - | - |
| `response_type` | Denotes the kind of credential that Auth0 will return (`code` or `token`). For this flow, the value must be `code`. |
| `client_id` | Your application's Client ID. You can find this value in your [Application Settings](https://manage.auth0.com/#/Applications/\{yourClientId}/settings). |
| `redirect_uri` | The URL to which Auth0 will redirect the browser after authorization has been granted by the user. The Authorization Code will be available in the `code` URL parameter. You must specify this URL as a valid callback URL in your [Application Settings](https://manage.auth0.com/#/Applications/\{yourClientId}/settings).
**Warning:** Per the [OAuth 2.0 Specification](https://tools.ietf.org/html/rfc6749#section-3.1.2), Auth0 removes everything after the hash and does *not* honor any fragments. |
| `scope` | Specifies the [scopes](/docs/get-started/apis/scopes) for which you want to request authorization, which dictate which claims (or user attributes) you want returned. These must be separated by a space. You can request any of the [standard OpenID Connect (OIDC) scopes](https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims) about users, such as `profile` or `email`, [custom claims](/docs/secure/tokens/json-web-tokens/json-web-token-claims#custom-claims) conforming to a [namespaced format](/docs/secure/tokens/json-web-tokens/create-custom-claims), or any scopes supported by the target API (e.g., `read:contacts`). Include `offline_access` to get a [Refresh Token](/docs/glossary?term=Refresh+Token) (make sure that the **Allow Offline Access** field is enabled in the [Application Settings](https://manage.auth0.com/#/applications)). |
| `audience` | The unique identifier of the API your web app wants to access. Use the **Identifier** value on the [Settings](https://manage.auth0.com/#/apis) tab for the API you created as part of the prerequisites for this tutorial. |
| `state` | (recommended) An opaque arbitrary alphanumeric string your app adds to the initial request that Auth0 includes when redirecting back to your application. To see how to use this value to prevent cross-site request forgery (CSRF) attacks, see [Mitigate CSRF Attacks With State Parameters](/docs/secure/attack-protection/state-parameters). |
| `organization` | (optional) ID of the organization to use when authenticating a user. When not provided, if your application is configured to **Display Organization Prompt**, the user will be able to enter the organization name when authenticating. |
| `invitation` | (optional) Ticket ID of the organization invitation. When [inviting a member to an Organization](/docs/manage-users/organizations/configure-organizations/invite-members), your application should handle invitation acceptance by forwarding the `invitation` and `organization` key-value pairs when the user accepts the invitation. |
As an example, your HTML snippet for your authorization URL when adding login to your app might look like:
#### Response
If all goes well, you'll receive an `HTTP 302` response. The authorization code is included at the end of the URL:
```http lines theme={null}
HTTP/1.1 302 Found
Location: {https://yourApp/callback}?code={authorizationCode}&state=xyzABC123
```
Now that you have an Authorization Code, you must exchange it for tokens. Using the extracted Authorization Code (`code`) from the previous step, you will need to `POST` to the [token URL](https://auth0.com/docs/api/authentication#authorization-code).
#### Example POST to token URL
```bash cURL theme={null}
curl --request POST \
--url 'https://{yourDomain}/oauth/token' \
--header 'content-type: application/x-www-form-urlencoded' \
--data grant_type=authorization_code \
--data 'client_id={yourClientId}' \
--data 'client_secret={yourClientSecret}' \
--data 'code={yourAuthorizationCode}' \
--data 'redirect_uri={https://yourApp/callback}'
```
```csharp C# theme={null}
var client = new RestClient("https://{yourDomain}/oauth/token");
var request = new RestRequest(Method.POST);
request.AddHeader("content-type", "application/x-www-form-urlencoded");
request.AddParameter("application/x-www-form-urlencoded", "grant_type=authorization_code&client_id={yourClientId}&client_secret=%7ByourClientSecret%7D&code=yourAuthorizationCode%7D&redirect_uri={https://yourApp/callback}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```
```go Go theme={null}
package main
import (
"fmt"
"strings"
"net/http"
"io/ioutil"
)
func main() {
url := "https://{yourDomain}/oauth/token"
payload := strings.NewReader("grant_type=authorization_code&client_id={yourClientId}&client_secret=%7ByourClientSecret%7D&code=yourAuthorizationCode%7D&redirect_uri={https://yourApp/callback}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("content-type", "application/x-www-form-urlencoded")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := ioutil.ReadAll(res.Body)
fmt.Println(res)
fmt.Println(string(body))
}
```
```java Java theme={null}
HttpResponse response = Unirest.post("https://{yourDomain}/oauth/token")
.header("content-type", "application/x-www-form-urlencoded")
.body("grant_type=authorization_code&client_id={yourClientId}&client_secret=%7ByourClientSecret%7D&code=yourAuthorizationCode%7D&redirect_uri={https://yourApp/callback}")
.asString();
```
```javascript Node.JS theme={null}
var axios = require("axios").default;
var options = {
method: 'POST',
url: 'https://{yourDomain}/oauth/token',
headers: {'content-type': 'application/x-www-form-urlencoded'},
data: new URLSearchParams({
grant_type: 'authorization_code',
client_id: '{yourClientId}',
client_secret: '{yourClientSecret}',
code: 'yourAuthorizationCode}',
redirect_uri: '{https://yourApp/callback}'
})
};
axios.request(options).then(function (response) {
console.log(response.data);
}).catch(function (error) {
console.error(error);
});
```
```php PHP theme={null}
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://{yourDomain}/oauth/token",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "grant_type=authorization_code&client_id={yourClientId}&client_secret=%7ByourClientSecret%7D&code=yourAuthorizationCode%7D&redirect_uri={https://yourApp/callback}",
CURLOPT_HTTPHEADER => [
"content-type: application/x-www-form-urlencoded"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
```
```python Python theme={null}
import http.client
conn = http.client.HTTPSConnection("")
payload = "grant_type=authorization_code&client_id={yourClientId}&client_secret=%7ByourClientSecret%7D&code=yourAuthorizationCode%7D&redirect_uri={https://yourApp/callback}"
headers = { 'content-type': "application/x-www-form-urlencoded" }
conn.request("POST", "/{yourDomain}/oauth/token", payload, headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
```
```ruby Ruby theme={null}
require 'uri'
require 'net/http'
require 'openssl'
url = URI("https://{yourDomain}/oauth/token")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
request = Net::HTTP::Post.new(url)
request["content-type"] = 'application/x-www-form-urlencoded'
request.body = "grant_type=authorization_code&client_id={yourClientId}&client_secret=%7ByourClientSecret%7D&code=yourAuthorizationCode%7D&redirect_uri={https://yourApp/callback}"
response = http.request(request)
puts response.read_body
```
##### Parameters
| Parameter Name | Description |
| - | - |
| `grant_type` | Set this to `authorization_code`. |
| `code` | The `authorization_code` retrieved in the previous step of this tutorial. |
| `client_id` | Your application's Client ID. You can find this value in your [Application Settings](https://manage.auth0.com/#/Applications/\{yourClientId}/settings). |
| `client_secret` | Your application's Client Secret. You can find this value in your [Application Settings](https://manage.auth0.com/#/Applications/\{yourClientId}/settings). To learn more about available application authentication methods, read [Application Credentials](/docs/secure/application-credentials). |
| `redirect_uri` | The valid callback URL set in your Application settings. This must exactly match the `redirect_uri` passed to the authorization URL in the previous step of this tutorial. Note that this must be URL encoded. |
#### Response
If all goes well, you'll receive an `HTTP 200` response with a payload containing `access_token`, `refresh_token`, `id_token`, and `token_type` values:
```json lines theme={null}
{
"access_token": "eyJz93a...k4laUWw",
"refresh_token": "GEbRxBN...edjnXbL",
"id_token": "eyJ0XAi...4faeEoQ",
"token_type": "Bearer"
}
```
Validate your tokens before saving them. To learn how, read [Validate ID Tokens](/docs/secure/tokens/id-tokens/validate-id-tokens) and [Validate Access Tokens](/docs/secure/tokens/access-tokens/validate-access-tokens).
[ID tokens](/docs/secure/tokens/id-tokens) contain user information that must be decoded and extracted.
[Access tokens](/docs/secure/tokens/access-tokens) are used to call the [Auth0 Authentication API's /userinfo endpoint](https://auth0.com/docs/api/authentication#get-user-info) or another API. If you are calling your own API, the first thing your API will need to do is [verify the Access token](/docs/secure/tokens/access-tokens/validate-access-tokens).
[Refresh tokens](/docs/secure/tokens/refresh-tokens) are used to obtain a new access token or ID token after the previous one has expired. The `refresh_token` will only be present in the response if you included the `offline_access` scope and enabled **Allow Offline Access** for your API in the Dashboard.
Refresh tokens must be stored securely since they allow a user to remain authenticated essentially forever.
To call your API from a regular web application, the application must pass the retrieved access token as a Bearer token in the Authorization header of your HTTP request.
```bash cURL lines theme={null}
curl --request GET \
--url https://myapi.com/api \
--header 'authorization: Bearer {accessToken}' \
--header 'content-type: application/json'
```
```csharp C# lines theme={null}
var client = new RestClient("https://myapi.com/api");
var request = new RestRequest(Method.GET);
request.AddHeader("content-type", "application/json");
request.AddHeader("authorization", "Bearer {accessToken}");
IRestResponse response = client.Execute(request);
```
```go Go lines expandable theme={null}
package main
import (
"fmt"
"net/http"
"io/ioutil"
)
func main() {
url := "https://myapi.com/api"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("content-type", "application/json")
req.Header.Add("authorization", "Bearer {accessToken}")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := ioutil.ReadAll(res.Body)
fmt.Println(res)
fmt.Println(string(body))
}
```
```java Java lines theme={null}
HttpResponse response = Unirest.get("https://myapi.com/api")
.header("content-type", "application/json")
.header("authorization", "Bearer {accessToken}")
.asString();
```
```javascript Node.JS lines theme={null}
var axios = require("axios").default;
var options = {
method: 'GET',
url: 'https://myapi.com/api',
headers: {'content-type': 'application/json', authorization: 'Bearer {accessToken}'}
};
axios.request(options).then(function (response) {
console.log(response.data);
}).catch(function (error) {
console.error(error);
});
```
```php PHP lines expandable theme={null}
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://myapi.com/api",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"authorization: Bearer {accessToken}",
"content-type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
```
```python Python lines theme={null}
import http.client
conn = http.client.HTTPSConnection("myapi.com")
headers = {
'content-type': "application/json",
'authorization': "Bearer {accessToken}"
}
conn.request("GET", "/api", headers=headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
```
```ruby Ruby lines theme={null}
require 'uri'
require 'net/http'
require 'openssl'
url = URI("https://myapi.com/api")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
request = Net::HTTP::Get.new(url)
request["content-type"] = 'application/json'
request["authorization"] = 'Bearer {accessToken}'
response = http.request(request)
puts response.read_body
```
You have already received a [refresh token](/docs/secure/tokens/refresh-tokens) if you've been following this tutorial and completed the following:
* configured your API to allow offline access
* included the `offline_access` scope when you initiated the authentication request through the [authorize endpoint](https://auth0.com/docs/api/authentication/reference#authorize-application).
You can use the Refresh Token to get a new access token. Usually, a user will need a new access token only after the previous one expires or when gaining access to a new resource for the first time. It's bad practice to call the endpoint to get a new access token every time you call an API, and Auth0 maintains rate limits that will throttle the amount of requests to the endpoint that can be executed using the same token from the same IP.
To refresh your token, make a `POST` request to the `/oauth/token` endpoint in the Authentication API, using `grant_type=refresh_token`.
##### Example POST to token URL
```bash cURL theme={null}
curl --request POST \
--url 'https://{yourDomain}/oauth/token' \
--header 'content-type: application/x-www-form-urlencoded' \
--data grant_type=refresh_token \
--data 'client_id={yourClientId}' \
--data 'refresh_token={yourRefreshToken}'
```
```csharp C# theme={null}
var client = new RestClient("https://{yourDomain}/oauth/token");
var request = new RestRequest(Method.POST);
request.AddHeader("content-type", "application/x-www-form-urlencoded");
request.AddParameter("application/x-www-form-urlencoded", "grant_type=refresh_token&client_id={yourClientId}&refresh_token=%7ByourRefreshToken%7D", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```
```go Go theme={null}
package main
import (
"fmt"
"strings"
"net/http"
"io/ioutil"
)
func main() {
url := "https://{yourDomain}/oauth/token"
payload := strings.NewReader("grant_type=refresh_token&client_id={yourClientId}&refresh_token=%7ByourRefreshToken%7D")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("content-type", "application/x-www-form-urlencoded")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := ioutil.ReadAll(res.Body)
fmt.Println(res)
fmt.Println(string(body))
}
```
```java Java theme={null}
HttpResponse response = Unirest.post("https://{yourDomain}/oauth/token")
.header("content-type", "application/x-www-form-urlencoded")
.body("grant_type=refresh_token&client_id={yourClientId}&refresh_token=%7ByourRefreshToken%7D")
.asString();
```
```javascript Node.JS theme={null}
var axios = require("axios").default;
var options = {
method: 'POST',
url: 'https://{yourDomain}/oauth/token',
headers: {'content-type': 'application/x-www-form-urlencoded'},
data: new URLSearchParams({
grant_type: 'refresh_token',
client_id: '{yourClientId}',
refresh_token: '{yourRefreshToken}'
})
};
axios.request(options).then(function (response) {
console.log(response.data);
}).catch(function (error) {
console.error(error);
});
```
```php PHP theme={null}
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://{yourDomain}/oauth/token",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "grant_type=refresh_token&client_id={yourClientId}&refresh_token=%7ByourRefreshToken%7D",
CURLOPT_HTTPHEADER => [
"content-type: application/x-www-form-urlencoded"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
```
```python Python theme={null}
import http.client
conn = http.client.HTTPSConnection("")
payload = "grant_type=refresh_token&client_id={yourClientId}&refresh_token=%7ByourRefreshToken%7D"
headers = { 'content-type': "application/x-www-form-urlencoded" }
conn.request("POST", "/{yourDomain}/oauth/token", payload, headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
```
```ruby Ruby theme={null}
require 'uri'
require 'net/http'
require 'openssl'
url = URI("https://{yourDomain}/oauth/token")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
request = Net::HTTP::Post.new(url)
request["content-type"] = 'application/x-www-form-urlencoded'
request.body = "grant_type=refresh_token&client_id={yourClientId}&refresh_token=%7ByourRefreshToken%7D"
response = http.request(request)
puts response.read_body
```
###### Parameters
| Parameter Name | Description |
| - | - |
| `grant_type` | Set this to `refresh_token`. |
| `client_id` | Your application's Client ID. You can find this value in your [Application Settings](https://manage.auth0.com/#/Applications/\{yourClientId}/settings). |
| `refresh_token` | The refresh token to use. |
| `scope` | (optional) A space-delimited list of requested scope permissions. If not sent, the original scopes will be used; otherwise you can request a reduced set of scopes. Note that this must be URL encoded. |
###### Response
If all goes well, you'll receive an `HTTP 200` response with a payload containing a new `access_token`, its lifetime in seconds (`expires_in`), granted `scope` values, and `token_type`. If the scope of the initial token included `openid`, then the response will also include a new `id_token`:
```json lines theme={null}
{
"access_token": "eyJ...MoQ",
"expires_in": 86400,
"scope": "openid offline_access",
"id_token": "eyJ...0NE",
"token_type": "Bearer"
}
```
Validate your tokens before saving them. To learn how, read [Validate ID Tokens](/docs/secure/tokens/id-tokens/validate-id-tokens) and [Validate Access Tokens](/docs/secure/tokens/access-tokens/validate-access-tokens).
### Sample use cases
#### Customize tokens
You can use Auth0 Actions to modify the scopes of an access token and/or add custom claims to access and ID tokens. To learn more about Actions, see [Understand how Auth0 Actions Work.](/docs/customize/actions/actions-overview)
To do so, add the following Post-Login Action, which will run after the user authenticates:
```js lines theme={null}
exports.onExecutePostLogin = async (event, api) => {
// Add custom claims to Access Token and ID Token
api.accessToken.setCustomClaim('https://foo/bar', 'value');
api.idToken.setCustomClaim('https://fiz/baz', 'some other value');
// Modify the scope of the Access Token
api.accessToken.addScope('foo');
api.accessToken.addScope('bar');
};
```
Auth0 returns profile information in a structured claim format as defined by the [OpenID Connect (OIDC) specification](https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims). This means that custom claims added to ID tokens or access tokens must [conform to guidelines and restrictions](/docs/secure/tokens/json-web-tokens/create-custom-claims) to avoid possible collisions.
## Learn more
* [OAuth 2.0 Authorization Framework](/docs/authenticate/protocols/oauth)
* [OpenID Connect Protocol](/docs/authenticate/protocols/openid-connect-protocol)
* [Tokens](/docs/secure/tokens)
# Client Credentials Exchange
Source: https://auth0.com/docs/get-started/authentication-and-authorization-flow/client-credentials-exchange
Learn how Hooks can be used with the Client Credentials Exchange extensibility point, which is available for database connections and passwordless connections.
The End of Life (EOL) date of Rules and Hooks will be **November 18, 2026**, and they are no longer available to new tenants created as of **October 16, 2023**. Existing tenants with active Hooks will retain Hooks product access through end of life.
We highly recommend that you use Actions to extend Auth0. With Actions, you have access to rich type information, inline documentation, and public `npm` packages, and can connect external integrations that enhance your overall extensibility experience. To learn more about what Actions offer, read [Understand How Auth0 Actions Work](/docs/customize/actions/actions-overview).
To help with your migration, we offer guides that will help you [migrate from Rules to Actions](/docs/customize/actions/migrate/migrate-from-rules-to-actions) and [migrate from Hooks to Actions](/docs/customize/actions/migrate/migrate-from-hooks-to-actions). We also have a dedicated [Move to Actions](https://auth0.com/extensibility/movetoactions) page that highlights feature comparisons, [an Actions demo](https://www.youtube.com/watch?v=UesFSY1klrI), and other resources to help you on your migration journey.
To read more about the Rules and Hooks deprecation, read our blog post: [Preparing for Rules and Hooks End of Life](https://auth0.com/blog/preparing-for-rules-and-hooks-end-of-life/).
At the Client Credentials Exchange extensibility point, Hooks let you execute custom actions when an Access Token is issued through the Authentication API [`POST /oauth/token` endpoint](https://auth0.com/docs/api/authentication#client-credentials-flow) using the Client Credentials Flow. For example, you may deny the token from being issued, add custom claims to the access token, or modify its scopes. To learn more, read [Client Credentials Flow](/docs/get-started/authentication-and-authorization-flow/client-credentials-flow).
Hooks at this extensibility point are blocking (synchronous), which means they execute as part of the trigger's process and prevent the rest of the Auth0 pipeline from running until the Hook is complete.
The `triggerId` for the Client Credentials Exchange extensibility point is `credentials-exchange`. To learn how to create hooks for this extensibility point, read [Create Hooks](/docs/customize/hooks/create-hooks).
To learn about other extensibility points, read Extensibility Points.
## Starter code and parameters
When creating a Hook executed at the Client Credentials Exchange extensibility point, you may find the following starter code helpful. Parameters that can be passed into and used by the Hook function are listed at the top of the code sample.
```javascript lines expandable theme={null}
/**
@param {object} client - client information
@param {string} client.name - client name
@param {string} client.id - client ID
@param {string} client.tenant - Auth0 tenant name
@param {object} client.metadata - client metadata
@param {array|undefined} scope - either an array of strings representing the token's scope claim, or undefined
@param {string} audience - token's audience claim
@param {object} context - Auth0 context info
@param {object} context.webtask - Hook (webtask) context
@param {function} cb - function (error, accessTokenClaims)
*/
module.exports = function(client, scope, audience, context, cb) {
var access_token = {};
access_token.scope = scope; // do not remove this line
// Modify scopes or add extra claims
// access_token['https://example.com/claim'] = 'bar';
// access_token.scope.push('extra');
// Deny the token and respond with an OAuth2 error response
// if (denyExchange) {
// // To return an HTTP 400 with { "error": "invalid_scope", "error_description": "Not authorized for this scope." }
// return cb(new InvalidScopeError('Not authorized for this scope.'));
//
// // To return an HTTP 400 with { "error": "invalid_request", "error_description": "Not a valid request." }
// return cb(new InvalidRequestError('Not a valid request.'));
//
// // To return an HTTP 500 with { "error": "server_error", "error_description": "A server error occurred." }
// return cb(new ServerError('A server error occurred.'));
// }
cb(null, access_token);
};
```
Please note:
* The callback function (`cb`) at the end of the sample code signals completion and must be included.
* The line `access_token.scope = scope` ensures that all granted scopes will be present in the access token. Removing it will reset all scopes, and the token will include only scopes you add with the script.
### Default response
When you run a Hook executed at the Client Credentials Exchange extensibility point, the default response object is:
```json lines theme={null}
{
"scope": "array of strings"
}
```
### Starter code response
Once you've customized the starter code with your scopes and additional claims, you can test the Hook using the runner embedded in the Hook Editor. The runner simulates a call to the Hook with the same body and response that you would get with a Client Credentials Exchange.
Executing the code using the runner requires a save, which means that the original code will be overwritten.
When you run a Hook based on the starter code, the response object is:
```json lines theme={null}
{
"audience": "https://my-tenant.auth0.com/api/v2/",
"client": {
"id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"name": "client-name",
"tenant": "my-tenant",
"metadata": {
"plan": "full"
}
},
"scope": [
"read:connections"
]
}
```
## Sample script: Add an additional scope to the access token
In this example, we use a Hook to add an additional scope to those already existing for the access token.
```js lines theme={null}
module.exports = function(client, scope, audience, context, cb) {
// Scopes to be added
var access_token = {};
// Get the scope that's currently on the Access Token
// and add it to the object we're working with
// Do not remove this line!
access_token.scope = scope;
// Append the `read:resource` scope
access_token.scope.push('read:resource');
// Callback to indicate completion and to return new
// array of scopes
cb(null, access_token);
};
```
To learn more, read [Scopes](/docs/get-started/apis/scopes).
### Response
When we run this Hook, the response object is:
```json lines theme={null}
{
"scope": [
"read:connections",
"read:resource"
]
}
```
## Sample script: Add a claim to the access token
In this example, we add a namespaced custom claim and its value to the access token. To learn more, read [Create Namespaced Custom Claims](/docs/secure/tokens/json-web-tokens/create-custom-claims).
You can add the following as claims to the issued token:
* The `scope` property of the response object
* Any properties with namespaced property names
The extensibility point ignores all other response object properties.
To access a configured Hook Secret from within a hook, use `context.webtask.secrets.SECRET_NAME`.
```js lines theme={null}
module.exports = function(client, scope, audience, context, cb) {
// Claims to be added
var access_token = {};
// New claim to add to the token
access_token['https://example.com/foo'] = 'bar';
// Callback to indicate completion and to return new claim
cb(null, access_token);
};
```
### Response
When we run this Hook, the response object is:
```json lines theme={null}
{
"https://example.com/foo": "bar"
}
```
## Sample script: Raise an error or deny an access token
In this example, we use custom Error objects to generate OAuth2 Error Responses. (To learn more, see [OAuth2 RFC - Section 5.2 in the IETF Datatracker](https://tools.ietf.org/html/rfc6749#section-5.2).)
If a plain JavaScript error is returned in the callback, such as:
```js lines theme={null}
module.exports = function(client, scope, audience, context, cb) {
// Callback to indicate completion and to return new claim
cb(new Error("Unknown error occurred.");
};
```
Then when you request a `client_credentials` grant from the `/oauth/token` endpoint, Auth0 will respond with:
```json lines theme={null}
HTTP 500
{ "error": "server_error", "error_description": "Unknown error occurred." }
```
However, if you like additional control over the OAuth2 Error Response, three custom Error objects are available to use instead.
### InvalidScopeError
```js lines theme={null}
module.exports = function(client, scope, audience, context, cb) {
const invalidScope = ...; // determine if scope is valid
if(invalidScope) {
cb(new InvalidScopeError("Scope is not permitted."));
}
};
```
Then when you request a `client_credentials` grant is from the `/oauth/token` endpoint, Auth0 responds with:
```json lines theme={null}
HTTP 400
{ "error": "invalid_scope", "error_description": "Scope is not permitted." }
```
### InvalidRequestError
```js lines theme={null}
module.exports = function(client, scope, audience, context, cb) {
const invalidRequest = ...; // determine if request is valid
if(invalidRequest) {
cb(new InvalidRequestError("Bad request."));
}
};
```
Then when you request a `client_credentials` grant from the `/oauth/token` endpoint, Auth0 will respond with:
```json lines theme={null}
HTTP 400
{ "error": "invalid_request", "error_description": "Bad request." }
```
### ServerError
```js lines theme={null}
module.exports = function(client, scope, audience, context, cb) {
callOtherService(function(err, response) {
if(err) {
return cb(new ServerError("Error calling remote system: " + err.message));
}
});
};
```
Then when you request a `client_credentials` grant from the `/oauth/token` endpoint, Auth0 responds with:
```json lines theme={null}
HTTP 400
{ "error": "server_error", "error_description": "Error calling remote system: ..." }
```
Currently, the behavior of the built-in JavaScript `Error` class and `ServerError` is identical, but the `ServerError` class allows you to be explicit about the OAuth2 error that will be returned.
## Learn more
# Client Credentials Flow
Source: https://auth0.com/docs/get-started/authentication-and-authorization-flow/client-credentials-flow
Learn how the Client Credentials flow works and why you should use it for machine-to-machine (M2M) applications.
The Client Credentials Flow (defined in [OAuth 2.0 RFC 6749, section 4.4](https://tools.ietf.org/html/rfc6749#section-4.4)) involves an application exchanging its application credentials, such as client ID and client secret, for an access token.
This flow is best suited for Machine-to-Machine (M2M) applications, such as CLIs, daemons, or backend services, because the system must authenticate and authorize the application instead of a user.
## How it works
1. Application sends application's credentials to the Auth0 Authorization Server. To learn more about client authentication methods, read [Application Credentials](/docs/secure/application-credentials).
2. Auth0 Authorization Server validates application's credentials.
3. Auth0 Authorization Server responds with an access token.
4. Application can use the access token to call an API on behalf of itself. For more information on this process, see [Validate JSON Web Tokens](/docs/secure/tokens/json-web-tokens/validate-json-web-tokens).
5. API responds with requested data.
## How to implement it
The easiest way to implement the Client Credentials Flow is to follow our [Backend Quickstarts](/docs/quickstart/backend).
Alternatively, you can use the Auth0 Authentication API to implement the Client Credentials Flow. For more information, read [Call Your API Using the Client Credentials Flow](/docs/get-started/authentication-and-authorization-flow/client-credentials-flow/call-your-api-using-the-client-credentials-flow).
## Learn more
* [Auth0 Rules](/docs/customize/rules)
* [Auth0 Hooks](/docs/customize/hooks)
* [Tokens](/docs/secure/tokens)
* [Token Best Practices](/docs/secure/tokens/token-best-practices)
* [Which OAuth 2.0 Flow Should I Use?](/docs/get-started/authentication-and-authorization-flow/which-oauth-2-0-flow-should-i-use)
# Call Your API Using the Client Credentials Flow
Source: https://auth0.com/docs/get-started/authentication-and-authorization-flow/client-credentials-flow/call-your-api-using-the-client-credentials-flow
Learn how to call your API from a machine-to-machine (M2M) application using the Client Credentials Flow.
This tutorial will help you call your API from a machine-to-machine (M2M) application using the Client Credentials Flow. To learn how the flow works and why you should use it, read [Client Credentials Flow](/docs/get-started/authentication-and-authorization-flow/client-credentials-flow).
Auth0 makes it easy for your application to implement the Client Credentials Flow. Following successful authentication, the application will have access to an access token, which can be used to call your protected APIs. To learn more about access tokens, read [Access Tokens](/docs/secure/tokens/access-tokens).
## Prerequisites
**Before beginning this tutorial:**
* [Register your API with Auth0](/docs/get-started/auth0-overview/set-up-apis)
* [Add appropriate API permissions](/docs/get-started/apis/add-api-permissions)
* [Register the M2M Application with Auth0](/docs/get-started/auth0-overview/create-applications/machine-to-machine-apps).
* Select an **Application Type** of **Machine to Machine Applications**.
* Choose your previously-registered API.
* Authorize the M2M Application to call your API.
## Steps
1. [Request tokens](#request-tokens):
From the authorized application, request an access token for your API.
2. [Call API](#call-api):
Use the retrieved access token to call your API.
Optional: [Explore sample use cases](#sample-use-cases)
### Request tokens
To access your API, you must request an access token for it. To do so, you will need to `POST` to the [token URL](/docs/api/authentication/client-credential-flow/get-token).
#### Example POST to token URL
```bash cURL theme={null}
curl --request POST \
--url 'https://{yourDomain}/oauth/token' \
--header 'content-type: application/x-www-form-urlencoded' \
--data grant_type=client_credentials \
--data client_id={yourClientId} \
--data client_secret={yourClientSecret} \
--data audience=YOUR_API_IDENTIFIER
```
```csharp C# theme={null}
var client = new RestClient("https://{yourDomain}/oauth/token");
var request = new RestRequest(Method.POST);
request.AddHeader("content-type", "application/x-www-form-urlencoded");
request.AddParameter("application/x-www-form-urlencoded", "grant_type=client_credentials&client_id={yourClientId}&client_secret={yourClientSecret}&audience=YOUR_API_IDENTIFIER", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```
```go Go theme={null}
package main
import (
"fmt"
"strings"
"net/http"
"io/ioutil"
)
func main() {
url := "https://{yourDomain}/oauth/token"
payload := strings.NewReader("grant_type=client_credentials&client_id={yourClientId}&client_secret={yourClientSecret}&audience=YOUR_API_IDENTIFIER")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("content-type", "application/x-www-form-urlencoded")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := ioutil.ReadAll(res.Body)
fmt.Println(res)
fmt.Println(string(body))
}
```
```java Java theme={null}
HttpResponse response = Unirest.post("https://{yourDomain}/oauth/token")
.header("content-type", "application/x-www-form-urlencoded")
.body("grant_type=client_credentials&client_id={yourClientId}&client_secret={yourClientSecret}&audience=YOUR_API_IDENTIFIER")
.asString();
```
```javascript Node.JS theme={null}
var axios = require("axios").default;
var options = {
method: 'POST',
url: 'https://{yourDomain}/oauth/token',
headers: {'content-type': 'application/x-www-form-urlencoded'},
data: new URLSearchParams({
grant_type: 'client_credentials',
client_id: '{yourClientId}',
client_secret: '{yourClientSecret}',
audience: 'YOUR_API_IDENTIFIER'
})
};
axios.request(options).then(function (response) {
console.log(response.data);
}).catch(function (error) {
console.error(error);
});
```
```php PHP theme={null}
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://{yourDomain}/oauth/token",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "grant_type=client_credentials&client_id={yourClientId}&client_secret={yourClientSecret}&audience=YOUR_API_IDENTIFIER",
CURLOPT_HTTPHEADER => [
"content-type: application/x-www-form-urlencoded"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
```
```python Python theme={null}
import http.client
conn = http.client.HTTPSConnection("")
payload = "grant_type=client_credentials&client_id={yourClientId}&client_secret={yourClientSecret}&audience=YOUR_API_IDENTIFIER"
headers = { 'content-type': "application/x-www-form-urlencoded" }
conn.request("POST", "/{yourDomain}/oauth/token", payload, headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
```
```ruby Ruby theme={null}
require 'uri'
require 'net/http'
require 'openssl'
url = URI("https://{yourDomain}/oauth/token")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
request = Net::HTTP::Post.new(url)
request["content-type"] = 'application/x-www-form-urlencoded'
request.body = "grant_type=client_credentials&client_id={yourClientId}&client_secret={yourClientSecret}&audience=YOUR_API_IDENTIFIER"
response = http.request(request)
puts response.read_body
```
##### Parameters
| Parameter Name | Description |
| - | - |
| `grant_type` | Set this to "client\_credentials". |
| `client_id` | Your application's Client ID. You can find this value on the [application's settings tab](https://manage.auth0.com/#/applications). |
| `client_secret` | Your application's Client Secret. You can find this value on the [application's settings tab](https://manage.auth0.com/#/applications). To learn more about available application authentication methods, read [Application Credentials](/docs/secure/application-credentials). |
| `audience` | The audience for the token, which is your API. You can find this in the **Identifier** field on your [API's settings tab](https://manage.auth0.com/#/apis). |
| `organization` | Optional. The organization name or identifier you want the request to be associated with. To learn more, read [Machine-to-Machine Access for Organizations](/docs/manage-users/organizations/organizations-for-m2m-applications). |
#### Response
If all goes well, you'll receive an `HTTP 200` response with a payload containing `access_token`, `token_type`, and `expires_in` values:
```json lines theme={null}
{
"access_token":"eyJz93a...k4laUWw",
"token_type":"Bearer",
"expires_in":86400
}
```
Validate your tokens before saving them. To learn how, read [Validate ID Tokens](/docs/secure/tokens/id-tokens/validate-id-tokens) and [Validate Access Tokens](/docs/secure/tokens/access-tokens/validate-access-tokens).
### Call API
To call your API from the M2M application, the application must pass the retrieved access token as a Bearer token in the Authorization header of your HTTP request.
```bash cURL lines theme={null}
curl --request GET \
--url https://myapi.com/api \
--header 'authorization: Bearer ACCESS_TOKEN' \
--header 'content-type: application/json'
```
```csharp C# lines theme={null}
var client = new RestClient("https://myapi.com/api");
var request = new RestRequest(Method.GET);
request.AddHeader("content-type", "application/json");
request.AddHeader("authorization", "Bearer ACCESS_TOKEN");
IRestResponse response = client.Execute(request);
```
```go Go lines expandable theme={null}
package main
import (
"fmt"
"net/http"
"io/ioutil"
)
func main() {
url := "https://myapi.com/api"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("content-type", "application/json")
req.Header.Add("authorization", "Bearer ACCESS_TOKEN")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := ioutil.ReadAll(res.Body)
fmt.Println(res)
fmt.Println(string(body))
}
```
```java Java lines theme={null}
HttpResponse response = Unirest.get("https://myapi.com/api")
.header("content-type", "application/json")
.header("authorization", "Bearer ACCESS_TOKEN")
.asString();
```
```javascript Node.JS lines theme={null}
var axios = require("axios").default;
var options = {
method: 'GET',
url: 'https://myapi.com/api',
headers: {'content-type': 'application/json', authorization: 'Bearer ACCESS_TOKEN'}
};
axios.request(options).then(function (response) {
console.log(response.data);
}).catch(function (error) {
console.error(error);
});
```
```php PHP lines expandable theme={null}
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://myapi.com/api",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"authorization: Bearer ACCESS_TOKEN",
"content-type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
```
```python Python lines theme={null}
import http.client
conn = http.client.HTTPSConnection("myapi.com")
headers = {
'content-type': "application/json",
'authorization': "Bearer ACCESS_TOKEN"
}
conn.request("GET", "/api", headers=headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
```
```ruby Ruby lines theme={null}
require 'uri'
require 'net/http'
require 'openssl'
url = URI("https://myapi.com/api")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
request = Net::HTTP::Get.new(url)
request["content-type"] = 'application/json'
request["authorization"] = 'Bearer ACCESS_TOKEN'
response = http.request(request)
puts response.read_body
```
### Sample use cases
#### Customize tokens
You can use [Actions](/docs/customize/actions) to deny access tokens based on custom logic and/or add claims to access tokens. Auth0 invokes Actions attached to the client credentials grant at runtime to execute your custom logic.
To learn more, read about the Actions [Machine to Machine Flow](/docs/customize/actions/explore-triggers/credentials-exchange).
#### View sample application: server client + API
For a sample implementation, read the [Server Client + API](/docs/get-started/architecture-scenarios/server-application-api) architecture scenario. This series of tutorials is accompanied by a [code sample that you can access in GitHub](https://github.com/auth0-samples/auth0-pnp-exampleco-timesheets).
Once your API receives a request with an access token, it will need to validate the token. To learn more, read [Validate Access Tokens](/docs/secure/tokens/access-tokens/validate-access-tokens).
## Learn more
* [Machine to Machine Triggers](/docs/customize/actions/explore-triggers/credentials-exchange)
* [OpenID Connect Protocol](/docs/authenticate/protocols/openid-connect-protocol)
* [Tokens](/docs/secure/tokens)
# Customize Tokens Using Hooks with Client Credentials Flow
Source: https://auth0.com/docs/get-started/authentication-and-authorization-flow/client-credentials-flow/customize-tokens-using-hooks-with-client-credentials-flow
Learn how to use Hooks to change scopes and add custom claims in the access token obtained using the Client Credentials Flow.
The End of Life (EOL) date of Rules and Hooks will be **November 18, 2026**, and they are no longer available to new tenants created as of **October 16, 2023**. Existing tenants with active Hooks will retain Hooks product access through end of life.
We highly recommend that you use Actions to extend Auth0. With Actions, you have access to rich type information, inline documentation, and public `npm` packages, and can connect external integrations that enhance your overall extensibility experience. To learn more about what Actions offer, read [Understand How Auth0 Actions Work](/docs/customize/actions/actions-overview).
To help with your migration, we offer guides that will help you [migrate from Rules to Actions](/docs/customize/actions/migrate/migrate-from-rules-to-actions) and [migrate from Hooks to Actions](/docs/customize/actions/migrate/migrate-from-hooks-to-actions). We also have a dedicated [Move to Actions](https://auth0.com/extensibility/movetoactions) page that highlights feature comparisons, [an Actions demo](https://www.youtube.com/watch?v=UesFSY1klrI), and other resources to help you on your migration journey.
To read more about the Rules and Hooks deprecation, read our blog post: [Preparing for Rules and Hooks End of Life](https://auth0.com/blog/preparing-for-rules-and-hooks-end-of-life/).
Because we plan to remove Rules and Hooks functions in 2026, you should create new Rules or Hooks only in your Development environment and only to test migration to Actions.
To learn how to migrate your Rules to Actions, read [Migrate from Rules to Actions](/docs/customize/actions/migrate/migrate-from-rules-to-actions). To learn how to migrate your Hooks to Actions, read [Migrate from Hooks to Actions](/docs/customize/actions/migrate/migrate-from-hooks-to-actions).
You can change scopes and add custom claims in the tokens issued through the [Client Credentials Flow](/docs/get-started/authentication-and-authorization-flow/client-credentials-flow) by adding [Hooks](/docs/customize/hooks).
Hooks allow you to customize the behavior of Auth0 using Node.js code. They are secure, self-contained functions associated with specific extensibility points of the Auth0 platform (like the Client Credentials flow). Auth0 invokes the Hooks at runtime to execute your custom logic.
You can manage Hooks using the Auth0 Dashboard or the Management API.
Although you may create multiple hooks for any given extensibility point, each extensibility point may have only one enabled hook at a time. Any subsequent hooks you create for that extensibility point are automatically disabled, so you must explicitly enable them. The enabled hook will be executed for all applications and APIs.
## Prerequisites
Before beginning this tutorial, you must:
* [Register your API with Auth0](/docs/get-started/auth0-overview/set-up-apis)
* [Add appropriate API permissions](/docs/get-started/apis/add-api-permissions)
* [Register the M2M Application with Auth0](/docs/get-started/auth0-overview/create-applications/machine-to-machine-apps).
* Select an **Application Type** of **Machine to Machine Applications**.
* Choose your previously-registered API.
* Authorize the M2M Application to call your API.
## Steps
1. **Create Hook**: Create a hook that will customize your token.
2. **Test Hook**: Test your new hook by running a Client Credentials Flow and decoding the access token.
### Create a Hook
In this example, you will:
* add an arbitrary claim (`https://foo.com/claim`) to the [Access Token](/docs/secure/tokens/access-tokens)
* add an extra permission to your configured API
Create a Hook to customize your token. When asked to choose an extensibility point, select `Client Credentials Exchange`, and add the following code in the editor:
```js lines theme={null}
module.exports = function(client, scope, audience, context, cb) {
var access_token = {};
access_token['https://foo.com/claim'] = 'bar';
access_token.scope = scope;
access_token.scope.push('extra');
cb(null, access_token);
};
```
Auth0 returns profile information in a structured claim format as defined by the [OpenID Connect (OIDC) specification](https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims). This means that custom claims added to ID tokens or access tokens must [conform to guidelines and restrictions](/docs/secure/tokens/json-web-tokens/create-custom-claims) to avoid possible collisions.
### Test your Hook
To test the hook you just created you need to run a Client Credentials exchange, get the Access Token, decode it, and review its contents.
#### Get token
To get a token, make a `POST` call to the [Client Credentials Flow endpoint](https://auth0.com/docs/api/authentication#client-credentials-flow). Be sure to replace CLIENT\_ID, CLIENT\_SECRET, and API\_IDENTIFIER placeholder values with your application's Client ID, your application's Client Secret, and your API's Identifier, respectively. You can find the Client ID and Client Secret in your [Application](https://manage.auth0.com/#/applications) settings and the API Identifier in your [API](https://manage.auth0.com/#/apis) settings.
```bash cURL theme={null}
curl --request POST \
--url 'https://{yourDomain}/oauth/token' \
--header 'content-type: application/x-www-form-urlencoded' \
--data grant_type=client_credentials \
--data 'client_id={yourClientId}' \
--data client_secret={yourClientSecret} \
--data audience=YOUR_API_IDENTIFIER
```
```csharp C# theme={null}
var client = new RestClient("https://{yourDomain}/oauth/token");
var request = new RestRequest(Method.POST);
request.AddHeader("content-type", "application/x-www-form-urlencoded");
request.AddParameter("application/x-www-form-urlencoded", "grant_type=client_credentials&client_id={yourClientId}&client_secret={yourClientSecret}&audience=YOUR_API_IDENTIFIER", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```
```go Go theme={null}
package main
import (
"fmt"
"strings"
"net/http"
"io/ioutil"
)
func main() {
url := "https://{yourDomain}/oauth/token"
payload := strings.NewReader("grant_type=client_credentials&client_id={yourClientId}&client_secret={yourClientSecret}&audience=YOUR_API_IDENTIFIER")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("content-type", "application/x-www-form-urlencoded")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := ioutil.ReadAll(res.Body)
fmt.Println(res)
fmt.Println(string(body))
}
```
```java Java theme={null}
HttpResponse response = Unirest.post("https://{yourDomain}/oauth/token")
.header("content-type", "application/x-www-form-urlencoded")
.body("grant_type=client_credentials&client_id={yourClientId}&client_secret={yourClientSecret}&audience=YOUR_API_IDENTIFIER")
.asString();
```
```javascript Node.JS theme={null}
var axios = require("axios").default;
var options = {
method: 'POST',
url: 'https://{yourDomain}/oauth/token',
headers: {'content-type': 'application/x-www-form-urlencoded'},
data: new URLSearchParams({
grant_type: 'client_credentials',
client_id: '{yourClientId}',
client_secret: '{yourClientSecret}',
audience: 'YOUR_API_IDENTIFIER'
})
};
axios.request(options).then(function (response) {
console.log(response.data);
}).catch(function (error) {
console.error(error);
});
```
```php PHP theme={null}
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://{yourDomain}/oauth/token",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "grant_type=client_credentials&client_id={yourClientId}&client_secret={yourClientSecret}&audience=YOUR_API_IDENTIFIER",
CURLOPT_HTTPHEADER => [
"content-type: application/x-www-form-urlencoded"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
```
```python Python theme={null}
import http.client
conn = http.client.HTTPSConnection("")
payload = "grant_type=client_credentials&client_id={yourClientId}&client_secret={yourClientSecret}&audience=YOUR_API_IDENTIFIER"
headers = { 'content-type': "application/x-www-form-urlencoded" }
conn.request("POST", "/{yourDomain}/oauth/token", payload, headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
```
```ruby Ruby theme={null}
require 'uri'
require 'net/http'
require 'openssl'
url = URI("https://{yourDomain}/oauth/token")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
request = Net::HTTP::Post.new(url)
request["content-type"] = 'application/x-www-form-urlencoded'
request.body = "grant_type=client_credentials&client_id={yourClientId}&client_secret={yourClientSecret}&audience=YOUR_API_IDENTIFIER"
response = http.request(request)
puts response.read_body
```
A successful response will include:
* an `access_token`,
* its expiration time in seconds (`expires_in`),
* the token's type set as `Bearer` (`token_type`), and
* an `extra` permission (`scope`) (which was added by your Hook)
```json lines theme={null}
HTTP/1.1 200 OK
Content-Type: application/json
{
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ik5ESTFNa05DTVRGQlJrVTRORVF6UXpFMk1qZEVNVVEzT1VORk5ESTVSVU5GUXpnM1FrRTFNdyJ9.eyJpc3MiOiJodHRwczovL2RlbW8tYWNjb3VudC5hdXRoMC3jb20vIiwic3ViIjoic0FRSlFpQmYxREw0c2lqSVZCb2pFRUZvcmRoa0o4WUNAY2xpZW50cyIsImF1ZCI6ImRlbW8tYWNjb3VudC5hcGkiLCJleHAiOjE0ODc3NjU8NjYsImlhdCI6MTQ4NzY3OTI2Niwic2NvcGUiOiJyZWFkOmRhdGEgZXh0cmEiLCJodHRwczovL2Zvby5jb20vY2xhaW0iOiKoPXIifQ.da-48mHY_7esfLZpvHWWL8sIH1j_2mUYAB49c-B472lCdsNFvpaLoq6OKQyhnqk9_aW_Xhfkusos3FECTrLFvf-qwQK70QtwbkbVye_IuPSTAYdQ2T-XTzGDm9Nmmy5Iwl9rNYLxVs2OoCdfpVMyda0OaI0AfHBgEdKWluTP67OOnV_dF3KpuwtK3dPKWTCo2j9VCa7X1I4h0CNuM79DHhY2wO7sL8WBej7BSNA3N2TUsp_YTWWfrvsr_vVhJf-32G7w_12ms_PNFUwj2C30ZZIPWc-uEkDztyMLdI-lu9q9TLrLdr0dOhfrtfkdeJx4pUSiHdJHf42kg7UAVK6JcA",
"expires_in": 86400,
"scope": "extra",
"token_type": "Bearer"
}
```
#### Decode token
The easiest way to decode the access token and review its contents is to use the [JWT.io Debugger](https://jwt.io/#debugger-io).
Copy your access token and paste it into the editor. The JWT is decoded automatically and its contents are displayed.
Note that the last two items of the **Payload** have both been set by your hook:
* `"scope": "extra"`
* `"https://foo.com/claim": "bar"`
## Learn more
* [Auth0 Hooks](/docs/customize/hooks)
* [Client Credentials Flow](/docs/get-started/authentication-and-authorization-flow/client-credentials-flow)
* [Call Your API Using the Client Credentials Flow](/docs/get-started/authentication-and-authorization-flow/client-credentials-flow/call-your-api-using-the-client-credentials-flow)
# Client-Initiated Backchannel Authentication Flow
Source: https://auth0.com/docs/get-started/authentication-and-authorization-flow/client-initiated-backchannel-authentication-flow
Learn how the CIBA flow lets a backend service initiate authentication on a separate device, such as a mobile app, without browser interaction.
To use Client-Initiated Backchannel Authentication (CIBA) features, you must have an Enterprise Plan or an appropriate add-on. Refer to [Auth0 Pricing](https://auth0.com/pricing/) for details.
The Client-Initiated Backchannel Authentication (CIBA) Flow is an OpenID Foundation standard that enables decoupled authentication and authorization using secure backchannel requests. The CIBA flow is designed for use cases where the device initiating a request (the consumption device) is different from the device a user uses to authenticate (the authentication device).
In a CIBA flow, there are two actors:
* Initiating user: The entity that initiates authentication or authorization on the consumption device. This could be a backend application, a human user, such as a customer service agent on a customer service application, or an AI agent performing a task on the end user’s behalf.
* Authorizing user: The end user who receives the authentication or authorization request on the authentication device and provides consent.
By decoupling authentication and authorization from the consumption device, the client application can directly call the OpenID Provider using a backchannel request. This provides enhanced security, as you can use more secure methods for client authentication like [mTLS](/docs/get-started/authentication-and-authorization-flow/authenticate-with-mtls) and [Private Key JWT](/docs/get-started/authentication-and-authorization-flow/authenticate-with-private-key-jwt) with the CIBA flow.
## Use cases
Common use cases for CIBA flow include:
* An AI agent uses human-in-the-loop approvals to request the user’s permission to complete an action requested by the user.
* A user has telephoned a call center, and the agent handling the call would like to access the caller’s personal information on their computer. The caller can consent to this by, for example, approving a push notification on their phone.
* A user would like to access a device with limited input capabilities, such as a bicycle you might rent in a city or a kiosk in a retail setting.
* A user initiates a sensitive transaction on a relatively insecure device and would like to authorize the transaction on a more secure device. For example, they might authorize a payment or change in personal details following a push notification on a personal mobile phone.
## Notification channels
Auth0 supports the following notification channels with CIBA:
* [Auth0 Guardian mobile push notifications](/docs/get-started/authentication-and-authorization-flow/client-initiated-backchannel-authentication-flow/mobile-push-notifications-with-ciba): Available for all [Enterprise plans](https://auth0.com/pricing). The user receives a push notification on their enrolled mobile device to authenticate or confirm transaction details. Authentication and authorization happen on the authentication device that receives the push notification. You can enable mobile push notifications with CIBA through:
* The Auth0 Guardian app
* A Custom app integrated with the Auth0 Guardian SDK
* [Email notifications](/docs/get-started/authentication-and-authorization-flow/client-initiated-backchannel-authentication-flow/email-notifications-with-ciba): Available as an add-on for [paid plans](https://auth0.com/pricing). The user receives an email to their verified email address. The email contains a link, and authentication and authorization happens via the browser.
By default, Auth0 uses and recommends Guardian push notifications for CIBA flows. Guardian push notifications are more secure than other channels such as email, which can be vulnerable to phishing attacks. You have to explicitly enable email notifications for CIBA flows.
## How it works
The following diagram describes the end-to-end CIBA flow:
1. The client application or consumption device requests user authentication or authorization.
2. The client application’s backend submits a `POST` request to the `/bc-authorize` endpoint.
3. Auth0 receives the `POST` request and sends a notification to the authentication device.
4. The authentication device retrieves the authorization details from Auth0 and presents them to the end user.
5. The end user reviews the request, including any contextual authorization details regarding the request.
6. The end user provides their response on the authentication device, which submits the user response to Auth0.
7. The client application’s backend polls the `/token` endpoint and receives the appropriate tokens upon completing the CIBA flow.
Because the CIBA flow is used for one-time asynchronous user authentication and authorization, CIBA does not create or store a grant containing the user’s consent for an application to access an API’s resources. If the user later authenticates using a different authentication flow, and that flow requests the same scopes the user previously consented to using CIBA, Auth0 will not have a record of that consent. Therefore, it will prompt the user to consent again.
## Entity Limits
The CIBA flow has the following limits:
* Up to 500 CIBA requests may be created per minute per tenant.
* Up to 5000 pending CIBA requests per tenant at any one time. A pending CIBA request is a request that has been initiated but has not yet received a response from the user. If a CIBA request expires without receiving a response, it may continue to count towards the 5000 limit for up to 24 hours.
## Get started
| Read... | To Learn... |
| - | - |
| [Configure Client-Initiated Backchannel Authentication](/docs/get-started/applications/configure-client-initiated-backchannel-authentication) | How to configure the CIBA grant type and notification channel for your application. |
| [Mobile push notifications with CIBA](/docs/get-started/authentication-and-authorization-flow/client-initiated-backchannel-authentication-flow/mobile-push-notifications-with-ciba) | How to authenticate users using the CIBA flow with mobile push notifications. |
| [Email notifications with CIBA](/docs/get-started/authentication-and-authorization-flow/client-initiated-backchannel-authentication-flow/email-notifications-with-ciba) | How to authenticate users using the CIBA flow with email notifications. |
| [User Authorization with CIBA](/docs/get-started/authentication-and-authorization-flow/client-initiated-backchannel-authentication-flow/user-authorization-with-ciba) | How to authorize users using the CIBA with Rich Authorization Requests (RAR) flow. |
# Email Notifications with CIBA
Source: https://auth0.com/docs/get-started/authentication-and-authorization-flow/client-initiated-backchannel-authentication-flow/email-notifications-with-ciba
Learn how to authenticate users with the Client-Initiated Backchannel Authentication Flow using email notifications.
To use Client-Initiated Backchannel Authentication (CIBA) features, you must have an Enterprise Plan or an appropriate add-on. Refer to [Auth0 Pricing](https://auth0.com/pricing/) for details.
When you use email notifications with CIBA, the user receives an email with a link that redirects them to authenticate or authorize a request in the browser.
When using email notifications with CIBA, the user logs in on the consumption device but completes authentication by clicking a link sent to their verified email address. When the user clicks the verification link, they are redirected to their browser, creating a session that Auth0 uses to track the authentication process and confirm the user's identity. This session is necessary to bridge the gap between the authentication device, in this case, the browser, and the consumption device, such as a Smart TV.
The following diagram explains the end-to-end CIBA with email notifications flow:
The following sections dive step-by-step into how user authentication works with CIBA using email notifications.
* [Prerequisites](#prerequisites)
* [Step 1: Client application initiates a CIBA request](#step-1%3A-client-application-initiates-a-ciba-request)
* [Step 2: Auth0 tenant acknowledges the CIBA request](#step-2%3A-auth0-tenant-acknowledges-the-ciba-request)
* [Step 3: Client application polls for a response](#step-3%3A-client-application-polls-for-a-response)
* [Step 4: Auth0 sends a link to the user's email address](#step-4%3A-auth0-sends-a-link-to-the-user’s-email-address)
* [Step 5: User authenticates in the browser](#step-5%3A-user-authenticates-in-the-browser)
* [Step 6: Browser presents consent details to the user](#step-6%3A-browser-sends-the-user-response-back-to-auth0)
* [Step 7: Auth0 receives user response after the flow completes](#step-7%3A-auth0-receives-user-response-after-the-flow-completes)
* [Step 8: Auth0 returns access token to client application](#step-8%3A-auth0-returns-access-token-to-client-application)
## Prerequisites
To initiate a CIBA email request using Auth0, you must:
* [Configure Client-Initiated Backchannel Authentication](/docs/get-started/applications/configure-client-initiated-backchannel-authentication) for your tenant and application, including [email notifications](/docs/get-started/applications/configure-client-initiated-backchannel-authentication/#configure-email-notifications).
* Set the `requested_expiry` parameter to a value between 301 to 259200 seconds (72 hours). To learn more, read [Configure notification channel](/docs/get-started/applications/configure-client-initiated-backchannel-authentication#configure-notification-channel).
* If using email notifications with CIBA and Rich Authorization Requests (RAR) for [user authorization](/docs/get-started/authentication-and-authorization-flow/client-initiated-backchannel-authentication-flow/user-authorization-with-ciba), [set the customized consent prompt](/docs/get-started/apis/configure-rich-authorization-requests#set-customized-consent-prompt).
## Step 1: Client application initiates a CIBA request
Use the [User Search APIs](/docs/manage-users/user-search) to find the authorizing user for whom you’d like to initiate a CIBA request and obtain their user ID.
Once you have a user ID for the authorizing user, use the Authentication API or our [SDKs](/docs/libraries) to send a CIBA request to the `/bc-authorize` endpoint:
```bash lines theme={null}
curl --location 'https://{YOUR_DOMAIN}.auth0.com/bc-authorize' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id={YOUR_CLIENT_ID}' \
--data-urlencode 'client_secret={YOUR_CLIENT_SECRET}' \
--data-urlencode 'login_hint={ "format": "iss_sub", "iss": "https://{YOUR_DOMAIN}.auth0.com/", "sub": "{USER_ID}" }' \
--data-urlencode 'scope={SCOPES}' \
--data-urlencode 'binding_message={BINDING_MESSAGE}'
```
```csharp lines theme={null}
var response = await authenticationApiClient.ClientInitiatedBackchannelAuthorization(
new ClientInitiatedBackchannelAuthorizationRequest()
{
ClientId = "{YOUR_CLIENT_ID}",
Scope = "{SCOPES}",
ClientSecret = "{YOUR_CLIENT_SECRET}",
BindingMessage = "{BINDING_MESSAGE}",
LoginHint = new LoginHint()
{
Format = "iss_sub",
Issuer = "https://{YOUR_DOMAIN}.auth0.com/",
Subject = "{USER_ID}"
}
}
);
```
```go lines theme={null}
resp, err := authAPI.CIBA.Initiate(context.Background(), ciba.Request{
ClientID: mgmtClientID,
ClientSecret: mgmtClientSecret,
Scope: "openid",
LoginHint: map[string]string{
"format": "iss_sub",
"iss": "https://{YOUR_DOMAIN}.auth0.com/",
"sub": "{USER_ID}",
},
BindingMessage: "{BINDING_MESSAGE}",
})
```
```java lines theme={null}
//Creating AuthClient Instance
AuthAPI auth = AuthAPI.newBuilder(domain, clientId, clientSecret).build();
//Authorize
Map loginHint = new HashMap<>();
loginHint.put("format", "iss_sub");
loginHint.put("iss", "https://{YOUR_DOMAIN}.auth0.com/");
loginHint.put("sub", "{USER_ID}");
Request request = auth.authorizeBackChannel("openid", "{BINDING_MESSAGE}", loginHint);
BackChannelAuthorizeResponse resp = request.execute().getBody();
```
| Parameters | Description |
| - | - |
| `tenant` | Tenant name. It can also be a custom domain. If the `iss_sub` format is used, then the tenant name is passed within the `iss` claim. |
| `client_id` | Client application identifier. |
| `client_secret` | Client authentication method used for user authentication with CIBA, such as Client Secret, Private Key JWT, or mTLS Authentication. If you're using Private Key JWT or mTLS, you don't need to include the client secret. |
| `scope` | Must include `openid`.
The scope can optionally include `offline_access` to request a refresh token. However, for one-time authorization of a transaction with the CIBA Flow, a refresh token is not needed and does not have any meaning in this context. |
| `user_id` | User ID for the authorizing user that is passed within the `login_hint` structure. If `iss_sub` format is used, then the user ID is passed within the `sub` claim.
The user ID may have a different format depending on the external provider. |
| `requested_expiry` | The maximum duration, in seconds, for which the CIBA session should be valid. The CIBA flow's requested expiry is between 1 and 259200 seconds (72 hours), and it defaults to 300 seconds. Include the `requested_expiry` parameter to set a custom expiry for the CIBA flow.
The `requested_expiry` parameter helps determine which notification channel CIBA uses:
If you set your `requested_expiry` to a value of 300 or lower in seconds, CIBA uses the mobile push notification channel if enabled. If you have not configured MFA for your tenant, the CIBA request fails.
If you set your `requested_expiry` to a value between 301 to 259200 seconds (72 hours), CIBA uses the email notification channel if enabled.
|
| `binding_message` | Human-readable message used to bind the CIBA flow across the authentication and consumption devices. The binding message is required and up to 64 characters. Use only alphanumeric and `+-_.,:#` characters. |
There is a user-specific rate limit where the authorizing user will not be sent more than 5 requests per minute.
## Step 2: Auth0 tenant acknowledges the CIBA request
If the Auth0 tenant successfully receives the `POST` request, you should receive a response containing an `auth-req-id` that references the request:
```json lines theme={null}
{
"auth_req_id": "eyJh...",
"expires_in": 300,
"interval": 5
}
```
The `auth_req_id` value is passed to the `/token` endpoint to poll for the completion of the CIBA flow.
## Step 3: Client application polls for a response
Use the Authentication API or our [SDKs](/docs/libraries) to call the `/token` endpoint using the `urn:openid:params:grant-type:ciba` grant type and the `auth_req_id` you received from the `/bc-authorize` endpoint:
```bash lines theme={null}
curl --location 'https://{YOUR_DOMAIN}.auth0.com/oauth/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id={YOUR_CLIENT_ID}' \
--data-urlencode 'client_secret={YOUR_CLIENT_SECRET}' \
--data-urlencode 'auth_req_id={AUTH_REQ_ID}' \
--data-urlencode 'grant_type=urn:openid:params:grant-type:ciba'
```
```csharp lines theme={null}
var token = await authenticationApiClient.GetTokenAsync(
new ClientInitiatedBackchannelAuthorizationTokenRequest()
{
AuthRequestId = response.AuthRequestId,
ClientId = "{YOUR_CLIENT_ID}",
ClientSecret = "{YOUR_CLIENT_SECRET}"
}
);
```
```go lines theme={null}
token, err := authAPI.OAuth.LoginWithGrant(context.Background(),
"urn:openid:params:grant-type:ciba",
url.Values{
"auth_req_id": []string{resp.AuthReqID},
"client_id": []string{clientID},
"client_secret": []string{clientSecret},
},
oauth.IDTokenValidationOptions{})
```
```java lines theme={null}
Request tokenRequest = auth.getBackChannelLoginStatus(authReqId, "grant-type");
BackChannelTokenResponse tokenResponse = tokenRequest.execute().getBody();
```
Until the authorizing user approves the transaction, you should receive the following response:
```json lines theme={null}
{
"error": "authorization_pending",
"error_description": "The end-user authorization is pending"
}
```
There is approximately a five-second wait interval for polling. If you poll too frequently, you will receive the following response, where the description varies depending on the backoff interval:
```json lines theme={null}
{
"error": "slow_down",
"error_description": "You are polling faster than allowed. Try again in 10 seconds."
"interval": 10
}
```
To resolve the error, wait until the next interval (in seconds) to poll the `/token` endpoint.
## Step 4: Auth0 sends a link to the user’s email address
The Auth0 Authorization Server uses the `login_hint`, which contains the user ID for the authorizing user, to initiate user authentication on the authentication device:
* The Auth0 Authorization Server sends an email to the user's verified email address.
* The email contains a verification link that the user must click to authenticate. The `binding_message` shows up as the request code.
* The link directs the user to the browser through a request to the `/bc-verify` endpoint, where the `consent` query parameter references the CIBA request awaiting consent.
## Step 5: User authenticates in the browser
If no active session is found, the verification link will ask the user to authenticate. The user clicks the link to proceed with user authentication.
To authenticate, the user enters their verified email address and password. The user must use the credentials provided to the `login_hint` parameter sent to the `/bc-authorize` endpoint when the client application [initiates a CIBA request](#step-1%3A-client-application-initiates-a-ciba-request). Otherwise, the user is prompted with an error message and needs to log out and try again.
Similar to a standard login flow, the`post-login` Actions trigger runs in the CIBA with email flow, enabling customers to provide custom logic to apply access control policies or ask for additional MFA factors. When executed from a CIBA verification link, the `event.transaction.protocol` value is `oidc-ciba-web-link`, allowing you to apply custom rules to this specific type of login. To learn more, read [Login Trigger](https://auth0.com/docs/customize/actions/explore-triggers/signup-and-login-triggers/login-trigger).
Once authenticated, the browser presents the consent details to the user from the Auth0 Consent API, which includes the `binding_message`, `scope`, and `audience`. The scopes are filtered according to your RBAC policy. To learn more, read [Role-Based Access Control](/docs/manage-users/access-control/rbac).
The following code sample is an example response from the Auth0 Consent API:
```json lines theme={null}
{
"id": "cns_abc123",
"requested_details": {
"audience": "https://$tenant.auth0.com/userinfo",
"scope": ["openid"],
"binding_message": "21-49-38"
},
"created_at": 1746693720
"expires_at": 1746693750
}
```
The user can accept or decline the authentication request at this point.
## Step 6: Browser sends the user response back to Auth0
The browser sends the user response back to Auth0. Depending on whether the user accepts or rejects the authentication request, Auth0 displays the following consent screens, which you need to customize by [setting the consent prompts](/docs/get-started/apis/configure-rich-authorization-requests#set-customized-consent-prompt):
### User accepts the authentication request
### User rejects the authentication request
## Step 7: Auth0 receives user response after the flow completes
The client application completes the polling upon receiving a response from the `/token` endpoint. A CIBA flow always requires a response, either an approval or decline, from the authorizing user, and existing grants are not checked.
## Step 8: Auth0 returns access token to client application
If the user rejects the email request, Auth0 returns an error response like the following to the client application:
```json lines theme={null}
{
"error": "access_denied",
"error_description": "The end-user denied the authorization request or it has been expired"
}
```
If the user approves the email request, Auth0 returns an access token like the following to the client application:
```json lines theme={null}
{
"access_token": "eyJh...",
"id_token": "eyJh...",
"expires_in": 86400,
"scope": "openid",
"token_type": "Bearer"
}
```
The `refresh_token` will only be present if the `offline_access` scope was included in the initial `/bc-authorize` request.
## Learn more
* [Client-Initiated Backchannel Authentication Flow](/docs/get-started/authentication-and-authorization-flow/client-initiated-backchannel-authentication-flow)
* [Configure Client-Initiated Backchannel Authentication](/docs/get-started/applications/configure-client-initiated-backchannel-authentication)
# Mobile Push Notifications with CIBA
Source: https://auth0.com/docs/get-started/authentication-and-authorization-flow/client-initiated-backchannel-authentication-flow/mobile-push-notifications-with-ciba
Learn how to authenticate users with the Client-Initiated Backchannel Authentication Flow using mobile push notifications.
To use Client-Initiated Backchannel Authentication (CIBA) features, you must have an Enterprise Plan or an appropriate add-on. Refer to [Auth0 Pricing](https://auth0.com/pricing/) for details.
When you use mobile push notifications with CIBA, the user receives a push notification to authenticate or authorize a request on their enrolled mobile device. You can send mobile push notifications with CIBA using the Auth0 Guardian app or a custom app integrated with the Auth0 Guardian SDK.
The CIBA flow with mobile push notifications authenticates and authorizes users on their mobile device, bypassing the need for a browser. Because the consumption device doesn't require an active browser session, the user doesn't need to be logged in before a CIBA request is triggered. This also ensures that the CIBA flow won't impact any existing sessions the user may have.
The following diagram explains the end-to-end CIBA with mobile push notifications flow:
The following sections dive step-by-step into how user authentication works with CIBA using mobile push notifications.
* [Prerequisites](#prerequisites)
* [Step 1: Client application initiates a CIBA request](#step-1%3A-client-application-initiates-a-ciba-request)
* [Step 2: Auth0 tenant acknowledges the CIBA request](#step-2%3A-auth0-tenant-acknowledges-the-ciba-request)
* [Step 3: Client application polls for a response](#step-3%3A-client-application-polls-for-a-response)
* [Step 4: Mobile application receives the push notification](#step-4%3A-mobile-application-receives-the-push-notification)
* [Step 5: Mobile application retrieves the consent details](#step-5%3A-mobile-application-retrieves-the-consent-details)
* [Step 6: Mobile application presents the consent details to the user](#step-6%3A-mobile-application-presents-the-consent-details-to-the-user)
* [Step 7: Mobile application sends the user response back to Auth0](#step-7%3A-mobile-application-sends-the-user-response-back-to-auth0)
* [Step 8: Auth0 receives user response after the flow completes](#step-8%3A-auth0-receives-user-response-after-the-flow-completes)
* [Step 9: Auth0 returns access token to client application](#step-9%3A-auth0-returns-access-token-to-client-application)
## Prerequisites
To initiate a CIBA push request using Auth0, you must:
* [Configure Client-Initiated Backchannel Authentication](/docs/get-started/applications/configure-client-initiated-backchannel-authentication) for your tenant and application, including [mobile push notifications](/docs/get-started/applications/configure-client-initiated-backchannel-authentication/#configure-mobile-push-notifications).
* Set the `requested_expiry` parameter to a value of 300 or lower in seconds. To learn more, read [Configure notification channel](/docs/get-started/applications/configure-client-initiated-backchannel-authentication#configure-notification-channel).
## Step 1: Client application initiates a CIBA request
Use the [User Search APIs](/docs/manage-users/user-search) to find the authorizing user for whom you’d like to initiate a CIBA request and obtain their user ID.
Once you have a user ID for the authorizing user, use the Authentication API or our [SDKs](/docs/libraries) to send a CIBA request to the `/bc-authorize` endpoint:
```bash lines theme={null}
curl --location 'https://{YOUR_DOMAIN}.auth0.com/bc-authorize' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id={YOUR_CLIENT_ID}' \
--data-urlencode 'client_secret={YOUR_CLIENT_SECRET}' \
--data-urlencode 'login_hint={ "format": "iss_sub", "iss": "https://{YOUR_DOMAIN}.auth0.com/", "sub": "{USER_ID}" }' \
--data-urlencode 'scope={SCOPES}' \
--data-urlencode 'binding_message={BINDING_MESSAGE}'
```
```csharp lines theme={null}
var response = await authenticationApiClient.ClientInitiatedBackchannelAuthorization(
new ClientInitiatedBackchannelAuthorizationRequest()
{
ClientId = "{YOUR_CLIENT_ID}",
Scope = "openid",
ClientSecret = "{YOUR_CLIENT_SECRET}",
BindingMessage = "{BINDING_MESSAGE}",
LoginHint = new LoginHint()
{
Format = "iss_sub",
Issuer = "https://{YOUR_DOMAIN}.auth0.com/",
Subject = "{USER_ID}"
}
}
);
```
```go lines theme={null}
resp, err := authAPI.CIBA.Initiate(context.Background(), ciba.Request{
ClientID: mgmtClientID,
ClientSecret: mgmtClientSecret,
Scope: "openid",
LoginHint: map[string]string{
"format": "iss_sub",
"iss": "https://{YOUR_DOMAIN}.auth0.com/",
"sub": "{USER_ID}",
},
BindingMessage: "{BINDING_MESSAGE}",
})
```
```java lines theme={null}
//Creating AuthClient Instance
AuthAPI auth = AuthAPI.newBuilder(domain, clientId, clientSecret).build();
//Authorize
Map loginHint = new HashMap<>();
loginHint.put("format", "iss_sub");
loginHint.put("iss", "https://{YOUR_DOMAIN}.auth0.com/");
loginHint.put("sub", "{USER_ID}");
Request request = auth.authorizeBackChannel("openid", "{BINDING_MESSAGE}", loginHint);
BackChannelAuthorizeResponse resp = request.execute().getBody();
```
| Parameters | Description |
| - | - |
| `tenant` | Tenant name. It can also be a custom domain. If the `iss_sub` format is used, then the tenant name is passed within the `iss` claim. |
| `client_id` | Client application identifier. |
| `client_secret` | Client authentication method used for user authentication with CIBA, such as Client Secret, Private Key JWT, or mTLS Authentication. If you're using Private Key JWT or mTLS, you don't need to include the client secret. |
| `scope` | Must include `openid`.
The scope can optionally include `offline_access` to request a refresh token. However, for one-time authorization of a transaction with the CIBA Flow, a refresh token is not needed and does not have any meaning in this context. |
| `user_id` | User ID for the authorizing user that is passed within the `login_hint` structure. If `iss_sub` format is used, then the user ID is passed within the `sub` claim.
The user ID may have a different format depending on the external provider. |
| `requested_expiry` | The maximum duration, in seconds, for which the CIBA session should be valid. The CIBA flow's requested expiry is between 1 and 259200 seconds (72 hours), and it defaults to 300 seconds. Include the `requested_expiry` parameter to set a custom expiry for the CIBA flow.
The `requested_expiry` parameter helps determine which notification channel CIBA uses:
If you set your `requested_expiry` to a value of 300 or lower in seconds, CIBA uses the mobile push notification channel if enabled. If you have not configured MFA for your tenant, the CIBA request fails.
If you set your `requested_expiry` to a value between 301 to 259200 seconds (72 hours), CIBA uses the email notification channel if enabled.
|
| `binding_message` | Human-readable message used to bind the CIBA flow across the authentication and consumption devices. The binding message is required and up to 64 characters. Use only alphanumeric and `+-_.,:#` characters. |
There is a user-specific rate limit where the authorizing user will not be sent more than 5 requests per minute.
## Step 2: Auth0 tenant acknowledges the CIBA request
If the Auth0 tenant successfully receives the `POST` request, you should receive a response containing an `auth-req-id` that references the request:
```json lines theme={null}
{
"auth_req_id": "eyJh...",
"expires_in": 300,
"interval": 5
}
```
The `auth_req_id` value is passed to the `/token` endpoint to poll for the completion of the CIBA flow.
## Step 3: Client application polls for a response
Use the Authentication API or our [SDKs](/docs/libraries) to call the `/token` endpoint using the `urn:openid:params:grant-type:ciba` grant type and the `auth_req_id` you received from the `/bc-authorize` endpoint:
```bash lines theme={null}
curl --location 'https://$tenant.auth0.com/oauth/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=' \
--data-urlencode 'client_secret=' \
--data-urlencode 'auth_req_id=' \
--data-urlencode 'grant_type=urn:openid:params:grant-type:ciba'
```
```csharp lines theme={null}
var token = await authenticationApiClient.GetTokenAsync(
new ClientInitiatedBackchannelAuthorizationTokenRequest()
{
AuthRequestId = response.AuthRequestId,
ClientId = "",
ClientSecret = ""
}
);
```
```go lines theme={null}
token, err := authAPI.OAuth.LoginWithGrant(context.Background(),
"urn:openid:params:grant-type:ciba",
url.Values{
"auth_req_id": []string{resp.AuthReqID},
"client_id": []string{clientID},
"client_secret": []string{clientSecret},
},
oauth.IDTokenValidationOptions{})
```
```java lines theme={null}
Request tokenRequest = auth.getBackChannelLoginStatus(authReqId, "grant-type");
BackChannelTokenResponse tokenResponse = tokenRequest.execute().getBody();
```
Until the authorizing user approves the transaction, you should receive the following response:
```json lines theme={null}
{
"error": "authorization_pending",
"error_description": "The end-user authorization is pending"
}
```
There is approximately a five-second wait interval for polling. If you poll too frequently, you will receive the following response, where the description varies depending on the backoff interval:
```json lines theme={null}
{
"error": "slow_down",
"error_description": "You are polling faster than allowed. Try again in 10 seconds."
"interval": 10
}
```
To resolve the error, wait until the next interval (in seconds) to poll the `/token` endpoint.
## Step 4: Mobile application receives the push notification
Auth0 sends a push notification to the user's registered mobile app or device via the Auth0 Guardian app or a custom app integrated with the [Auth0 Guardian SDK](/docs/secure/multi-factor-authentication/auth0-guardian).
If you're using a custom app, the [Auth0 Guardian SDK](/docs/secure/multi-factor-authentication/auth0-guardian) provides methods to parse the data received from the push notification and return a ready-to-use `Notification` instance. The `Notification` instance includes a transaction linking ID, or `txlinkid`, that the mobile application uses to retrieve the consent details from Auth0.
The following code samples are example iOS and Android mobile push notification implementations using the Guardian SDK:
```swift lines theme={null}
//implementing UNUserNotificationCenterDelegate
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: (UNNotificationPresentationOptions) -> Void) {
let userInfo = notification.request.content.userInfo
if let notification = Guardian.notification(from: userInfo) {
// Implement this function to display the prompt and handle user's consent/rejection.
handleGuardianNotification(notification: notification)
}
}
```
```kotlin lines theme={null}
// at the FCM listener you receive a RemoteMessage
@Override
public void onMessageReceived(RemoteMessage message) {
Notification notification = Guardian.parseNotification(message.getData());
if (notification != null) {
// you received a Guardian notification, handle it
handleGuardianNotification(notification);
return;
}
/* handle other push notifications you might be using ... */
}
```
## Step 5: Mobile application retrieves the consent details
Your Auth0 Guardian app or custom app integrated with the Auth0 Guardian SDK retrieves the consent details i.e. the contents of the `binding_message` from the Auth0 Consent API.
If you're using a custom app, the following code samples are example iOS and Android implementations that retrieve data from the Auth0 Consent API:
```swift lines theme={null}
let device: AuthenticationDevice = // the object you obtained during the initial Guardian SDK enrollment process and stored locally
if let consentId = notification.transactionLinkingId {
Guardian
.consent(forDomain: {yourTenantDomain}, device: device)
.fetch(consentId: consentId, notificationToken: notification.transactionToken)
.start{result in
switch result {
case .success(let payload):
// present consent details to the user
case .failure(let cause):
// something went wrong
}
}
}
```
```kotlin lines theme={null}
Enrollment enrollment = // the object you obtained during the initial Guardian SDK enrollment process and stored locally
if (notification.getTransactionLinkingId() != null) {
guardian
.fetchConsent(notification, enrollment)
.start(new Callback {
@Override
void onSuccess(RichConsent consentDetails) {
// present consent details to the user
}
@Override
void onFailure(Throwable exception) {
// something went wrong
}
});
}
```
## Step 6: Mobile application presents the consent details to the user
The Auth0 Consent API responds to the Auth0 Guardian app or your custom app integrated with the Auth0 Guardian SDK with the consent details, including the `binding_message`, `scope`, and `audience`. The scopes returned to the mobile application are filtered according to your RBAC policy. To learn more, read [Role-Based Access Control](/docs/manage-users/access-control/rbac).
The mobile application presents the authentication request and/or the consent details to the user.
The following code sample is an example response from the Auth0 Consent API:
```json lines theme={null}
{
"id": "cns_abc123",
"requested_details": {
"audience": "https://$tenant.auth0.com/userinfo",
"scope": ["openid"],
"binding_message": "21-49-38"
},
"created_at": 1746693720
"expires_at": 1746693750
}
```
The user can accept or decline the authentication request at this point.
## Step 7: Mobile application sends the user response back to Auth0
The Auth0 Guardian app or your custom app sends the user response back to Auth0.
If you're using a custom app integrated with the Auth0 Guardian SDK, the following code samples are example iOS and Android implementations that handle the user response:
### User accepts the authentication request
```swift lines theme={null}
Guardian
.authentication(forDomain: "{yourTenantDomain}", device: device)
.allow(notification: notification)
// or reject(notification: notification, withReason: "hacked")
.start { result in
switch result {
case .success:
// the auth request was successfully rejected
case .failure(let cause):
// something failed, check cause to see what went wrong
}
}
```
```kotlin lines theme={null}
guardian
.allow(notification, enrollment)
.execute(); // or start(new Callback<> ...)
```
### User rejects the authentication request
```swift lines theme={null}
Guardian
.authentication(forDomain: "{yourTenantDomain}", device: device)
.reject(notification: notification)
// or reject(notification: notification, withReason: "hacked")
.start { result in
switch result {
case .success:
// the auth request was successfully rejected
case .failure(let cause):
// something failed, check cause to see what went wrong
}
}
```
```kotlin lines theme={null}
guardian
.reject(notification, enrollment) // or reject(notification, enrollment, reason)
.execute(); // or start(new Callback<> ...)
```
## Step 8: Auth0 receives user response after the flow completes
The client application completes the polling upon receiving a response from the `/token` endpoint. A CIBA flow always requires a response, either an approval or decline, from the authorizing user, and existing grants are not checked.
## Step 9: Auth0 returns access token to client application
If the user rejects the push request, Auth0 returns an error response like the following to the client application:
```json lines theme={null}
{
"error": "access_denied",
"error_description": "The end-user denied the authorization request or it has been expired"
}
```
If the user approves the push request, Auth0 returns an access token like the following to the client application:
```json lines theme={null}
{
"access_token": "eyJh...",
"id_token": "eyJh...",
"expires_in": 86400,
"scope": "openid",
"token_type": "Bearer"
}
```
The `refresh_token` will only be present if the `offline_access` scope was included in the initial `/bc-authorize` request.
## Learn more
* [Client-Initiated Backchannel Authentication Flow](/docs/get-started/authentication-and-authorization-flow/client-initiated-backchannel-authentication-flow)
* [Configure Client-Initiated Backchannel Authentication](/docs/get-started/applications/configure-client-initiated-backchannel-authentication)
# User Authorization with CIBA
Source: https://auth0.com/docs/get-started/authentication-and-authorization-flow/client-initiated-backchannel-authentication-flow/user-authorization-with-ciba
Learn how to use Rich Authorization Requests with the Client-Initiated Backchannel Flow.
To use Client-Initiated Backchannel Authentication (CIBA) features, you must have an Enterprise Plan or an appropriate add-on. Refer to [Auth0 Pricing](https://auth0.com/pricing/) for details.
[Client-Initiated Backchannel Authentication (CIBA)](/docs/get-started/authentication-and-authorization-flow/client-initiated-backchannel-authentication-flow) is an OAuth 2.0 specification that allows a client application to initiate an authentication and/or authorization flow without requiring direct user interaction on the initiating application. [Rich Authorization Requests (RAR)](/docs/get-started/apis/configure-rich-authorization-requests) is an OAuth 2.0 extension that allows client applications to request for more complex permissions beyond standard OAuth 2.0 scopes in an authorization request.
You can use CIBA with RAR to pass fine-grained authorization data to the authorization server in a backchannel request. The `authorization_details` parameter contains details about the request that you can customize in a consent prompt to show the user.
You can authorize users with CIBA using the following notification channels:
* [Mobile push notifications](/docs/get-started/authentication-and-authorization-flow/client-initiated-backchannel-authentication-flow/mobile-push-notifications-with-ciba) using the Auth0 Guardian app and a custom app integrated with the Auth0 Guardian SDK.
* [Email notifications](/docs/get-started/authentication-and-authorization-flow/client-initiated-backchannel-authentication-flow/email-notifications-with-ciba), which require setting a customized consent prompt.
## Common use cases
Use RAR with the CIBA flow for use cases that require more fine-grained control over resource access. Common use cases include:
1. A payments app prompts the user to confirm a money transfer. The `authorization_details` can be customized to show the transaction details.
2. An AI agent prompts the user with details about a rescheduled doctor’s appointment. The `authorization_details` can be customized to show the new time and date.
## How it works
The User Authorization with CIBA flow is similar to the User Authentication with CIBA flow, where RAR support enables clients to pass the `authorization_details` to the authorization server via the `/bc-authorize` endpoint.
The following sequence diagram explains the end-to-end User Authorization with CIBA flow:
The following sections dive step-by-step into how user authorization works with CIBA.
* [Prerequisites](#prerequisites)
* [Step 1: Client application initiates a CIBA request](#step-1%3A-client-application-initiates-a-ciba-request)
* [Step 2: Auth0 tenant acknowledges the CIBA request](#step-2%3A-auth0-tenant-acknowledges-the-ciba-request)
* [Step 3: Client application polls for a response](#step-3%3A-client-application-polls-for-a-response)
* [Step 4: Authentication device receives the push notification](#step-4%3A-authentication-device-receives-the-notification)
* [Step 5: Authentication device retrieves the consent details](#step-5%3A-authentication-device-retrieves-the-consent-details)
* [Step 6: Authentication device presents the consent details to the user](#step-6%3A-authentication-device-presents-the-consent-details-to-the-user)
* [Step 7: Authentication device sends the user response back to Auth0](#step-7%3A-authentication-device-sends-the-user-response-back-to-auth0)
* [Step 8: Auth0 receives user response after the flow completes](#step-8%3A-auth0-receives-user-response-after-the-flow-completes)
* [Step 9: Auth0 returns access token to the client application](#step-9%3A-auth0-returns-access-token-to-client-application)
## Prerequisites
To initiate a CIBA request using Auth0, you must:
* [Configure Client-Initiated Backchannel Authentication](/docs/get-started/applications/configure-client-initiated-backchannel-authentication) for your tenant and application, including your [notification channel](/docs/get-started/applications/configure-client-initiated-backchannel-authentication#configure-notification-channel).
* [Configure Rich Authorization Requests](/docs/get-started/apis/configure-rich-authorization-requests) for your resource server, which includes registering your `authorization_details` types.
* If you're using email notifications with CIBA with RAR, [set a customized consent prompt](/docs/get-started/apis/configure-rich-authorization-requests#set-customized-consent-prompt).
## Step 1: Client application initiates a CIBA request
Use the [User Search APIs](/docs/manage-users/user-search) to find the authorizing user for whom you’d like to initiate a CIBA request and obtain their user ID.
Once you have a user ID for the authorizing user, use the [Authentication API](https://auth0.com/docs/api/authentication/login/start-back-channel-login) to send a CIBA request with the `authorization_details` to the `/bc-authorize` endpoint:
```bash lines theme={null}
curl --location 'https://{YOUR_DOMAIN}.auth0.com/bc-authorize' \
--request POST \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id={YOUR_CLIENT_ID}' \
--data-urlencode 'client_secret={YOUR_CLIENT_SECRET}' \
--data-urlencode 'login_hint={ "format": "iss_sub", "iss": "https://{YOUR_DOMAIN}.auth0.com/", "sub":"{USER_ID}"}' \
--data-urlencode 'audience=https://api.example.com' \
--data-urlencode 'binding_message=Confirm payment of 2500' \
--data-urlencode 'authorization_details=[{
"type": "money_transfer",
"instructedAmount": {
"amount": 2500,
"currency": "USD"
},
"sourceAccount": "xxxxxxxxxxx1234",
"destinationAccount": "xxxxxxxxxxx9876",
"beneficiary": "Hanna Herwitz",
"subject": "A Lannister Always Pays His Debts"
}]'
```
| Parameters | Description |
| - | - |
| `tenant` | Tenant name that is passed within the `login_hint` structure. It can also be a custom domain. If the `iss_sub` format is used, then the tenant name is passed within the `iss` claim.
**Example**: `login_hint={"format": "iss_sub", "iss": "https://{YOUR_DOMAIN}.auth0.com/", "sub":"{USER_ID"}` |
| `client_id` | Client application identifier. |
| `client_secret` | Client authentication method used for user authentication with CIBA, such as Client Secret, Private Key JWT, or mTLS Authentication. If you're using Private Key JWT or mTLS, you don't need to include the client secret. |
| `scope` | Must include `openid`.
The scope can optionally include `offline_access` to request a refresh token. However, for one-time authorization of a transaction with the CIBA Flow, a refresh token is not needed and does not have any meaning in this context. |
| `user_id` | User ID for the authorizing user that is passed within the `login_hint` structure. If `iss_sub` format is used, then the user ID is passed within the `sub` claim.
The user ID may have a different format depending on the external provider. |
| `requested_expiry` | The CIBA flow's requested expiry is between 1 and 259200 (72 hours) seconds, and it defaults to 300 seconds. Include the `requested_expiry` parameter to set a custom expiry for the CIBA flow.
The `requested_expiry` parameter helps determine which notification channel CIBA uses:
If you set your `requested_expiry` to a value of 300 or lower in seconds, CIBA uses the mobile push notification channel if enabled. If you have not configured MFA for your tenant, the CIBA request fails.
If you set your `requested_expiry` to a value between 301 to 259200 seconds, CIBA uses the email notification channel if enabled.
|
| `binding_message` | Human-readable message used to bind the CIBA flow across the authentication and consumption devices. The binding message is required and up to 64 characters. Use only alphanumeric and `+-_.,:#` characters |
| `audience` | Unique identifier of the audience for the issued token. |
| `authorization_details` | An optional JSON array of objects that describes the permissions to be authorized. You should register each object’s `type` value on the resource server using the resource server’s `authorization_details` parameter. To learn more, read [Configure Rich Authorization Requests](/docs/get-started/apis/configure-rich-authorization-requests). |
## Step 2: Auth0 tenant acknowledges the CIBA request
If the Auth0 tenant successfully receives the `POST` request, you should receive a response containing an `auth-req-id` that references the request:
```json lines theme={null}
{
"auth_req_id": "eyJh...",
"expires_in": 300,
"interval": 5
}
```
The `auth_req_id` value is passed to the `/token` endpoint to poll for the completion of the CIBA flow.
## Step 3: Client application polls for a response
Use the [Authentication API](https://auth0.com/docs/api/authentication/login/start-back-channel-login) to call the `/token` endpoint using the `urn:openid:params:grant-type:ciba` grant type and the `auth_req_id` you received from the `/bc-authorize` endpoint:
```bash lines theme={null}
curl --location 'https://{YOUR_DOMAIN}.auth0.com/oauth/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id={YOUR_CLIENT_ID}' \
--data-urlencode 'client_secret={YOUR_CLIENT_SECRET}' \
--data-urlencode 'auth_req_id={AUTH_REQ_ID}' \
--data-urlencode 'grant_type=urn:openid:params:grant-type:ciba'
```
```csharp lines theme={null}
var token = await authenticationApiClient.GetTokenAsync(
new ClientInitiatedBackchannelAuthorizationTokenRequest()
{
AuthRequestId = response.AuthRequestId,
ClientId = "your-client-id",
ClientSecret = "your-client-secret"
}
);
```
```go lines theme={null}
token, err := authAPI.OAuth.LoginWithGrant(context.Background(),
"urn:openid:params:grant-type:ciba",
url.Values{
"auth_req_id": []string{resp.AuthReqID},
"client_id": []string{clientID},
"client_secret": []string{clientSecret},
},
oauth.IDTokenValidationOptions{})
```
```java lines theme={null}
Request tokenRequest = auth.getBackChannelLoginStatus(authReqId, "grant-type");
BackChannelTokenResponse tokenResponse = tokenRequest.execute().getBody();
```
Until the authorizing user approves the transaction, you should receive the following response:
```json lines theme={null}
{
"error": "authorization_pending",
"error_description": "The end-user authorization is pending"
}
```
There is approximately a five-second wait interval for polling. If you poll too frequently, you will receive the following response, where the description varies depending on the backoff interval:
```json lines theme={null}
{
"error": "slow_down",
"error_description": "You are polling faster than allowed. Try again in 10 seconds."
"interval": 10
}
```
To resolve the error, wait until the next interval (in seconds) to poll the `/token` endpoint.
## Step 4: Authentication device receives the notification
Depending on the notification channel, Auth0 sends a notification to the authentication device:
* [Mobile push notification](/docs/get-started/authentication-and-authorization-flow/client-initiated-backchannel-authentication-flow/mobile-push-notifications-with-ciba#step-4%3A-mobile-application-receives-the-push-notification): Auth0 sends it to the Auth0 Guardian app or a custom mobile app integrated with the Auth0 Guardian SDK.
* [Email notification](/docs/get-started/authentication-and-authorization-flow/client-initiated-backchannel-authentication-flow/email-notifications-with-ciba#step-4%3A-auth0-sends-a-link-to-the-user’s-email-address): Auth0 sends it to the user’s verified email address.
## Step 5: Authentication device retrieves the consent details
The authentication device retrieves the consent details i.e. the contents of the `binding_message` from the Auth0 Consent API:
* [Mobile push notification](/docs/get-started/authentication-and-authorization-flow/client-initiated-backchannel-authentication-flow/mobile-push-notifications-with-ciba#step-5%3A-mobile-application-retrieves-the-consent-details): The Auth0 Guardian app or a custom app integrated with the Auth0 Guardian SDK calls the Auth0 Consent API to retrieve the consent details.
* [Email notification](/docs/get-started/authentication-and-authorization-flow/client-initiated-backchannel-authentication-flow/email-notifications-with-ciba#step-5%3A-user-authenticates-in-the-browser): When the user clicks on the verification link, they are redirected to the browser, which retrieves the consent details from the Auth0 Consent API.
## Step 6: Authentication device presents the consent details to the user
The Auth0 Consent API responds to the authentication device with the consent details, including the `binding_message`, `scope`, `audience`, and `authorization_details` if configured. The scopes returned to the mobile application are filtered according to your RBAC policy. To learn more, read [Role-Based Access Control](/docs/manage-users/access-control/rbac).
The following code sample is an example response from the Auth0 Consent API:
```json lines theme={null}
{
"id": "cns_2309dsfsd098",
"requested_details": {
"audience": "https://api.example.com",
"scope": ["read:profile", "write:profile"],
"binding_message": "abc123",
"authorization_details": [
{
"type": "money_transfer",
"instructedAmount": {
"amount": 2500,
"currency": "USD"
},
"sourceAccount": "xxxxxxxxxxx1234",
"destinationAccount": "xxxxxxxxxxx9876",
"beneficiary": "Hanna Herwitz",
"subject": "A Lannister Always Pays His Debts"
}
]
},
"created_at": 1632739200,
"expires_at": 1632739200
}
```
The authentication device presents the consent details with the `authorization_details` to the user:
* [Mobile push notification](/docs/get-started/authentication-and-authorization-flow/client-initiated-backchannel-authentication-flow/mobile-push-notifications-with-ciba#step-6%3A-mobile-application-presents-the-consent-details-to-the-user): The Auth0 Guardian app renders the `authorization_details` in a consent screen using a push notification.
* [Email notification](/docs/get-started/authentication-and-authorization-flow/client-initiated-backchannel-authentication-flow/email-notifications-with-ciba#step-6%3A-browser-sends-the-user-response-back-to-auth0): The browser renders the `authorization_details` in a custom consent screen. To learn how to customize the consent screen, read [Set customized consent prompt](/docs/get-started/apis/configure-rich-authorization-requests#set-customized-consent-prompt).
The user can accept or decline the authorization request at this point.
## Step 7: Authentication device sends the user response back to Auth0
After the user accepts or declines the authorization request, the authentication device sends the user response back to Auth0:
* [Mobile push notification](/docs/get-started/authentication-and-authorization-flow/client-initiated-backchannel-authentication-flow/mobile-push-notifications-with-ciba#step-7%3A-mobile-application-sends-the-user-response-back-to-auth0): The Auth0 Guardian app or a custom app integrated with the Auth0 Guardian SDK sends the user response back to Auth0.
* [Email notification](/docs/get-started/authentication-and-authorization-flow/client-initiated-backchannel-authentication-flow/email-notifications-with-ciba#step-6%3A-browser-sends-the-user-response-back-to-auth0): The browser sends the user response back to Auth0.
## Step 8: Auth0 receives user response after the flow completes
The client application completes the polling upon receiving a response from the `/token` endpoint. A CIBA flow always requires a response, either an approval or decline, from the authorizing user, and existing grants are not checked. This means Auth0 treats every CIBA request as a fresh authorization for the authorizing user.
## Step 9: Auth0 returns access token to client application
If the user rejects the push request, Auth0 returns an error response like the following to the client application:
```json lines theme={null}
{
"error": "access_denied",
"error_description": "The end-user denied the authorization request or it has been expired"
}
```
If the user approves the push request, Auth0 returns an access token with the `authorization_details` like the following to the client application:
```json lines theme={null}
{
"id_token": "...",
"access_token": "...",
"expires_in": "...",
"scope": "{SCOPES}",
"authorization_details": [{
"type": "money_transfer",
"instructedAmount": {
"amount": 2500,
"currency": "USD"
},
"sourceAccount": "xxxxxxxxxxx1234",
"destinationAccount": "xxxxxxxxxxx9876",
"beneficiary": "Hanna Herwitz",
"subject": "A Lannister Always Pays His Debts"
}]
}
```
The `refresh_token` will only be present if the `offline_access` scope was included in the initial `/bc-authorize` request.
## Query authorization\_details
At compile time, you can query the type and objects of `authorization_details` from the consent details in a strongly typed manner as you would dynamically query JSON:
```swift lines theme={null}
let requestedDetails: ConsentRequestedDetails = payload.requestedDetails
let myAuthorizationDetailsTypes = requestedDetails.authorizationDetails[0].objectValue!;
let type = myAuthorizationDetailsTypes["type"]?.stringValue // Your pre-registered type value
let stringProperty = myAuthorizationDetailsTypes["string_property"]?.stringValue
let boolProperty = myAuthorizationDetailsTypes["bool_property"]?.boolValue
let numericProperty = myAuthorizationDetailsTypes["numeric_property"]?.doubleValue
let nestedObjectProperty = myAuthorizationDetailsTypes["nested_property"]?.objectValue
let nestedArrayProperty = myAuthorizationDetailsTypes["nested_array_property"]?.arrayValue
```
```kotlin lines theme={null}
RichConsentRequestedDetails requestedDetails = consentDetails.getRequestedDetails();
Map authorizationDetails = requestedDetails.getAuthorizationDetails().get(0);
String type = (String) myAuthorizationDetailsTypes.get("type");
String stringProperty = (String) myAuthorizationDetailsTypes.get("string_property");
boolean booleanProperty = (boolean) myAuthorizationDetailsTypes.get("boolean_property");
int numericProperty = (int) myAuthorizationDetailsTypes.get("numeric_property");
Object nestedObjectProperty = myAuthorizationDetailsTypes.get("nested_property");
List
If you define a custom type to represent your object, you can use the `filterAuthorizationDetailsByType()` function to return all `authorization_details` objects that match the desired type.
The following code sample queries `authorization_details` with the `payment` type:
```swift lines theme={null}
// Must implement AuthorizationDetailsType
struct Payment : AuthorizationDetailsType {
static let type = "payment";
let amount: Double;
let currency: String;
}
...
let requestedDetails: ConsentRequestedDetails = payload.requestedDetails
let payments = requestedDetails.filterAuthorizationDetailsByType(Payment.self)
let firstPayment = payments.first!
let type: String = firstPayment.type // "payment"
let amount: Double = firstPayment.amount
let currency: String = firstPayment.currency
```
```kotlin lines expandable theme={null}
@AuthorizatioDetailsType("payment")
class Payment {
private String type;
private int amount;
private String currency;
public Payment(String type, int amount, String currency) {
this.type = type;
this.amount = amount;
this.currency = currency;
}
public String getType() {
return type;
}
public int getAmount() {
return amount;
}
public String getCurrency() {
return currency;
}
}
...
RichConsentRequestedDetails requestedDetails = consentDetails.getRequestedDetails();
List payments = requestedDetails.filterAuthorizationDetailsByType(Payment.class);
Payment firstPayment = payments.get(0);
String type = firstPayment.getType();
int amount = firstPayment.getAmount();
String currency = firstPayment.getCurrency();
```
`filterAuthorizationDetailsByType()` only returns objects matching the specified `authorization_details` type. As a result, your mobile application should present all relevant `authorization_details` to the user for consent, regardless of their type, to ensure a complete understanding of the request
You can also query the `authorization_details` when the AI agent or application polls the `/oauth/token`endpoint for a response:
```bash lines theme={null}
curl --request POST \
--url "https://{YOUR_DOMAIN}.auth0.com/oauth/token" \
--header "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode "grant_type=urn:openid:params:grant-type:ciba" \
--data-urlencode "client_id={YOUR_CLIENT_ID}" \
--data-urlencode "client_secret={YOUR_CLIENT_SECRET}" \
--data-urlencode "auth_req_id={AUTH_REQ_ID}"
```
| Parameters | Description |
| - | - |
| `grant_type` | Set to the CIBA grant type: `urn:openid:params:grant-type:ciba` |
| `client_id` | Set to the application’s client ID. |
| `client_secret` | Set to the application’s client secret. |
| `auth_req_id` | Returned from the Auth0 tenant when it acknowledges the CIBA request. References the CIBA request. |
When the authorizing user approves the request, Auth0 receives the user response, and the CIBA flow completes, returning an access token and `authorization_details` array:
```json lines theme={null}
{
"access_token": "ey...ZQ",
"expires_in": 86400,
"authorization_details": [{
"type": "money_transfer",
"instructedAmount": {
"amount": 2500,
"currency": "USD"
},
"sourceAccount": "xxxxxxxxxxx1234",
"destinationAccount": "xxxxxxxxxxx9876",
"beneficiary": "Hanna Herwitz",
"subject": "A Lannister Always Pays His Debts"
}],
"token_type": "Bearer"
}
```
## Limitations
Auth0 doesn’t support:
* Modifying RAR in Actions for CIBA flows.
* Advertising RAR types for clients to discover, which means you need to pre-register clients with the `authorization_details` types they can send.
* Validating RAR objects beyond checking that they have a `type` property that matches allowed types for the API. Your resource server is responsible for the granular validation of the content within `authorization_details`. For more information, see [Configure RAR](/docs/get-started/apis/configure-rich-authorization-requests).
## Learn more
* [Configure Rich Authorization Requests (RAR)](/docs/get-started/apis/configure-rich-authorization-requests)
* [Authorization Code Flow with Rich Authorization Requests (RAR)](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow/authorization-code-flow-with-rar)
* [Configure Client-Initiated Backchannel Authentication](/docs/get-started/applications/configure-client-initiated-backchannel-authentication)
# Device Authorization Flow
Source: https://auth0.com/docs/get-started/authentication-and-authorization-flow/device-authorization-flow
Learn how the Device Authorization flow works and why you should use it for input-constrained devices, such as smart TVs and media consoles. For use with native apps.
With input-constrained devices that connect to the internet, rather than authenticate the user directly, the device asks the user to go to a link on their computer or smartphone and authorize the device. This avoids a poor user experience for devices that do not have an easy way to enter text. To do this, device apps use the Device Authorization Flow (ratified in [OAuth 2.0](https://tools.ietf.org/html/rfc8628)), in which they pass along their Client ID to initiate the authorization process and get a token.
## How it works
The Device Authorization Flow contains two different paths; one occurs on the device requesting authorization and the other occurs in a browser. The browser flow path, wherein a device code is bound to the session in the browser, occurs in parallel to part of the device flow path.
### Device Flow
1. The user starts the app on the device.
2. The device app requests authorization from the Auth0 Authorization Server using its Client ID (`/oauth/device/code` endpoint).
3. The Auth0 Authorization Server responds with a `device_code`, `user_code`, `verification_uri`, `verification_uri_complete` `expires_in` (lifetime in seconds for `device_code` and `user_code`), and polling `interval`.
4. The device app asks the user to activate using their computer or smartphone. The app may accomplish this by:
* asking the user to visit the `verification_uri` and enter the `user_code` after displaying these values on-screen
* asking the user to interact with either a QR Code or shortened URL with embedded user code generated from the `verification_uri_complete`
* directly navigating to the verification page with embedded user code using `verification_uri_complete`, if running natively on a browser-based device
5. The device app begins polling your Auth0 Authorization Server for an Access Token (**/oauth/token** endpoint) using the time period specified by `interval` and counting from receipt of the last polling request's response. The device app continues polling until either the user completes the browser flow path or the user code expires.
6. When the user successfully completes the browser flow path, your Auth0 Authorization Server responds with an Access Token (and optionally, a Refresh Token). The device app should now forget its `device_code` because it will expire.
7. Your device app can use the Access Token to call an API to access information about the user.
8. The API responds with requested data.
### Browser Flow
1. The user visits the `verification_uri` on their computer, enters the `user_code` and confirms that the device that is being activated is displaying the `user_code`. If the user visits the `verification_uri_complete` by any other mechanism (such as by scanning a QR code), only the device confirmation will be needed.
2. Your Auth0 Authorization Server redirects the user to the login and consent prompt, if needed.
3. The user authenticates using one of the configured login options and may see a consent page asking to authorize the device app.
4. Your device app is authorized to access the API.
## How to implement it
The easiest way to implement the Device Authorization Flow is to follow our tutorial: [Call API Using Device Authorization Flow](/docs/get-started/authentication-and-authorization-flow/device-authorization-flow/call-your-api-using-the-device-authorization-flow).
## Force device reauthorization
To force the user to reauthorize a device, you must revoke the Refresh Token assigned to the device. To learn how, read [Unlink Devices from Users](/docs/manage-users/user-accounts/unlink-devices-from-users). Note that the device will not be forced to reauthorize until the current Access Token expires and the application tries to use the revoked Refresh Token. To learn more about Refresh Tokens, read [Refresh Tokens](/docs/secure/tokens/refresh-tokens).
## Learn more
* [Tokens](/docs/secure/tokens)
* [Token Best Practices](/docs/secure/tokens/token-best-practices)
* [Which OAuth 2.0 Flow Should I Use?](/docs/get-started/authentication-and-authorization-flow/which-oauth-2-0-flow-should-i-use)
* [Auth0 Actions](/docs/customize/actions)
# Call Your API Using the Device Authorization Flow
Source: https://auth0.com/docs/get-started/authentication-and-authorization-flow/device-authorization-flow/call-your-api-using-the-device-authorization-flow
Learn how to call your API from an input-constrained device using the Device Authorization flow.
This tutorial will help you call your own API from an input-constrained device using the Device Authorization Flow. If you want to learn how the flow works and why you should use it, see [Device Authorization Flow](/docs/get-started/authentication-and-authorization-flow/device-authorization-flow).
Auth0 makes it easy for your app to implement the Device Authorization flow using:
* [Authentication API](https://auth0.com/docs/api/authentication): Keep reading to learn how to call our API directly. For an interactive experience, read [Device Flow Playground](https://auth0.github.io/device-flow-playground/).
## Prerequisites
Before beginning this tutorial:
* Check limitations (below) to be sure the Device Authorization flow is suitable for your implementation.
* [Register the Application with Auth0](/docs/get-started/auth0-overview/create-applications/native-apps).
* Select an **Application Type** of **Native**.
* If necessary, set **Allowed Web Origins**. You can use this to allow localhost as an origin for local development, or to set an allowed origin for specific TV software with architecture subject to CORS (e.g., HTML5 + JS). Most applications will not use this setting.
* Ensure that the **OIDC Conformant** toggle is enabled. This setting is in the [Dashboard](https://manage.auth0.com/#) under **Applications > Application > Advanced Settings > OAuth**.
* Make sure the Application's **Grant Types** include **Device Code**. To learn how, read [Update Grant Types](/docs/get-started/applications/update-grant-types).
* If you want your Application to be able to use Refresh Tokens, make sure the Application's **Grant Types** include **Refresh Token**. To learn how, read [Update Grant Types](/docs/get-started/applications/update-grant-types). To learn more about Refresh Tokens, read [Refresh Tokens](/docs/secure/tokens/refresh-tokens).
* Set up and enable at least one connection for the Application: [Database connections](/docs/get-started/applications/set-up-database-connections), [Social connections](/docs/authenticate/identity-providers/social-identity-providers)
* [Register your API with Auth0](/docs/get-started/architecture-scenarios/mobile-api/part-2#create-the-api)
* If you want your API to receive Refresh Tokens to allow it to obtain new tokens when the previous ones expire, enable **Allow Offline Access**. To learn more about Refresh Tokens, read [Refresh Tokens](/docs/secure/tokens/refresh-tokens).
* [Configure Device User Code Settings](/docs/get-started/tenant-settings/configure-device-user-code-settings) to define the character set, format, and length of your randomly-generated user code.
## Steps
1. [Request device code](#request-device-code) (Device Flow): Request a device code that the user can use to authorize the device.
2. [Request device activation](#request-device-activation) (Device Flow): Request that the user authorize the device using their laptop or smartphone.
3. [Request tokens](#request-tokens) (Device Flow): Poll the token endpoint to request a token.
4. [Authorize user](#authorize-user) (Browser Flow): The user authorizes the device, so the device can receive tokens.
5. [Receive tokens](#receive-tokens) (Device Flow): After the user successfully authorizes the device, receive tokens.
6. [Call API](#call-your-api) (Device Flow): Use the retrieved Access Token to call your API.
7. [Refresh tokens](#refresh-tokens) (Device Flow): Use a Refresh Token to request new tokens when the existing ones expire.
Optional: [Explore sample use cases](#sample-use-cases).
Optional: [Troubleshoot](#troubleshoot).
### Request device code
Once the user has started their device app and wants to authorize the device, you'll need to get a device code. When the user begins their session in their browser-based device, this code will be bound to that session.
To get the device code, your app must request a code from the [device code URL](https://auth0.com/docs/api/authentication#get-device-code), including the Client ID.
#### Example POST to device code URL
```bash cURL theme={null}
curl --request POST \
--url 'https://{yourDomain}/oauth/device/code' \
--header 'content-type: application/x-www-form-urlencoded' \
--data 'client_id={yourClientId}' \
--data 'scope={scope}' \
--data 'audience={audience}'
```
```csharp C# theme={null}
var client = new RestClient("https://{yourDomain}/oauth/device/code");
var request = new RestRequest(Method.POST);
request.AddHeader("content-type", "application/x-www-form-urlencoded");
request.AddParameter("application/x-www-form-urlencoded", "client_id={yourClientId}&scope=%7Bscope%7D&audience=%7Baudience%7D", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```
```go Go theme={null}
package main
import (
"fmt"
"strings"
"net/http"
"io/ioutil"
)
func main() {
url := "https://{yourDomain}/oauth/device/code"
payload := strings.NewReader("client_id={yourClientId}&scope=%7Bscope%7D&audience=%7Baudience%7D")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("content-type", "application/x-www-form-urlencoded")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := ioutil.ReadAll(res.Body)
fmt.Println(res)
fmt.Println(string(body))
}
```
```java Java theme={null}
HttpResponse response = Unirest.post("https://{yourDomain}/oauth/device/code")
.header("content-type", "application/x-www-form-urlencoded")
.body("client_id={yourClientId}&scope=%7Bscope%7D&audience=%7Baudience%7D")
.asString();
```
```javascript Node.JS theme={null}
var axios = require("axios").default;
var options = {
method: 'POST',
url: 'https://{yourDomain}/oauth/device/code',
headers: {'content-type': 'application/x-www-form-urlencoded'},
data: {client_id: '{yourClientId}', scope: '{scope}', audience: '{audience}'}
};
axios.request(options).then(function (response) {
console.log(response.data);
}).catch(function (error) {
console.error(error);
});
```
```php PHP theme={null}
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://{yourDomain}/oauth/device/code",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "client_id={yourClientId}&scope=%7Bscope%7D&audience=%7Baudience%7D",
CURLOPT_HTTPHEADER => [
"content-type: application/x-www-form-urlencoded"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
```
```python Python theme={null}
import http.client
conn = http.client.HTTPSConnection("")
payload = "client_id={yourClientId}&scope=%7Bscope%7D&audience=%7Baudience%7D"
headers = { 'content-type': "application/x-www-form-urlencoded" }
conn.request("POST", "/{yourDomain}/oauth/device/code", payload, headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
```
```ruby Ruby theme={null}
require 'uri'
require 'net/http'
require 'openssl'
url = URI("https://{yourDomain}/oauth/device/code")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
request = Net::HTTP::Post.new(url)
request["content-type"] = 'application/x-www-form-urlencoded'
request.body = "client_id={yourClientId}&scope=%7Bscope%7D&audience=%7Baudience%7D"
response = http.request(request)
puts response.read_body
```
##### Device code parameters
Note that when requesting a device code to call a custom API, you:
* must include an audience parameter
* can include additional scopes supported by the target API
If your app wants an Access Token only to retrieve info about the authenticated user, then no audience parameter is required.
| Parameter Name | Description |
| - | - |
| `client_id` | Your application's Client ID. You can find this value in your [Application Settings](https://manage.auth0.com/#/Applications/\{yourClientId}/settings). |
| `scope` | The [scopes](/docs/get-started/apis/scopes) for which you want to request authorization. These must be separated by a space. You can request any of the [standard OIDC scopes](https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims) about users, such as `profile` and `email`, [custom claims](/docs/secure/tokens/json-web-tokens/json-web-token-claims#custom-claims) conforming to a [namespaced format](/docs/secure/tokens/json-web-tokens/create-custom-claims), or any [scopes supported by the target API](/docs/get-started/apis/scopes/api-scopes) (e.g., `read:contacts`). Include `openid` to get an ID Token or to be able to use the [/userinfo endpoint](https://auth0.com/docs/api/authentication#user-profile) to retrieve profile information for the user. Include `offline_access` to get a Refresh Token (make sure that the **Allow Offline Access** field is enabled in the [API Settings](https://manage.auth0.com/#/apis)). Note that this must be URL encoded. |
| `audience` | The unique identifier of the API your app wants to access. Use the **Identifier** value on the [Settings](https://manage.auth0.com/#/apis) tab for the API you created as part of the prerequisites for this tutorial. Note that this must be URL encoded. |
#### Device code response
If all goes well, you'll receive an `HTTP 200` response with a payload containing `device_code`, `user_code`, `verification_uri`, and `expires_in`, `interval`, and `verification_uri_complete` values:
```json lines theme={null}
{
"device_code": "Ag_EE...ko1p",
"user_code": "QTZL-MCBW",
"verification_uri": "https://accounts.acmetest.org/activate",
"verification_uri_complete": "https://accounts.acmetest.org/activate?user_code=QTZL-MCBW",
"expires_in": 900,
"interval": 5
}
```
* `device_code` is the unique code for the device. When the user goes to the `verification_uri` in their browser-based device, this code will be bound to their session.
* `user_code` contains the code that should be input at the `verification_uri` to authorize the device.
* `verification_uri` contains the URL the user should visit to authorize the device.
* `verification_uri_complete` contains the complete URL the user should visit to authorize the device. This allows your app to embed the `user_code` in the URL, if you so choose.
* `expires_in` indicates the lifetime (in seconds) of the `device_code` and `user_code`.
* `interval` indicates the interval (in seconds) at which the app should poll the token URL to request a token.
You can [configure the character set, format, and length of your randomly-generated user code](/docs/get-started/tenant-settings/configure-device-user-code-settings) in your tenant settings.
To prevent brute force attacks, we enforce the following limits on `user_code`:
**Minimum length**:
* BASE20 Letters: 8 characters
* Numbers: 9 characters
**Maximum length**:
* 20 characters (including hyphens and spaces, which may be added as separators for readability)
**Expiration time**:
* 15 minutes
### Request device activation
Once you have received a `device_code` and `user_code`, you must ask the user to go to the `verification_uri` on their laptop or smartphone and enter the `user_code`:
The `device_code` is not intended for the user directly and should not be displayed during the interaction to avoid confusing the user.
When building a CLI, you could skip this step and immediately open the browser with `verification_uri_complete`.
### Request tokens
While you are waiting for the user to activate the device, begin polling the token URL to request an Access Token. Using the extracted polling interval (`interval`) from the previous step, you will need to `POST` to the [token URL](https://auth0.com/docs/api/authentication#device-auth) sending along the `device_code`.
To avoid errors due to network latency, you should start counting each interval after receipt of the last polling request's response.
#### Example request token POST to token URL
```bash cURL theme={null}
curl --request POST \
--url 'https://{yourDomain}/oauth/token' \
--header 'content-type: application/x-www-form-urlencoded' \
--data grant_type=urn:ietf:params:oauth:grant-type:device_code \
--data 'device_code={yourDeviceCode}' \
--data 'client_id={yourClientId}'
```
```csharp C# theme={null}
var client = new RestClient("https://{yourDomain}/oauth/token");
var request = new RestRequest(Method.POST);
request.AddHeader("content-type", "application/x-www-form-urlencoded");
request.AddParameter("application/x-www-form-urlencoded", "grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Adevice_code&device_code=%7ByourDeviceCode%7D&client_id={yourClientId}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```
```go Go theme={null}
package main
import (
"fmt"
"strings"
"net/http"
"io/ioutil"
)
func main() {
url := "https://{yourDomain}/oauth/token"
payload := strings.NewReader("grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Adevice_code&device_code=%7ByourDeviceCode%7D&client_id={yourClientId}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("content-type", "application/x-www-form-urlencoded")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := ioutil.ReadAll(res.Body)
fmt.Println(res)
fmt.Println(string(body))
}
```
```java Java theme={null}
HttpResponse response = Unirest.post("https://{yourDomain}/oauth/token")
.header("content-type", "application/x-www-form-urlencoded")
.body("grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Adevice_code&device_code=%7ByourDeviceCode%7D&client_id={yourClientId}")
.asString();
```
```javascript Node.JS theme={null}
var axios = require("axios").default;
var options = {
method: 'POST',
url: 'https://{yourDomain}/oauth/token',
headers: {'content-type': 'application/x-www-form-urlencoded'},
data: new URLSearchParams({
grant_type: 'urn:ietf:params:oauth:grant-type:device_code',
device_code: '{yourDeviceCode}',
client_id: '{yourClientId}'
})
};
axios.request(options).then(function (response) {
console.log(response.data);
}).catch(function (error) {
console.error(error);
});
```
```php PHP theme={null}
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://{yourDomain}/oauth/token",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Adevice_code&device_code=%7ByourDeviceCode%7D&client_id={yourClientId}",
CURLOPT_HTTPHEADER => [
"content-type: application/x-www-form-urlencoded"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
```
```python Python theme={null}
import http.client
conn = http.client.HTTPSConnection("")
payload = "grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Adevice_code&device_code=%7ByourDeviceCode%7D&client_id={yourClientId}"
headers = { 'content-type': "application/x-www-form-urlencoded" }
conn.request("POST", "/{yourDomain}/oauth/token", payload, headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
```
```ruby Ruby theme={null}
require 'uri'
require 'net/http'
require 'openssl'
url = URI("https://{yourDomain}/oauth/token")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
request = Net::HTTP::Post.new(url)
request["content-type"] = 'application/x-www-form-urlencoded'
request.body = "grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Adevice_code&device_code=%7ByourDeviceCode%7D&client_id={yourClientId}"
response = http.request(request)
puts response.read_body
```
##### Token request parameters
| Parameter Name | Description |
| - | - |
| `grant_type` | Set this to "urn:ietf:params:oauth:grant-type:device\_code". This is an extension grant type (as defined by Section 4.5 of [RFC6749](https://tools.ietf.org/html/rfc6749#section-4.5)). Note that this must be URL encoded. |
| `device_code` | The `device_code` retrieved in the previous step of this tutorial. |
| `client_id` | Your application's Client ID. You can find this value in your [Application Settings](https://manage.auth0.com/#/Applications/\{yourClientId}/settings). |
#### Token responses
While you wait for the user to authorize the device, you may receive a few different `HTTP 4xx` responses:
##### Authorization pending
You will see this error while waiting for the user to take action. Continue polling using the suggested interval retrieved in the previous step of this tutorial.
```json lines theme={null}
HTTP/1.1 403 Forbidden
{
"error": "authorization_pending",
"error_description": "..."
}
```
##### Slow down
You are polling too fast. Slow down and use the suggested interval retrieved in the previous step of this tutorial. To avoid receiving this error due to network latency, you should start counting each interval after receipt of the last polling request's response.
```json lines theme={null}
HTTP/1.1 429 Too Many Requests
{
"error": "slow_down",
"error_description": "..."
}
```
##### Expired token
The user has not authorized the device quickly enough, so the `device_code` has expired. Your application should notify the user that the flow has expired and prompt them to reinitiate the flow.
The `expired_token` error will be returned exactly once; after that, `invalid_grant` is returned. Your device **must** stop polling.
```json lines theme={null}
HTTP/1.1 403 Bad Request
{
"error": "expired_token",
"error_description": "..."
}
```
##### Access denied
Finally, if access is denied, you will receive:
```json lines theme={null}
HTTP/1.1 403 Forbidden
{
"error": "access_denied",
"error_description": "..."
}
```
This can occur for a variety of reasons, including:
* the user refused to authorize the device
* the authorization server denied the transaction
* a configured rule denied access (To learn more, read [Auth0 Rules](/docs/customize/rules).)
### Authorize user
The user will either scan the QR code, or else will open the activation page and enter the user code:
A confirmation page will be shown to have the user confirm that this is the right device:
The user will complete the transaction by signing in. This step may include one or more of the following processes:
* Authenticating the user;
* Redirecting the user to an Identity Provider to handle authentication;
* Checking for active SSO sessions;
* Obtaining user consent for the device, unless consent has been previously given.
Upon successful authentication and consent, the confirmation prompt will be shown:
At this point, the user has authenticated, and the device has been authorized.
### Receive tokens
While the user has been authenticating and authorizing the device, the device app has continued to poll the token URL to request an Access Token.
Once the user has successfully authorized the device, you'll receive an `HTTP 200` response with a payload containing `access_token`, `refresh_token` (optionally), `id_token` (optionally), `token_type`, and `expires_in` values:
```json lines theme={null}
{
"access_token":"eyJz93a...k4laUWw",
"refresh_token":"GEbRxBN...edjnXbL",
"id_token": "eyJ0XAi...4faeEoQ",
"token_type":"Bearer",
"expires_in":86400
}
```
Validate your tokens before saving them. To learn how, read [Validate ID Tokens](/docs/secure/tokens/id-tokens/validate-id-tokens) and [Validate Access Tokens](/docs/secure/tokens/access-tokens/validate-access-tokens).
Access Tokens are used to call the Auth0 Authentication API's [`/userinfo` endpoint](https://auth0.com/docs/api/authentication#get-user-info) or another API. (To learn more about Access Tokens, read [Access Tokens](/docs/secure/tokens/access-tokens).) You will be able to use the Access Token to call `/userinfo` only if you included the `openid` scope. If you are calling your own API, the first thing your API will need to do is [verify the Access Token](/docs/secure/tokens/access-tokens/validate-access-tokens).
ID Tokens contain user information that must be decoded and extracted. (To learn more about ID Tokens, read [ID Tokens](/docs/secure/tokens/id-tokens).) The `id_token` will only be present in the response if you included the `openid` scope.
Refresh Tokens are used to obtain a new Access Token or ID Token after the previous one has expired. (To learn more about Refresh Tokens, read [Refresh Tokens](/docs/secure/tokens/refresh-tokens).) The `refresh_token` will only be present in the response if you included the `offline_access` scope and enabled **Allow Offline Access** for your API in the Dashboard.
Refresh tokens must be stored securely since they allow a user to remain authenticated essentially forever.
### Call your API
To call your API, the application must pass the retrieved Access Token as a Bearer token in the Authorization header of your HTTP request.
```bash cURL lines theme={null}
curl --request GET \
--url https://myapi.com/api \
--header 'authorization: Bearer ACCESS_TOKEN' \
--header 'content-type: application/json'
```
```csharp C# lines theme={null}
var client = new RestClient("https://myapi.com/api");
var request = new RestRequest(Method.GET);
request.AddHeader("content-type", "application/json");
request.AddHeader("authorization", "Bearer ACCESS_TOKEN");
IRestResponse response = client.Execute(request);
```
```go Go lines expandable theme={null}
package main
import (
"fmt"
"net/http"
"io/ioutil"
)
func main() {
url := "https://myapi.com/api"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("content-type", "application/json")
req.Header.Add("authorization", "Bearer ACCESS_TOKEN")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := ioutil.ReadAll(res.Body)
fmt.Println(res)
fmt.Println(string(body))
}
```
```java Java lines theme={null}
HttpResponse response = Unirest.get("https://myapi.com/api")
.header("content-type", "application/json")
.header("authorization", "Bearer ACCESS_TOKEN")
.asString();
```
```javascript Node.JS lines theme={null}
var axios = require("axios").default;
var options = {
method: 'GET',
url: 'https://myapi.com/api',
headers: {'content-type': 'application/json', authorization: 'Bearer ACCESS_TOKEN'}
};
axios.request(options).then(function (response) {
console.log(response.data);
}).catch(function (error) {
console.error(error);
});
```
```php PHP lines expandable theme={null}
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://myapi.com/api",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"authorization: Bearer ACCESS_TOKEN",
"content-type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
```
```python Python lines theme={null}
import http.client
conn = http.client.HTTPSConnection("myapi.com")
headers = {
'content-type': "application/json",
'authorization': "Bearer ACCESS_TOKEN"
}
conn.request("GET", "/api", headers=headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
```
```ruby Ruby lines theme={null}
require 'uri'
require 'net/http'
require 'openssl'
url = URI("https://myapi.com/api")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
request = Net::HTTP::Get.new(url)
request["content-type"] = 'application/json'
request["authorization"] = 'Bearer ACCESS_TOKEN'
response = http.request(request)
puts response.read_body
```
### Refresh tokens
You have already received a Refresh Token if you've been following this tutorial and completed the following:
* configured your API to allow offline access
* included the `offline_access` scope when you initiated the authentication request through the [authorize endpoint](https://auth0.com/docs/api/authentication/reference#authorize-application)
You can use the Refresh Token to get a new Access Token. Usually, a user will need a new Access Token only after the previous one expires or when gaining access to a new resource for the first time. It's bad practice to call the endpoint to get a new Access Token every time you call an API, and Auth0 maintains rate limits that will throttle the amount of requests to the endpoint that can be executed using the same token from the same IP.
To refresh your token, make a `POST` request to the `/oauth/token` endpoint in the Authentication API, using `grant_type=refresh_token`.
#### Example refresh token POST to token URL
```bash cURL theme={null}
curl --request POST \
--url 'https://{yourDomain}/oauth/token' \
--header 'content-type: application/x-www-form-urlencoded' \
--data grant_type=refresh_token \
--data 'client_id={yourClientId}' \
--data 'client_secret={yourClientSecret}' \
--data 'refresh_token={yourRefreshToken}'
```
```csharp C# theme={null}
var client = new RestClient("https://{yourDomain}/oauth/token");
var request = new RestRequest(Method.POST);
request.AddHeader("content-type", "application/x-www-form-urlencoded");
request.AddParameter("application/x-www-form-urlencoded", "grant_type=refresh_token&client_id={yourClientId}&client_secret={yourClientSecret}&refresh_token=%7ByourRefreshToken%7D", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```
```go Go theme={null}
package main
import (
"fmt"
"strings"
"net/http"
"io/ioutil"
)
func main() {
url := "https://{yourDomain}/oauth/token"
payload := strings.NewReader("grant_type=refresh_token&client_id={yourClientId}&client_secret={yourClientSecret}&refresh_token=%7ByourRefreshToken%7D")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("content-type", "application/x-www-form-urlencoded")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := ioutil.ReadAll(res.Body)
fmt.Println(res)
fmt.Println(string(body))
}
```
```java Java theme={null}
HttpResponse response = Unirest.post("https://{yourDomain}/oauth/token")
.header("content-type", "application/x-www-form-urlencoded")
.body("grant_type=refresh_token&client_id={yourClientId}&client_secret={yourClientSecret}&refresh_token=%7ByourRefreshToken%7D")
.asString();
```
```javascript Node.JS theme={null}
var axios = require("axios").default;
var options = {
method: 'POST',
url: 'https://{yourDomain}/oauth/token',
headers: {'content-type': 'application/x-www-form-urlencoded'},
data: new URLSearchParams({
grant_type: 'refresh_token',
client_id: '{yourClientId}',
client_secret: '{yourClientSecret}',
refresh_token: '{yourRefreshToken}'
})
};
axios.request(options).then(function (response) {
console.log(response.data);
}).catch(function (error) {
console.error(error);
});
```
```php PHP theme={null}
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://{yourDomain}/oauth/token",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "grant_type=refresh_token&client_id={yourClientId}&client_secret={yourClientSecret}&refresh_token=%7ByourRefreshToken%7D",
CURLOPT_HTTPHEADER => [
"content-type: application/x-www-form-urlencoded"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
```
```python Python theme={null}
import http.client
conn = http.client.HTTPSConnection("")
payload = "grant_type=refresh_token&client_id={yourClientId}&client_secret={yourClientSecret}&refresh_token=%7ByourRefreshToken%7D"
headers = { 'content-type': "application/x-www-form-urlencoded" }
conn.request("POST", "/{yourDomain}/oauth/token", payload, headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
```
```ruby Ruby theme={null}
require 'uri'
require 'net/http'
require 'openssl'
url = URI("https://{yourDomain}/oauth/token")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
request = Net::HTTP::Post.new(url)
request["content-type"] = 'application/x-www-form-urlencoded'
request.body = "grant_type=refresh_token&client_id={yourClientId}&client_secret={yourClientSecret}&refresh_token=%7ByourRefreshToken%7D"
response = http.request(request)
puts response.read_body
```
##### Refresh token request parameters
| Parameter Name | Description |
| - | - |
| `grant_type` | Set this to "refresh\_token". |
| `client_id` | Your application's Client ID. You can find this value in your [Application Settings](https://manage.auth0.com/#/Applications/\{yourClientId}/settings). |
| `client_secret` | Your application's Client Secret. You can find this value in your [Application Settings](https://manage.auth0.com/#/Applications/\{yourClientSecret}/settings). |
| `refresh_token` | The Refresh Token to use. |
| `scope` | (Optional) A space-delimited list of requested scope permissions. If not sent, the original scopes will be used; otherwise you can request a reduced set of scopes. Note that this must be URL encoded. |
#### Refresh token response
If all goes well, you'll receive an `HTTP 200` response with a payload containing a new `access_token`, `id_token` (optionally), token lifetime in seconds (`expires_in`), granted `scope` values, and `token_type`:
```json lines theme={null}
{
"access_token": "eyJ...MoQ",
"expires_in": 86400,
"scope": "openid offline_access",
"id_token": "eyJ...0NE",
"token_type": "Bearer"
}
```
Validate your tokens before saving them. To learn how, read [Validate ID Tokens](/docs/secure/tokens/id-tokens/validate-id-tokens) and [Validate Access Tokens](/docs/secure/tokens/access-tokens/validate-access-tokens).
## Sample use cases
### Detect device authorization flow use
You can use Rules to detect whether the current transaction is using the Device Authorization Flow. (To learn more about rules, read [Auth0 Rules](/docs/customize/rules).) To do so, check the `context` object's `protocol` property:
```javascript lines theme={null}
function (user, context, callback) {
if (context.protocol === 'oauth2-device-code') {
...
}
callback(null, user, context);
}
```
### Sample implementations
* [Device Authorization Playground](https://auth0.github.io/device-flow-playground/)
* [AppleTV (Swift)](https://github.com/pushpabrol/auth0-device-flow-appletv): Simple application that shows how Auth0 can be used with the Device Authorization Flow from an AppleTV.
* [CLI (Node.js)](https://gist.github.com/panva/ebaacfe433a8677bdbf458f6e1132045): Sample implementation of a CLI that uses the Device Authorization Flow instead of the Authorization Code Flow. The major difference is that your CLI does not need to host a web server and listen on a port.
## Troubleshoot
Tenant logs are created for any interaction that takes place and can be used to troubleshoot issues. To learn more, read [Logs](/docs/deploy-monitor/logs).
### Error codes
| Code | Name | Description |
| - | - | - |
| `fdeaz` | Failed device authorization request | |
| `fdeac` | Failed device activation | |
| `fdecc` | User canceled the device confirmation | |
| `fede` | Failed Exchange | Device Code for Access Token |
| `sede` | Success Exchange | Device Code for Access Token |
### Limitations
To use the Device Authorization Flow, devices must:
* Support Server Name Indication (SNI) when [Custom Domains](/docs/customize/custom-domains) are used
* Have an [Auth0 application type](/docs/get-started/applications) of **Native**
* Have the [Token Endpoint Authentication Method](/docs/get-started/applications/application-settings) set to **None**
* Be [OIDC-conformant](/docs/get-started/applications/application-settings)
* Not be created through [Dynamic Client Registration](/docs/get-started/applications/dynamic-client-registration)
In addition, the Device Authorization Flow does not allow:
* [Social Connections](/docs/authenticate/identity-providers/social-identity-providers) using [Auth0 developer keys](/docs/authenticate/identity-providers/social-identity-providers/devkeys) unless you are using the [Universal Login experience](/docs/authenticate/login/auth0-universal-login/universal-login-vs-classic-login/universal-experience)
* Query string parameters to be accessed from hosted login page or Rules or Actions
* [User account linking](/docs/manage-users/user-accounts/user-account-linking)
We support the full Draft 15, except for confidential Clients. To learn more, read [OAuth 2.0 Device Authorization Grant Draft 15 on ietf.org](https://tools.ietf.org/html/draft-ietf-oauth-device-flow-15).
## Learn more
* [OAuth 2.0 Authorization Framework](/docs/authenticate/protocols/oauth)
* [OpenID Connect Protocol](/docs/authenticate/protocols/openid-connect-protocol)
* [Tokens](/docs/secure/tokens)
* [Logs](/docs/deploy-monitor/logs)
# Hybrid Flow
Source: https://auth0.com/docs/get-started/authentication-and-authorization-flow/hybrid-flow
Learn how the Hybrid Flow works to provide optimum access to the ID Token while still leveraging the Authorization Code Flow for the secure and safe retrieval of Access and Refresh Tokens.
Applications that are able to securely store [Client Credentials](/docs/secure/application-credentials) may benefit from the use of the Hybrid Flow (defined in the [OpenID Connect specification, section 3.3](https://openid.net/specs/openid-connect-core-1_0.html#HybridFlowAuth)). The Hybrid flow allows your application to have immediate access to an ID token while ensuring secure and safe retrieval of access tokens and refresh tokens. This can be useful in situations where your application needs to immediately access information about the user, but must perform some processing before gaining access to protected resources for an extended period of time.
## How it works
The Hybrid Flow combines steps from the [Implicit Flow with Form Post](/docs/get-started/authentication-and-authorization-flow/implicit-flow-with-form-post) and [Authorization Code Flow](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow):
1. User selects **Login** within application.
2. Application redirects user to Auth0 Authorization Server ([`/authorize` endpoint](https://auth0.com/docs/api/authentication#authorization-code-flow)), passing along `response_type` parameter indicating type of requested credential (ID token and authorization code), and `response_mode` parameter of `form_post` to ensure security.
3. Auth0 Authorization Server redirects user to login and authorization prompt.
4. User authenticates using one of the configured login options, and may see a consent prompt listing the permissions Auth0 will give to the application.
5. Auth0 Authorization Server redirects user back to application with single-use authorization code, and ID token, access token, or both, depending on provided `response_type`.
6. Application sends authorization code, application's client ID, and application's credentials, such as Client Secret or Private Key JWT, to Auth0 Authorization Server ([`/oauth/token` endpoint](https://auth0.com/docs/api/authentication?http#authorization-code-flow43)).
7. Auth0 Authorization Server verifies authorization code, application's client ID, and application's credentials.
8. Auth0 Authorization Server responds with second ID token and access token (and optionally, a refresh token).
9. Application can use second access token to call an API to access information about user.
10. API responds with requested data.
If your application only needs to use Hybrid Flow for sign-on, you will not need a Refresh Token or an Access Token, only an ID Token with claims.
## How to implement it
You can follow our tutorial to use the Authentication API to [Call Your API Using the Hybrid Flow](/docs/get-started/authentication-and-authorization-flow/hybrid-flow/call-api-hybrid-flow).
## Learn more
* [Auth0 Rules](/docs/customize/rules)
* [Auth0 Hooks](/docs/customize/hooks)
* [Tokens](/docs/secure/tokens)
* [Token Best Practices](/docs/secure/tokens/token-best-practices)
* [Which OAuth 2.0 Flow Should I Use?](/docs/get-started/authentication-and-authorization-flow/which-oauth-2-0-flow-should-i-use)
* [Application Credentials](/docs/secure/application-credentials)
# Call Your API Using the Hybrid Flow
Source: https://auth0.com/docs/get-started/authentication-and-authorization-flow/hybrid-flow/call-api-hybrid-flow
Learn how to execute the Hybrid Flow so your app can use an ID token to access information about the user while obtaining an authorization code that can be exchanged for an Access Token.
This tutorial will help you call your own API using the Hybrid Flow. If you want to learn how the flow works and why you should use it, see [Hybrid Flow](/docs/get-started/authentication-and-authorization-flow/hybrid-flow).
Auth0 makes it easy for your app to implement the Authorization Code Flow using:
* [Authentication API](https://auth0.com/docs/api/authentication): If you prefer to build your own solution, keep reading to learn how to call our API directly.
## Prerequisites
**Before beginning this tutorial:**
* [Register your Application with Auth0](/docs/get-started/auth0-overview/create-applications/regular-web-apps).
* Select the appropriate **Application Type**.
* Add an **Allowed Callback URL** of `{https://yourApp/callback}`.
* Make sure your Application's **Grant Types** include **Implicit** and **Authorization Code**. To learn how, read [Update Grant Types](/docs/get-started/applications/update-grant-types).
* If you want your Application to be able to use Refresh Tokens, make sure the Application's **Grant Types** include **Refresh Token**. To learn how, read [Update Grant Types](/docs/get-started/applications/update-grant-types). To learn more about Refresh Tokens, read [Refresh Tokens](/docs/secure/tokens/refresh-tokens).
* [Register your API with Auth0](/docs/get-started/auth0-overview/set-up-apis)
* If you want your API to receive Refresh Tokens to allow it to obtain new tokens when the previous ones expire, enable **Allow Offline Access**.
## Steps
1. [Authorize user](#authorize-user):
Request the user's authorization and redirect back to your app with an authorization code.
2. [Request tokens](#request-tokens):
Exchange your authorization code for tokens.
3. [Call API](#call-api):
Use the retrieved Access Token to call your API.
4. [Refresh tokens](#refresh-tokens):
Use a Refresh Token to request new tokens when the existing ones expire.
Optional: [Explore sample use cases](#sample-use-cases)
### Authorize user
This step may include one or more of the following processes:
* Authenticating the user
* Redirecting the user to an Identity Provider to handle authentication
* Checking for active Single Sign-on (SSO) sessions
* Obtaining user consent for the requested permission level, unless consent has been previously given.
To authorize the user, your app must send the user to the [authorization URL](https://auth0.com/docs/api/authentication#authorization-code-grant).
#### Example authorization URL
##### Parameters
Note that for authorizing a user when calling a custom API, you:
* must include an audience parameter
* can include additional scopes supported by the target API
| Parameter Name | Description |
| - | - |
| `response_type` | Denotes the kind of credential that Auth0 will return (code or token). For this flow, the value must include `code`, but may also include `id_token`, `token`, or `id_token token`. Specifically, `id_token` returns an ID Token, and `token` returns an Access Token. |
| `response_mode` | Specifies the method with which response parameters should be returned. For security purposes, the value should be `form_post`. In this mode, response parameters will be encoded as HTML form values that are transmitted via the HTTP POST method and encoded in the body using the `application/x-www-form-urlencoded` format. |
| `client_id` | Your application's Client ID. You can find this value in your [Application Settings](https://manage.auth0.com/#/Applications/\{yourClientId}/settings). |
| `redirect_uri` | The URL to which Auth0 will redirect the browser after authorization has been granted by the user. The Authorization Code will be available in the `code` URL parameter. You must specify this URL as a valid callback URL in your [Application Settings](https://manage.auth0.com/#/Applications/\{yourClientId}/settings).
**Warning:** Per the [OAuth 2.0 Specification](https://tools.ietf.org/html/rfc6749#section-3.1.2), Auth0 removes everything after the hash and does *not* honor any fragments. |
| `scope` | Specifies the [scopes](/docs/get-started/apis/scopes) for which you want to request authorization, which dictate which claims (or user attributes) you want returned. These must be separated by a space. You can request any of the [standard OpenID Connect (OIDC) scopes](https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims) about users, such as `profile` or `email`, [custom claims](/docs/secure/tokens/json-web-tokens/json-web-token-claims#custom-claims) conforming to a [namespaced format](/docs/secure/tokens/json-web-tokens/create-custom-claims), or any scopes supported by the target API (e.g., `read:contacts`). Include `offline_access` to get a [Refresh Token](/docs/glossary?term=Refresh+Token) (make sure that the **Allow Offline Access** field is enabled in the [Application Settings](https://manage.auth0.com/#/applications)). |
| `audience` | The unique identifier of the API your application wants to access. Use the **Identifier** value on the [Settings](https://manage.auth0.com/#/apis) tab for the API you created as part of the prerequisites for this tutorial. |
| `state` | (recommended) An opaque arbitrary alphanumeric string your app adds to the initial request that Auth0 includes when redirecting back to your application. To see how to use this value to prevent cross-site request forgery (CSRF) attacks, see [Mitigate CSRF Attacks With State Parameters](/docs/secure/attack-protection/state-parameters). |
| `nonce` | A cryptographically random string that your app adds to the initial request and Auth0 includes inside the ID Token, [used to prevent token replay attacks](/docs/get-started/authentication-and-authorization-flow/implicit-flow-with-form-post/mitigate-replay-attacks-when-using-the-implicit-flow). |
| `organization` | (optional) ID of the organization to use when authenticating a user. When not provided, if your application is configured to **Display Organization Prompt**, the user will be able to enter the organization name when authenticating. |
| `invitation` | (optional) Ticket ID of the organization invitation. When [inviting a member to an Organization](/docs/manage-users/organizations/configure-organizations/invite-members), your application should handle invitation acceptance by forwarding the `invitation` and `organization` key-value pairs when the user accepts the invitation. |
As an example, your HTML snippet for your authorization URL when adding login to your app might look like:
#### Response
If all goes well, you'll receive an `HTTP 302` response. The requested credentials are encoded in the body:
```json lines theme={null}
HTTP/1.1 302 Found
Content-Type: application/x-www-form-urlencoded
code=AUTHORIZATION_CODE&
access_token=ey...MhPw
&expires_in=7200
&token_type=Bearer
id_token=eyJ...acA&
state=xyzABC123
```
Note that the returned values depend on what you requested as a `response_type`.
| Response Type | Components |
| - | - |
| `code ` | Authorization code |
| `id_token ` | ID Token |
| `token ` | Access Token (plus `expires_in` and `token_type` values) |
| `id_token token` | ID Token, Access Token (plus `expires_in` and `token_type` values) |
Auth0 will also return any state value you included in your call to the authorization URL.
The Access Token that you receive in this transaction is only the first Access Token that you will receive. We do not recommend that it be used to call APIs.
Validate your tokens before saving them. To learn how, read [Validate ID Tokens](/docs/secure/tokens/id-tokens/validate-id-tokens) and [Validate Access Tokens](/docs/secure/tokens/access-tokens/validate-access-tokens).
When you decode and parse your ID token, you will notice an additional claim, `c_hash`, which contains a hash of the `code`. This claim is mandatory when an ID token is issued at the same time as a `code`, and you should validate it:
1. Using the hash algorithm specified in the `alg` claim in the ID Token header, hash the octets of the ASCII representation of the `code`.
2. Base64url-encode the left-most half of the hash.
3. Check that the result matches the `c_hash` value.
### Request tokens
Now that you have an Authorization Code, you must exchange it for tokens. Using the extracted Authorization Code (`code`) from the previous step, you will need to `POST` to the [token URL](https://auth0.com/docs/api/authentication#authorization-code).
The Access Token you receive in this step is the one you should use to call your API. Make sure you keep it separate from the Access Token you received in the previous step of this tutorial.
#### Example POST to token URL
```bash cURL theme={null}
curl --request POST \
--url 'https://{yourDomain}/oauth/token' \
--header 'content-type: application/x-www-form-urlencoded' \
--data grant_type=authorization_code \
--data 'client_id={yourClientId}' \
--data 'client_secret={yourClientSecret}' \
--data 'code=yourAuthorizationCode}' \
--data 'redirect_uri={https://yourApp/callback}'
```
```csharp C# theme={null}
var client = new RestClient("https://{yourDomain}/oauth/token");
var request = new RestRequest(Method.POST);
request.AddHeader("content-type", "application/x-www-form-urlencoded");
request.AddParameter("application/x-www-form-urlencoded", "grant_type=authorization_code&client_id={yourClientId}&client_secret=%7ByourClientSecret%7D&code=yourAuthorizationCode%7D&redirect_uri={https://yourApp/callback}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```
```go Go theme={null}
package main
import (
"fmt"
"strings"
"net/http"
"io/ioutil"
)
func main() {
url := "https://{yourDomain}/oauth/token"
payload := strings.NewReader("grant_type=authorization_code&client_id={yourClientId}&client_secret=%7ByourClientSecret%7D&code=yourAuthorizationCode%7D&redirect_uri={https://yourApp/callback}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("content-type", "application/x-www-form-urlencoded")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := ioutil.ReadAll(res.Body)
fmt.Println(res)
fmt.Println(string(body))
}
```
```java Java theme={null}
HttpResponse response = Unirest.post("https://{yourDomain}/oauth/token")
.header("content-type", "application/x-www-form-urlencoded")
.body("grant_type=authorization_code&client_id={yourClientId}&client_secret=%7ByourClientSecret%7D&code=yourAuthorizationCode%7D&redirect_uri={https://yourApp/callback}")
.asString();
```
```javascript Node.JS theme={null}
var axios = require("axios").default;
var options = {
method: 'POST',
url: 'https://{yourDomain}/oauth/token',
headers: {'content-type': 'application/x-www-form-urlencoded'},
data: new URLSearchParams({
grant_type: 'authorization_code',
client_id: '{yourClientId}',
client_secret: '{yourClientSecret}',
code: 'yourAuthorizationCode}',
redirect_uri: '{https://yourApp/callback}'
})
};
axios.request(options).then(function (response) {
console.log(response.data);
}).catch(function (error) {
console.error(error);
});
```
```php PHP theme={null}
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://{yourDomain}/oauth/token",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "grant_type=authorization_code&client_id={yourClientId}&client_secret=%7ByourClientSecret%7D&code=yourAuthorizationCode%7D&redirect_uri={https://yourApp/callback}",
CURLOPT_HTTPHEADER => [
"content-type: application/x-www-form-urlencoded"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
```
```python Python theme={null}
import http.client
conn = http.client.HTTPSConnection("")
payload = "grant_type=authorization_code&client_id={yourClientId}&client_secret=%7ByourClientSecret%7D&code=yourAuthorizationCode%7D&redirect_uri={https://yourApp/callback}"
headers = { 'content-type': "application/x-www-form-urlencoded" }
conn.request("POST", "/{yourDomain}/oauth/token", payload, headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
```
```ruby Ruby theme={null}
require 'uri'
require 'net/http'
require 'openssl'
url = URI("https://{yourDomain}/oauth/token")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
request = Net::HTTP::Post.new(url)
request["content-type"] = 'application/x-www-form-urlencoded'
request.body = "grant_type=authorization_code&client_id={yourClientId}&client_secret=%7ByourClientSecret%7D&code=yourAuthorizationCode%7D&redirect_uri={https://yourApp/callback}"
response = http.request(request)
puts response.read_body
```
##### Parameters
| Parameter Name | Description |
| - | - |
| `grant_type` | Set this to `authorization_code`. |
| `code` | The `authorization_code` retrieved in the previous step of this tutorial. |
| `client_id` | Your application's Client ID. You can find this value in your [Application Settings](https://manage.auth0.com/#/Applications/\{yourClientId}/settings). |
| `client_secret` | Your application's Client Secret. You can find this value in your [Application Settings](https://manage.auth0.com/#/Applications/\{yourClientId}/settings). To learn more about available application authentication methods, read [Application Credentials](/docs/secure/application-credentials). |
| `redirect_uri` | The valid callback URL set in your Application settings. This must exactly match the `redirect_uri` passed to the authorization URL in the previous step of this tutorial. Note that this must be URL encoded. |
#### Response
If all goes well, you'll receive an `HTTP 200` response with a payload containing `access_token`, `refresh_token`, `id_token`, and `token_type` values:
```json lines theme={null}
{
"access_token": "eyJz93a...k4laUWw",
"refresh_token": "GEbRxBN...edjnXbL",
"id_token": "eyJ0XAi...4faeEoQ",
"token_type": "Bearer"
}
```
Validate your tokens before saving them. To learn how, read [Validate ID Tokens](/docs/secure/tokens/id-tokens/validate-id-tokens) and [Validate Access Tokens](/docs/secure/tokens/access-tokens/validate-access-tokens).
[ID tokens](/docs/secure/tokens/id-tokens) contain user information that must be decoded and extracted.
[Access tokens](/docs/secure/tokens/access-tokens) are used to call the [Auth0 Authentication API's /userinfo endpoint](https://auth0.com/docs/api/authentication#get-user-info) or another API. If you are calling your own API, the first thing your API will need to do is [verify the Access token](/docs/secure/tokens/access-tokens/validate-access-tokens).
[Refresh tokens](/docs/secure/tokens/refresh-tokens) are used to obtain a new access token or ID token after the previous one has expired. The `refresh_token` will only be present in the response if you included the `offline_access` scope and enabled **Allow Offline Access** for your API in the Dashboard.
Refresh tokens must be stored securely since they allow a user to remain authenticated essentially forever.
### Call API
To call your API from a regular web application (or similar cases in which the application credentials can be safely stored), the application must pass the retrieved Access Token as a Bearer token in the Authorization header of your HTTP request.
```bash cURL lines theme={null}
curl --request GET \
--url https://myapi.com/api \
--header 'authorization: Bearer {accessToken}' \
--header 'content-type: application/json'
```
```csharp C# lines theme={null}
var client = new RestClient("https://myapi.com/api");
var request = new RestRequest(Method.GET);
request.AddHeader("content-type", "application/json");
request.AddHeader("authorization", "Bearer {accessToken}");
IRestResponse response = client.Execute(request);
```
```go Go lines expandable theme={null}
package main
import (
"fmt"
"net/http"
"io/ioutil"
)
func main() {
url := "https://myapi.com/api"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("content-type", "application/json")
req.Header.Add("authorization", "Bearer {accessToken}")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := ioutil.ReadAll(res.Body)
fmt.Println(res)
fmt.Println(string(body))
}
```
```java Java lines theme={null}
HttpResponse response = Unirest.get("https://myapi.com/api")
.header("content-type", "application/json")
.header("authorization", "Bearer {accessToken}")
.asString();
```
```javascript Node.JS lines theme={null}
var axios = require("axios").default;
var options = {
method: 'GET',
url: 'https://myapi.com/api',
headers: {'content-type': 'application/json', authorization: 'Bearer {accessToken}'}
};
axios.request(options).then(function (response) {
console.log(response.data);
}).catch(function (error) {
console.error(error);
});
```
```php PHP lines expandable theme={null}
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://myapi.com/api",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"authorization: Bearer {accessToken}",
"content-type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
```
```python Python lines theme={null}
import http.client
conn = http.client.HTTPSConnection("myapi.com")
headers = {
'content-type': "application/json",
'authorization': "Bearer {accessToken}"
}
conn.request("GET", "/api", headers=headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
```
```ruby Ruby lines theme={null}
require 'uri'
require 'net/http'
require 'openssl'
url = URI("https://myapi.com/api")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
request = Net::HTTP::Get.new(url)
request["content-type"] = 'application/json'
request["authorization"] = 'Bearer {accessToken}'
response = http.request(request)
puts response.read_body
```
### Refresh tokens
You have already received a [refresh token](/docs/secure/tokens/refresh-tokens) if you've been following this tutorial and completed the following:
* configured your API to allow offline access
* included the `offline_access` scope when you initiated the authentication request through the [authorize endpoint](https://auth0.com/docs/api/authentication/reference#authorize-application).
You can use the Refresh Token to get a new access token. Usually, a user will need a new access token only after the previous one expires or when gaining access to a new resource for the first time. It's bad practice to call the endpoint to get a new access token every time you call an API, and Auth0 maintains rate limits that will throttle the amount of requests to the endpoint that can be executed using the same token from the same IP.
To refresh your token, make a `POST` request to the `/oauth/token` endpoint in the Authentication API, using `grant_type=refresh_token`.
#### Example POST to token URL
```bash cURL theme={null}
curl --request POST \
--url 'https://{yourDomain}/oauth/token' \
--header 'content-type: application/x-www-form-urlencoded' \
--data grant_type=refresh_token \
--data 'client_id={yourClientId}' \
--data 'refresh_token={yourRefreshToken}'
```
```csharp C# theme={null}
var client = new RestClient("https://{yourDomain}/oauth/token");
var request = new RestRequest(Method.POST);
request.AddHeader("content-type", "application/x-www-form-urlencoded");
request.AddParameter("application/x-www-form-urlencoded", "grant_type=refresh_token&client_id={yourClientId}&refresh_token=%7ByourRefreshToken%7D", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```
```go Go theme={null}
package main
import (
"fmt"
"strings"
"net/http"
"io/ioutil"
)
func main() {
url := "https://{yourDomain}/oauth/token"
payload := strings.NewReader("grant_type=refresh_token&client_id={yourClientId}&refresh_token=%7ByourRefreshToken%7D")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("content-type", "application/x-www-form-urlencoded")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := ioutil.ReadAll(res.Body)
fmt.Println(res)
fmt.Println(string(body))
}
```
```java Java theme={null}
HttpResponse response = Unirest.post("https://{yourDomain}/oauth/token")
.header("content-type", "application/x-www-form-urlencoded")
.body("grant_type=refresh_token&client_id={yourClientId}&refresh_token=%7ByourRefreshToken%7D")
.asString();
```
```javascript Node.JS theme={null}
var axios = require("axios").default;
var options = {
method: 'POST',
url: 'https://{yourDomain}/oauth/token',
headers: {'content-type': 'application/x-www-form-urlencoded'},
data: new URLSearchParams({
grant_type: 'refresh_token',
client_id: '{yourClientId}',
refresh_token: '{yourRefreshToken}'
})
};
axios.request(options).then(function (response) {
console.log(response.data);
}).catch(function (error) {
console.error(error);
});
```
```php PHP theme={null}
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://{yourDomain}/oauth/token",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "grant_type=refresh_token&client_id={yourClientId}&refresh_token=%7ByourRefreshToken%7D",
CURLOPT_HTTPHEADER => [
"content-type: application/x-www-form-urlencoded"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
```
```python Python theme={null}
import http.client
conn = http.client.HTTPSConnection("")
payload = "grant_type=refresh_token&client_id={yourClientId}&refresh_token=%7ByourRefreshToken%7D"
headers = { 'content-type': "application/x-www-form-urlencoded" }
conn.request("POST", "/{yourDomain}/oauth/token", payload, headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
```
```ruby Ruby theme={null}
require 'uri'
require 'net/http'
require 'openssl'
url = URI("https://{yourDomain}/oauth/token")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
request = Net::HTTP::Post.new(url)
request["content-type"] = 'application/x-www-form-urlencoded'
request.body = "grant_type=refresh_token&client_id={yourClientId}&refresh_token=%7ByourRefreshToken%7D"
response = http.request(request)
puts response.read_body
```
##### Parameters
| Parameter Name | Description |
| - | - |
| `grant_type` | Set this to `refresh_token`. |
| `client_id` | Your application's Client ID. You can find this value in your [Application Settings](https://manage.auth0.com/#/Applications/\{yourClientId}/settings). |
| `refresh_token` | The refresh token to use. |
| `scope` | (optional) A space-delimited list of requested scope permissions. If not sent, the original scopes will be used; otherwise you can request a reduced set of scopes. Note that this must be URL encoded. |
#### Response
If all goes well, you'll receive an `HTTP 200` response with a payload containing a new `access_token`, its lifetime in seconds (`expires_in`), granted `scope` values, and `token_type`. If the scope of the initial token included `openid`, then the response will also include a new `id_token`:
```json lines theme={null}
{
"access_token": "eyJ...MoQ",
"expires_in": 86400,
"scope": "openid offline_access",
"id_token": "eyJ...0NE",
"token_type": "Bearer"
}
```
Validate your tokens before saving them. To learn how, read [Validate ID Tokens](/docs/secure/tokens/id-tokens/validate-id-tokens) and [Validate Access Tokens](/docs/secure/tokens/access-tokens/validate-access-tokens).
### Sample use cases
#### Customize tokens
You can use rules to change the returned scopes of Access Tokens and/or add claims to Access and ID Tokens. (To learn more about rules, read [Auth0 Rules](/docs/customize/rules).) To do so, add the following rule, which will run after the user authenticates:
```js lines theme={null}
exports.onExecutePostLogin = async (event, api) => {
// Add custom claims to Access Token and ID Token
api.accessToken.setCustomClaim('https://foo/bar', 'value');
api.idToken.setCustomClaim('https://fiz/baz', 'some other value');
// Modify the scope of the Access Token
api.accessToken.addScope('foo');
api.accessToken.addScope('bar');
};
```
Scopes will be available in the token after all rules have run.
Auth0 returns profile information in a structured claim format as defined by the [OpenID Connect (OIDC) specification](https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims). This means that custom claims added to ID tokens or access tokens must [conform to guidelines and restrictions](/docs/secure/tokens/json-web-tokens/create-custom-claims) to avoid possible collisions.
## Learn more
* [OAuth 2.0 Authorization Framework](/docs/authenticate/protocols/oauth)
* [OpenID Connect Protocol](/docs/authenticate/protocols/openid-connect-protocol)
* [Tokens](/docs/secure/tokens)
# Implicit Flow with Form Post
Source: https://auth0.com/docs/get-started/authentication-and-authorization-flow/implicit-flow-with-form-post
Learn how the Implicit flow with Form Post works and why you should use it for traditional web apps that need only an ID Token to perform user authentication.
Don't let the term "implicit" mislead you! Although OAuth now discourages the use of the implicit grant for obtaining access tokens in SPAs, the scenario addressed by Implicit Flow with Form Post is completely different and is **unaffected by the security issues** that led to discouraging use with SPAs. Specifically, Implicit Flow with Form Post applies to traditional web apps as opposed to SPAs. You obtain ID tokens as opposed to access tokens, which have a completely different intended use. The flow uses POST as opposed to placing tokens in URL fragments (as with SPAs) which can expose token bits to browser history attacks, redirect headers, and so on.
You can use OpenID Connect (OIDC) with many different flows to achieve web sign-in for a traditional web app. In one common flow, you obtain an ID token using authorization code flow performed by the app backend. This method is effective and robust, however, it requires your web app to obtain and manage a secret. You can avoid that burden if all you want to do is implement sign-in and you don’t need to obtain access tokens for invoking APIs.
Implicit Flow with Form Post flow uses OIDC to implement web sign-in that is very similar to the way SAML and WS-Federation operates. The web app requests and obtains tokens through the front channel, without the need for secrets or extra backend calls. With this method, you don’t need to obtain, maintain, use, and protect a secret in your application.
## How it works
You should use this flow for login-only use cases; if you need to request Access Tokens while logging the user in so you can call an API, use the [Authorization Code Flow with PKCE](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow-with-pkce) or the [Hybrid Flow](/docs/get-started/authentication-and-authorization-flow/hybrid-flow).
1. The user clicks **Login** in the app.
2. Auth0's SDK redirects the user to the Auth0 Authorization Server (`/authorize` endpoint) passing along a `response_type` parameter of `id_token` that indicates the type of requested credential. It also passes along a `response_mode` parameter of `form_post` to ensure security.
3. Your Auth0 Authorization Server redirects the user to the login and authorization prompt.
4. The user authenticates using one of the configured login options and may see a consent page listing the permissions Auth0 will give to the app.
5. Your Auth0 Authorization Server redirects the user back to the app with an ID Token.
## How to implement it
You can [use our Express OpenID Connect SDK](https://www.npmjs.com/package/express-openid-connect) to securely implement the Implicit Flow with Form Post.
The [Auth0 Single-Page App SDK](/docs/libraries/auth0-single-page-app-sdk) and [Single-Page Quickstarts](/docs/quickstart/spa) adhere to the new recommendations and use the [Authorization Code Flow with PKCE](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow-with-pkce).
Finally, you can follow our tutorials to use our API endpoints to [Add Login Using the Implicit Flow with Form Post](/docs/get-started/authentication-and-authorization-flow/implicit-flow-with-form-post/add-login-using-the-implicit-flow-with-form-post).
## Learn more
* [Auth0 Rules](/docs/customize/rules)
* [Auth0 Hooks](/docs/customize/hooks)
* [Tokens](/docs/secure/tokens)
* [Token Best Practices](/docs/secure/tokens/token-best-practices)
* [Which OAuth 2.0 Flow Should I Use?](/docs/get-started/authentication-and-authorization-flow/which-oauth-2-0-flow-should-i-use)
* [Mitigate Replay Attacks When Using the Implicit Flow](/docs/get-started/authentication-and-authorization-flow/implicit-flow-with-form-post/mitigate-replay-attacks-when-using-the-implicit-flow)
# Add Login Using the Implicit Flow with Form Post
Source: https://auth0.com/docs/get-started/authentication-and-authorization-flow/implicit-flow-with-form-post/add-login-using-the-implicit-flow-with-form-post
Learn how to add login to your single-page application (SPA) using the Implicit Flow with Form Post.
You can add login to your single-page application (SPA) using the Implicit Flow with Form Post. To learn how the flow works and why you should use it, read [Implicit Flow with Form Post](/docs/get-started/authentication-and-authorization-flow/implicit-flow-with-form-post).
Use the Implicit Flow with Form Post for login-only use cases; if you need to request access tokens while logging the user in so you can call your API, use the Authorization Code Flow with PKCE. To learn more, read [Authorization Code Flow with Proof Key for Code Exchange (PKCE](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow-with-pkce)).
To implement the Implicit Flow with Form Post, you can use the following resources:
* [Express OpenID Connect SDK](https://www.npmjs.com/package/express-openid-connect): The easiest way to implement the flow, which will do most of the heavy-lifting for you. If you use our Javascript SDK, please ensure you are implementing mitigations that are appropriate for your architecture. To learn more, read [Auth0.js Reference](/docs/libraries/auth0js).
* [Authentication API](https://auth0.com/docs/api/authentication): If you prefer to build your own solution, keep reading to learn how to call our API directly.
Following a successful login, your application will have access to the user's [ID token](/docs/secure/tokens/id-tokens). The ID token will contain basic user profile information.
## Prerequisites
Register your app with Auth0. To learn more, read [Register Single Page Applications](/docs/get-started/auth0-overview/create-applications/single-page-web-apps).
* Select **Single-Page App** as the **Application Type**.
* Add an **Allowed Callback URL** of `{https://yourApp/callback}`.
* Make sure your application's **Grant Types** include **Implicit**. To learn more, read [Update Grant Types](/docs/get-started/applications/update-grant-types).
## Authorize user
Request the user's authorization and redirect back to your app. To begin the flow, you'll need to get the user's authorization. This step may include one or more of the following processes:
* Authenticating the user;
* Redirecting the user to an Identity Provider to handle authentication;
* Checking for active Single Sign-on (SSO) sessions;
* Obtaining user consent for the requested permission level, unless consent has been previously given.
To authorize the user, your app must send the user to the authorization URL.
### Authorization URL example
### Parameters
| Parameter Name | Description |
| - | - |
| `response_type` | Denotes the kind of credential that Auth0 will return (code or token). For the Implicit Flow, the value can be `id_token`, `token`, or `id_token token`. Specifically, `id_token` returns an ID Token, and `token` returns an Access Token. |
| `response_mode` | Specifies the method with which response parameters should be returned. For security purposes, the value should be `form_post`. In this mode, response parameters will be encoded as HTML form values that are transmitted via the HTTP POST method and encoded in the body using the `application/x-www-form-urlencoded` format. |
| `client_id` | Your application's Client ID. You can find this value at your [Application's Settings](https://manage.auth0.com/#/applications/\{yourClientId}/settings). |
| `redirect_uri` | The URL to which Auth0 will redirect the browser after authorization has been granted by the user. You must specify this URL as a valid callback URL in your [Application Settings](https://manage.auth0.com/#/Applications/\{yourClientId}/settings).
**Warning:** Per the [OAuth 2.0 Specification](https://tools.ietf.org/html/rfc6749#section-3.1.2), Auth0 removes everything after the hash and does *not* honor any fragments. |
| `scope` | Specifies the [scopes](/docs/get-started/apis/scopes) for which you want to request authorization, which dictate which claims (or user attributes) you want returned. These must be separated by a space. You can request any of the [standard OpenID Connect (OIDC) scopes](https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims) about users, such as `profile` and `email`, [custom claims](/docs/secure/tokens/json-web-tokens/json-web-token-claims#custom-claims) conforming to a [namespaced format](/docs/secure/tokens/json-web-tokens/create-custom-claims), or any scopes supported by the target API (for example, `read:contacts`). |
| `state` | (recommended) An opaque arbitrary alphanumeric string that your app adds to the initial request and Auth0 includes when redirecting back to your application. To see how to use this value to prevent cross-site request forgery (CSRF) attacks, see [Mitigate CSRF Attacks With State Parameters](/docs/secure/attack-protection/state-parameters). |
| `nonce` | (required for `response_type` containing `id_token token`, otherwise recommended) A cryptographically random string that your app adds to the initial request and Auth0 includes inside the ID Token, [used to prevent token replay attacks](/docs/get-started/authentication-and-authorization-flow/implicit-flow-with-form-post/mitigate-replay-attacks-when-using-the-implicit-flow). |
| `connection` | (optional) Forces the user to sign in with a specific connection. For example, you can pass a value of `github` to send the user directly to GitHub to log in with their GitHub account. When not specified, the user sees the Auth0 Lock screen with all configured connections. You can see a list of your configured connections on the **Connections** tab of your application. |
| `organization` | (optional) ID of the organization to use when authenticating a user. When not provided, if your application is configured to **Display Organization Prompt**, the user will be able to enter the organization name when authenticating. |
| `invitation` | (optional) Ticket ID of the organization invitation. When [inviting a member to an Organization](/docs/manage-users/organizations/configure-organizations/invite-members), your application should handle invitation acceptance by forwarding the `invitation` and `organization` key-value pairs when the user accepts the invitation. |
As an example, your HTML snippet for your authorization URL when adding login to your app might look like:
### Response
If all goes well, you'll receive an `HTTP 302` response. The requested credentials are encoded in the body:
```json lines theme={null}
HTTP/1.1 302 Found
Content-Type: application/x-www-form-urlencoded
id_token=eyJ...acA&
state=xyzABC123
```
Note that the returned values depend on what you requested as a `response_type`.
| Response Type | Components |
| - | - |
| id\_token | ID Token |
| token | Access Token (plus `expires_in` and `token_type` values) |
| id\_token token | ID Token, Access Token (plus `expires_in` and `token_type` values) |
Auth0 will also return any state value you included in your call to the authorization URL.
Validate your tokens before saving them. To learn how, read [Validate ID Tokens](/docs/secure/tokens/id-tokens/validate-id-tokens) and [Validate Access Tokens](/docs/secure/tokens/access-tokens/validate-access-tokens).
ID tokens contain user information that must be decoded and extracted.
## Use cases
### Basic authentication request
This example shows the most basic request you can make when authorizing the user in step 1. It displays the Auth0 login screen and allows the user to sign in with any of your configured connections:
This will return an ID token, which you can parse from your redirect URL.
### Request user's name and profile picture
In addition to the usual user authentication, this example shows how to request additional user details, such as name and picture.
To request the user's name and picture, you need to add the appropriate scopes when authorizing the user:
Now, your ID token will contain the requested name and picture claims. When you decode the ID token, it will look similar to:
```json lines theme={null}
{
"name": "jerrie@...",
"picture": "https://s.gravatar.com/avatar/6222081fd7dcea7dfb193788d138c457?s=480&r=pg&d=https%3A%2F%2Fcdn.auth0.com%2Favatars%2Fje.png",
"iss": "https://auth0pnp.auth0.com/",
"sub": "auth0|581...",
"aud": "xvt...",
"exp": 1478113129,
"iat": 1478077129
}
```
### Request user log in with GitHub
In addition to the usual user authentication, this example shows how to send users directly to a social identity provider, such as GitHub. For this example to work, you need to go to [Auth0 Dashboard > Authentication > Social](https://manage.auth0.com/#/connections/social) and configure the appropriate connection. Get the connection name from the **Settings** tab.
To send users directly to the GitHub login screen, you need to pass the `connection` parameter and set its value to the connection name (in this case, `github`) when authorizing the user:
Now, your ID Token will contain a `sub` claim with the user's unique ID returned from GitHub. When you decode the ID Token, it will look similar to:
```json lines theme={null}
{
"name": "Jerrie Pelser",
"nickname": "jerriep",
"picture": "https://avatars.githubusercontent.com/u/1006420?v=3",
"iss": "https://auth0pnp.auth0.com/",
"sub": "github|100...",
"aud": "xvt...",
"exp": 1478114742,
"iat": 1478078742
}
```
## Learn more
* [OAuth 2.0 Authorization Framework](/docs/authenticate/protocols/oauth)
* [OpenID Connect Protocol](/docs/authenticate/protocols/openid-connect-protocol)
* [Tokens](/docs/secure/tokens)
* [Mitigate Replay Attacks When Using the Implicit Flow](/docs/get-started/authentication-and-authorization-flow/implicit-flow-with-form-post/mitigate-replay-attacks-when-using-the-implicit-flow)
* [Register Single-Page Web Applications](/docs/get-started/auth0-overview/create-applications/single-page-web-apps)
* [Update Grant Types](/docs/get-started/applications/update-grant-types)
# Mitigate Replay Attacks When Using the Implicit Flow
Source: https://auth0.com/docs/get-started/authentication-and-authorization-flow/implicit-flow-with-form-post/mitigate-replay-attacks-when-using-the-implicit-flow
Learn how to securely generate and validate a cryptographic nonce for use with the Implicit Flow with Form Post.
To mitigate replay attacks when using the [Implicit Flow with Form Post](/docs/get-started/authentication-and-authorization-flow/implicit-flow-with-form-post), a nonce must be sent on authentication requests [as required by the OpenID Connect (OIDC) specification](https://openid.net/specs/openid-connect-core-1_0.html#ImplicitAuthRequest).
The nonce is generated by the application, sent as a `nonce` query string parameter in the authentication request, and included in the ID Token response from Auth0. This allows applications to correlate the ID Token response from Auth0 with the initial authentication request.
To learn more about where to include the nonce, see [Add Login Using the Implicit Flow with Form Post](/docs/get-started/authentication-and-authorization-flow/implicit-flow-with-form-post/add-login-using-the-implicit-flow-with-form-post).
[Auth0.js](/docs/libraries/auth0js) manages `state` and `nonce` parameters for you when using [cross-origin authentication](/docs/authenticate/login/cross-origin-authentication).
## Generate a cryptographically random nonce
One way to generate a cryptographically random nonce is to use a tool like [Nano ID](https://github.com/ai/nanoid) or similar. This does require you to bundle the tool with your JavaScript code, however. If that's not possible, you can take advantage of the fact that [modern browsers](http://caniuse.com/#feat=cryptography) can use the [Web Crypto API](https://www.w3.org/TR/WebCryptoAPI/) to generate cryptographically secure random strings for use as nonces.
```javascript lines theme={null}
function randomString(length) {
var charset = '0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz+/'
result = ''
while (length > 0) {
var bytes = new Uint8Array(16);
var random = window.crypto.getRandomValues(bytes);
random.forEach(function(c) {
if (length == 0) {
return;
}
if (c < charset.length) {
result += charset[c];
length--;
}
});
}
return result;
}
```
## Persist nonces across requests
The generated nonce must be persisted in your web application using any of the following methods:
* `HttpOnly` session cookie
* HTML5 local storage value
For example:
```js lines theme={null}
window.localStorage.setItem('nonce', randomString(16));
```
## Validate ID token
Once Auth0 responds with an [ID Token](/docs/secure/tokens/id-tokens), this token must be [validated and decoded](/docs/secure/tokens/id-tokens/validate-id-tokens) as usual.
Its `nonce` claim must contain the exact same value that was sent in the request.
If not, authentication should be rejected by the application.
```javascript lines theme={null}
var jwt = '...'; // validated and decoded ID Token body
if (jwt.nonce === window.localStorage.getItem('nonce')) {
// Nonce is OK
} else {
// Nonce is not OK! Token replay attack might be underway
}
```
## Learn more
* [Implicit Flow with Form Post](/docs/get-started/authentication-and-authorization-flow/implicit-flow-with-form-post)
* [Add Login Using the Implicit Flow with Form Post](/docs/get-started/authentication-and-authorization-flow/implicit-flow-with-form-post/add-login-using-the-implicit-flow-with-form-post)
* [Implicit Flow with OIDC](/docs/authenticate/login/oidc-conformant-authentication/oidc-adoption-implicit-flow)
# Resource Owner Password Flow
Source: https://auth0.com/docs/get-started/authentication-and-authorization-flow/resource-owner-password-flow
Learn how the Resource Owner Password flow works and why you should use it for highly-trusted applications.
Because the Resource Owner Password (ROP) Flow involves the application handling the user's password, it must not be used by third-party clients.
Though we do not recommend it, highly-trusted applications can use the Resource Owner Password Flow (defined in [OAuth 2.0 RFC 6749, section 4.3](https://tools.ietf.org/html/rfc6749#section-4.3) and sometimes called Resource Owner Password Grant or ROPG), which requests that users provide credentials (username/email/phone and password), typically using an interactive form. Because credentials are sent to the backend and can be stored for future use before being exchanged for an Access Token, it is imperative that the application is absolutely trusted with this information.
Even if this condition is met, the Resource Owner Password Flow should only be used when redirect-based flows (like the [Authorization Code Flow](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow)) cannot be used.
## How it works
1. The user clicks **Login** within the application and enters their credentials.
2. Your application forwards the user's credentials to your Auth0 Authorization Server ([`/oauth/token` endpoint](https://auth0.com/docs/api/authentication#resource-owner-password)).
3. Your Auth0 Authorization Server validates the credentials.
4. Your Auth0 Authorization Server responds with an Access Token (and optionally, a Refresh Token).
5. Your application can use the Access Token to call an API to access information about the user.
6. The API responds with requested data.
## How to implement it
The easiest way to implement the Resource Owner Password Flow is to follow our tutorial to use our API endpoints to [Call Your API Using the Resource Owner Password Flow](/docs/get-started/authentication-and-authorization-flow/resource-owner-password-flow/call-your-api-using-resource-owner-password-flow).
## Realm support
Auth0 provides an extension grant that offers similar functionality to the Resource Owner Password grant, but allows you to keep separate user directories (which map to separate connections) and specify which one to use during the flow.
For example, let's say you want to present a dropdown on your application's login user interface that allows users to choose their user type: `Employees` or `Customers`. In this case, you would configure `Employees` and `Customers` as realms (and set up a corresponding connection for each), which allows employee and customer credentials to be kept in separate user directories. When you request a token, you will submit the realm value along with the user's credentials and the submitted realm will be used to verify the password.
To learn more about implementing this extension grant, read [Call Your API Using Resource Owner Password Flow: Configure Realm Support](/docs/get-started/authentication-and-authorization-flow/resource-owner-password-flow/call-your-api-using-resource-owner-password-flow).
## Rules
Rules will run for the Resource Owner Password Flow (including the Realm extension grant). However, redirect rules won't work. If you try to perform a redirect by specifying `context.redirect` in your rule, the authentication flow will return an error. To learn more about rules, read [Auth0 Rules](/docs/customize/rules). To learn more about redirect rules, read [Redirect Users from Within Rules](/docs/customize/rules/redirect-users).
## MFA support
If you need to use the Resource Owner Password Flow, but require stronger authentication, you can add multi-factor authentication (MFA). To learn how, read [Authenticate Using the Resource Owner Password Flow with MFA](/docs/secure/multi-factor-authentication/authenticate-using-ropg-flow-with-mfa).
## Attack protection
When using the Resource Owner Password Flow with brute-force protection, some attack protection features may fail. Some common issues, however, can be avoided. To learn more, read [Avoid Common Issues with Resource Owner Password Flow and Attack Protection](/docs/get-started/authentication-and-authorization-flow/resource-owner-password-flow/avoid-common-issues-with-resource-owner-password-flow-and-attack-protection).
## Learn more
* [Auth0 Rules](/docs/customize/rules)
* [Auth0 Hooks](/docs/customize/hooks)
* [Tokens](/docs/secure/tokens)
* [Token Best Practices](/docs/secure/tokens/token-best-practices)
* [Which OAuth 2.0 Flow Should I Use?](/docs/get-started/authentication-and-authorization-flow/which-oauth-2-0-flow-should-i-use)
# Avoid Common Issues with Resource Owner Password Flow and Attack Protection
Source: https://auth0.com/docs/get-started/authentication-and-authorization-flow/resource-owner-password-flow/avoid-common-issues-with-resource-owner-password-flow-and-attack-protection
Learn how to avoid common issues encountered when using the Resource Owner Password Flow to call server-side APIs with attack protection enabled.
Because the Resource Owner Password (ROP) Flow involves the application handling the user's password, it must not be used by third-party clients.
Though we do not recommend it, highly-trusted applications can call server-side APIs using the [Resource Owner Password Flow](/docs/get-started/authentication-and-authorization-flow/resource-owner-password-flow) (sometimes called Resource Owner Password Grant or ROPG), which requests that users provide credentials (username and password), typically using an interactive form. If [brute-force protection is enabled](/docs/secure/attack-protection/brute-force-protection), when Auth0 validates the credentials, we may also [check for attacks](/docs/secure/attack-protection) and perform appropriate actions if an attack is detected.
Unfortunately, when using this flow with brute-force protection, some attack protection features may fail. Some common issues, however, can be avoided.
## Attack protection and server-side APIs
Brute-force protection and suspicious IP throttling rely on having the user's IP address. When calling an API from your server, Auth0 treats the IP address of your server as the IP address of the user and provides it as input to the brute-force protection and suspicious IP throttling functionality. This could potentially trigger false positives, causing attack protection to block users or trigger warnings for legitimate requests.
To avoid this, send the user's IP address to Auth0 along with their credentials, and configure your application to trust the IP address.
Due to security considerations, you may only configure authenticated applications (such as those with authentication based on a client secret) this way. Authenticated applications must only be used from protected resources, which are typically server-side. Do not use them from native applications or Single-page applications (SPAs) because they are not capable of storing secrets.
## Configure your Application to trust the IP address
Register either a [regular web application](/docs/get-started/auth0-overview/create-applications/regular-web-apps) or a [machine-to-machine application](/docs/get-started/auth0-overview/create-applications/machine-to-machine-apps). While configuring the application:
1. Under **Credentials**, select an **Authentication Method** other than `None`.
2. Under **Settings > Advanced Settings**, locate the **OAuth** tab, and enable **Trust Token Endpoint IP Header**, which will set the `auth0-forwarded-for` header as a trusted source of the user's IP address for brute-force protection. This setting will not be available for non-authenticated applications.
## Send the user's IP address from your server
1. When you request tokens using the [Resource Owner Password Flow](/docs/get-started/authentication-and-authorization-flow/resource-owner-password-flow/call-your-api-using-resource-owner-password-flow), include an `auth0-forwarded-for` header that contains the value of the user's IP address. Be sure that the IP address you provide really belongs to your user.
Trusting headers like the `auth0-forwarded-for` (or, in general, data from applications) as sources for the user's IP address can be risky. Because this header is easy to spoof and makes it possible to bypass attack protection validation, only do this if you know you can trust that header.
2. Specify AllowLists of IPs to be ignored when triggering brute-force protection and suspicious IP throttling.
If your authenticated application is configured to send the `auth0-forwarded-for` header:
* Only the IP address contained in the `auth0-forwarded-for` header is checked against the brute-force protection and suspicious IP throttling AllowLists.
* The proxy IP address is ignored by brute-force protection and suspicious IP throttling, so doesn't need to be added to the AllowLists.
* If specific clients that use the proxy should not be subject to brute-force protection or suspicious IP throttling, add them to the AllowLists.
The `auth0-forwarded-for` header will only be accepted for authenticated calls with the Client Secret. If your application is not authenticated or is not configured to send the `auth0-forwarded-for` header:
* The originating IP address of each request is checked against the brute-force protection and suspicious IP throttling AllowLists.
* If you AllowList the IP proxy, all traffic passing through the proxy will be exempt from brute-force protection and suspicious IP throttling. This is probably not what you want.
### Example
## Handle Breached Password Detection responses
If you’ve enabled [Breached Password Detection](/docs/secure/attack-protection/breached-password-detection) for your tenant, you need to configure your application to handle responses from the [Auth0 Authentication API](https://auth0.com/docs/api/authentication) accordingly.
For example, if you send a password using the ROP flow, and Auth0 detects that it’s been compromised, the Authentication API returns a response with the HTTP `401 Unauthorized` status code and the following body:
```json lines theme={null}
{
"error": "password_leaked",
"error_description": "This login attempt has been blocked because the password you're using was previously disclosed through a data breach (not in this application). Please check your email for more information."
}
```
Your application should handle this error, render a message to the user, and [trigger an interactive password reset flow](/docs/authenticate/database-connections/password-change#authentication-api).
## Validate with logs
If your settings are working correctly, you will see the following in the logs:
```bash lines theme={null}
type: sepft
...
ip:
client_ip:
...
```
## Learn more
* [Resource Owner Password Flow](/docs/get-started/authentication-and-authorization-flow/resource-owner-password-flow)
* [Call Your API Using Resource Owner Password Flow](/docs/get-started/authentication-and-authorization-flow/resource-owner-password-flow/call-your-api-using-resource-owner-password-flow)
* [Attack Protection](/docs/secure/attack-protection)
# Call Your API Using Resource Owner Password Flow
Source: https://auth0.com/docs/get-started/authentication-and-authorization-flow/resource-owner-password-flow/call-your-api-using-resource-owner-password-flow
Learn how to call your own API from highly-trusted applications using the Resource Owner Password Flow.
This tutorial will help you call your own API using the Resource Owner Password Flow. If you want to learn how the flow works and why you should use it, see [Resource Owner Password Flow](/docs/get-started/authentication-and-authorization-flow/resource-owner-password-flow).
Because the Resource Owner Password (ROP) Flow involves the application handling the user's password, it must not be used by third-party clients.
Auth0 makes it easy for your app to implement the Resource Owner Password Flow (sometimes called Resource Owner Password Grant or ROPG) using the [Authentication API](https://auth0.com/docs/api/authentication). Keep reading to learn how to call our API directly.
## Prerequisites
**Before beginning this tutorial:**
* [Register your Application with Auth0](/docs/get-started/auth0-overview/create-applications/regular-web-apps).
* Select an **Application Type** of **Regular Web Apps**.
* Add an **Allowed Callback URL** of `{https://yourApp/callback}`. This field cannot be undefined or an error message will be returned.
* Make sure your Application's **Grant Types** include **Password**. To learn how, read [Update Grant Types](/docs/get-started/applications/update-grant-types).
* If you want your Application to be able to use Refresh Tokens, make sure the Application's **Grant Types** include **Refresh Token**. To learn how, read [Update Grant Types](/docs/get-started/applications/update-grant-types). To learn more about Refresh Tokens, read [Refresh Tokens](/docs/secure/tokens/refresh-tokens).
* [Register your API with Auth0](/docs/get-started/auth0-overview/set-up-apis)
* If you want your API to receive Refresh Tokens to allow it to obtain new tokens when the previous ones expire, enable **Allow Offline Access**.
* Set up a connection
* Make sure your connection is capable of authenticating users by username and password (for example, [database connections](/docs/get-started/applications/set-up-database-connections), or AD/LDAP, ADFS, or Azure Active Directory [enterprise connections](/docs/authenticate/identity-providers/enterprise-identity-providers)).
* Update or disable any [rules](/docs/customize/rules), so they only impact specific connections. If you get an `access_denied` error while testing the Password Owner Resource Grant, this could be due to an access control rule.
## Steps
1. [Configure tenant](#configure-tenant):Set the tenant's default connection.
2. [Request tokens](#request-tokens):
Exchange your authorization code for tokens.
3. [Call API](#call-api):
Use the retrieved Access Token to call your API.
4. [Refresh tokens](#refresh-tokens):
Use a Refresh Token to request new tokens when the existing ones expire.
Optional: [Explore sample use cases](#sample-use-cases)
Optional: [Configure realm support](#configure-realm-support)
Optional: [Configure MFA](#configure-mfa)
Optional: [Configure attack protection](#configure-anomaly-detection)
### Configure tenant
The Resource Owner Password Flow relies on a connection that is capable of authenticating users by username and password, so you must set the default connection for the tenant.
1. Go to [Auth0 Dashboard > Tenant Settings](https://manage.auth0.com/#/tenant), and scroll down to locate the **Default Directory** setting.
2. Enter the name of the connection you would like to use. Make sure it is capable of authenticating users by username and password.
### Request tokens
To call your API, you must first get the user's credentials, typically through an interactive form. Once your application has the credentials, you must exchange them for tokens. To do so, you must `POST` to the [token URL](https://auth0.com/docs/api/authentication#resource-owner-password).
#### Example POST to token URL
```bash cURL theme={null}
curl --request POST \
--url 'https://{yourDomain}/oauth/token' \
--header 'content-type: application/x-www-form-urlencoded' \
--data grant_type=password \
--data 'username={username}' \
--data 'password={password}' \
--data 'audience={yourApiIdentifier}' \
--data scope=read:sample \
--data 'client_id={yourClientId}' \
--data 'client_secret={yourClientSecret}'
```
```csharp C# theme={null}
var client = new RestClient("https://{yourDomain}/oauth/token");
var request = new RestRequest(Method.POST);
request.AddHeader("content-type", "application/x-www-form-urlencoded");
request.AddParameter("application/x-www-form-urlencoded", "grant_type=password&username=%7Busername%7D&password=%7Bpassword%7D&audience=%7ByourApiIdentifier%7D&scope=read%3Asample&client_id={yourClientId}&client_secret=%7ByourClientSecret%7D", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```
```go Go theme={null}
package main
import (
"fmt"
"strings"
"net/http"
"io/ioutil"
)
func main() {
url := "https://{yourDomain}/oauth/token"
payload := strings.NewReader("grant_type=password&username=%7Busername%7D&password=%7Bpassword%7D&audience=%7ByourApiIdentifier%7D&scope=read%3Asample&client_id={yourClientId}&client_secret=%7ByourClientSecret%7D")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("content-type", "application/x-www-form-urlencoded")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := ioutil.ReadAll(res.Body)
fmt.Println(res)
fmt.Println(string(body))
}
```
```java Java theme={null}
HttpResponse response = Unirest.post("https://{yourDomain}/oauth/token")
.header("content-type", "application/x-www-form-urlencoded")
.body("grant_type=password&username=%7Busername%7D&password=%7Bpassword%7D&audience=%7ByourApiIdentifier%7D&scope=read%3Asample&client_id={yourClientId}&client_secret=%7ByourClientSecret%7D")
.asString();
```
```javascript Node.JS theme={null}
var axios = require("axios").default;
var options = {
method: 'POST',
url: 'https://{yourDomain}/oauth/token',
headers: {'content-type': 'application/x-www-form-urlencoded'},
data: new URLSearchParams({
grant_type: 'password',
username: '{username}',
password: '{password}',
audience: '{yourApiIdentifier}',
scope: 'read:sample',
client_id: '{yourClientId}',
client_secret: '{yourClientSecret}'
})
};
axios.request(options).then(function (response) {
console.log(response.data);
}).catch(function (error) {
console.error(error);
});
```
```php PHP theme={null}
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://{yourDomain}/oauth/token",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "grant_type=password&username=%7Busername%7D&password=%7Bpassword%7D&audience=%7ByourApiIdentifier%7D&scope=read%3Asample&client_id={yourClientId}&client_secret=%7ByourClientSecret%7D",
CURLOPT_HTTPHEADER => [
"content-type: application/x-www-form-urlencoded"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
```
```python Python theme={null}
import http.client
conn = http.client.HTTPSConnection("")
payload = "grant_type=password&username=%7Busername%7D&password=%7Bpassword%7D&audience=%7ByourApiIdentifier%7D&scope=read%3Asample&client_id={yourClientId}&client_secret=%7ByourClientSecret%7D"
headers = { 'content-type': "application/x-www-form-urlencoded" }
conn.request("POST", "/{yourDomain}/oauth/token", payload, headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
```
```ruby Ruby theme={null}
require 'uri'
require 'net/http'
require 'openssl'
url = URI("https://{yourDomain}/oauth/token")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
request = Net::HTTP::Post.new(url)
request["content-type"] = 'application/x-www-form-urlencoded'
request.body = "grant_type=password&username=%7Busername%7D&password=%7Bpassword%7D&audience=%7ByourApiIdentifier%7D&scope=read%3Asample&client_id={yourClientId}&client_secret=%7ByourClientSecret%7D"
response = http.request(request)
puts response.read_body
```
##### Parameters
| Parameter Name | Description |
| - | - |
| `grant_type` | Set this to `password`. |
| `username` | The username entered by the user. |
| `password` | The password entered by the user. |
| `client_id` | Your application's Client ID. You can find this value in your [Application Settings](https://manage.auth0.com/#/Applications/\{yourClientId}/settings). |
| `client_assertion` | A JWT containing a signed assertion with your application credentials. Required when Private Key JWT is your application authentication method. |
| `client_assertion_type` | The value is `urn:ietf:params:oauth:client-assertion-type:jwt-bearer`. Required when Private Key JWT is the application authentication method. |
| `client_secret` | Your application's Client Secret. Required when Client Secret is the application authentication method. [Application Settings](https://manage.auth0.com/#/applications/\{yourClientId}/settings) is `Post` or `Basic`. If your application is not highly trusted (for example, a SPA), then do not set this parameter. |
| `audience` | The audience for the token, which is your API. You can find this in the **Identifier** field on your [API's settings tab](https://manage.auth0.com/#/apis). |
| `scope` | Specifies the [scopes](/docs/get-started/apis/scopes) for which you want to request authorization, which dictate which claims (or user attributes) you want returned. These must be separated by a space. You can request any of the [standard OpenID Connect (OIDC) scopes](https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims) about users, such as `profile` or `email`, [custom claims](/docs/secure/tokens/json-web-tokens/json-web-token-claims#custom-claims) conforming to a [namespaced format](/docs/secure/tokens/json-web-tokens/create-custom-claims), or any scopes supported by the target API (e.g., `read:contacts`). Include `offline_access` to get a [Refresh Token](/docs/glossary?term=Refresh+Token) (make sure that the **Allow Offline Access** field is enabled in the [Application Settings](https://manage.auth0.com/#/applications)). |
#### Response
If all goes well, you'll receive an `HTTP 200` response with a payload containing `access_token`, `refresh_token`, `id_token`, `token_type`, and `expires_in` values:
```json lines theme={null}
{
"access_token": "eyJz93a...k4laUWw",
"refresh_token": "GEbRxBN...edjnXbL",
"id_token": "eyJ0XAi...4faeEoQ",
"token_type": "Bearer",
"expires_in": 36000
}
```
Validate your tokens before saving them. To learn how, read [Validate ID Tokens](/docs/secure/tokens/id-tokens/validate-id-tokens) and [Validate Access Tokens](/docs/secure/tokens/access-tokens/validate-access-tokens).
Refresh tokens must be stored securely since they allow a user to remain authenticated essentially forever.
Because providing a password gives full access, any password-based exchange gives access to all scopes. For example, if you include no [API scopes](/docs/get-started/apis/scopes/api-scopes) in the request, all API scopes will be included in the Access Token. Similarly, if you include only the `openid` scope in the request, all `openid` standard [OpenID Connect scopes](/docs/get-started/apis/scopes/openid-connect-scopes) will be returned. In these cases, the `scope` parameter will be included in the response and will list the issued scopes.
If you need the user's information, include the `openid` scope in your request. If the API uses `RS256` as the [signing algorithm](/docs/get-started/applications/signing-algorithms), the Access Token will include `/userinfo` as a valid audience, which means you can use it to invoke the [/userinfo endpoint](https://auth0.com/docs/api/authentication#get-user-info) and retrieve the user's claims.
### Call API
To call your API, the application must pass the retrieved Access Token as a Bearer token in the Authorization header of your HTTP request.
```bash cURL lines theme={null}
curl --request GET \
--url https://myapi.com/api \
--header 'authorization: Bearer {accessToken}' \
--header 'content-type: application/json'
```
```csharp C# lines theme={null}
var client = new RestClient("https://myapi.com/api");
var request = new RestRequest(Method.GET);
request.AddHeader("content-type", "application/json");
request.AddHeader("authorization", "Bearer {accessToken}");
IRestResponse response = client.Execute(request);
```
```go Go lines expandable theme={null}
package main
import (
"fmt"
"net/http"
"io/ioutil"
)
func main() {
url := "https://myapi.com/api"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("content-type", "application/json")
req.Header.Add("authorization", "Bearer {accessToken}")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := ioutil.ReadAll(res.Body)
fmt.Println(res)
fmt.Println(string(body))
}
```
```java Java lines theme={null}
HttpResponse response = Unirest.get("https://myapi.com/api")
.header("content-type", "application/json")
.header("authorization", "Bearer {accessToken}")
.asString();
```
```javascript Node.JS lines theme={null}
var axios = require("axios").default;
var options = {
method: 'GET',
url: 'https://myapi.com/api',
headers: {'content-type': 'application/json', authorization: 'Bearer {accessToken}'}
};
axios.request(options).then(function (response) {
console.log(response.data);
}).catch(function (error) {
console.error(error);
});
```
```php PHP lines expandable theme={null}
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://myapi.com/api",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"authorization: Bearer {accessToken}",
"content-type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
```
```python Python lines theme={null}
import http.client
conn = http.client.HTTPSConnection("myapi.com")
headers = {
'content-type': "application/json",
'authorization': "Bearer {accessToken}"
}
conn.request("GET", "/api", headers=headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
```
```ruby Ruby lines theme={null}
require 'uri'
require 'net/http'
require 'openssl'
url = URI("https://myapi.com/api")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
request = Net::HTTP::Get.new(url)
request["content-type"] = 'application/json'
request["authorization"] = 'Bearer {accessToken}'
response = http.request(request)
puts response.read_body
```
### Refresh tokens
You have already received a [refresh token](/docs/secure/tokens/refresh-tokens) if you've been following this tutorial and completed the following:
* configured your API to allow offline access
* included the `offline_access` scope when you initiated the authentication request through the [authorize endpoint](https://auth0.com/docs/api/authentication/reference#authorize-application).
You can use the Refresh Token to get a new access token. Usually, a user will need a new access token only after the previous one expires or when gaining access to a new resource for the first time. It's bad practice to call the endpoint to get a new access token every time you call an API, and Auth0 maintains rate limits that will throttle the amount of requests to the endpoint that can be executed using the same token from the same IP.
To refresh your token, make a `POST` request to the `/oauth/token` endpoint in the Authentication API, using `grant_type=refresh_token`.
#### Example POST to token URL
```bash cURL theme={null}
curl --request POST \
--url 'https://{yourDomain}/oauth/token' \
--header 'content-type: application/x-www-form-urlencoded' \
--data grant_type=refresh_token \
--data 'client_id={yourClientId}' \
--data 'refresh_token={yourRefreshToken}'
```
```csharp C# theme={null}
var client = new RestClient("https://{yourDomain}/oauth/token");
var request = new RestRequest(Method.POST);
request.AddHeader("content-type", "application/x-www-form-urlencoded");
request.AddParameter("application/x-www-form-urlencoded", "grant_type=refresh_token&client_id={yourClientId}&refresh_token=%7ByourRefreshToken%7D", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```
```go Go theme={null}
package main
import (
"fmt"
"strings"
"net/http"
"io/ioutil"
)
func main() {
url := "https://{yourDomain}/oauth/token"
payload := strings.NewReader("grant_type=refresh_token&client_id={yourClientId}&refresh_token=%7ByourRefreshToken%7D")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("content-type", "application/x-www-form-urlencoded")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := ioutil.ReadAll(res.Body)
fmt.Println(res)
fmt.Println(string(body))
}
```
```java Java theme={null}
HttpResponse response = Unirest.post("https://{yourDomain}/oauth/token")
.header("content-type", "application/x-www-form-urlencoded")
.body("grant_type=refresh_token&client_id={yourClientId}&refresh_token=%7ByourRefreshToken%7D")
.asString();
```
```javascript Node.JS theme={null}
var axios = require("axios").default;
var options = {
method: 'POST',
url: 'https://{yourDomain}/oauth/token',
headers: {'content-type': 'application/x-www-form-urlencoded'},
data: new URLSearchParams({
grant_type: 'refresh_token',
client_id: '{yourClientId}',
refresh_token: '{yourRefreshToken}'
})
};
axios.request(options).then(function (response) {
console.log(response.data);
}).catch(function (error) {
console.error(error);
});
```
```php PHP theme={null}
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://{yourDomain}/oauth/token",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "grant_type=refresh_token&client_id={yourClientId}&refresh_token=%7ByourRefreshToken%7D",
CURLOPT_HTTPHEADER => [
"content-type: application/x-www-form-urlencoded"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
```
```python Python theme={null}
import http.client
conn = http.client.HTTPSConnection("")
payload = "grant_type=refresh_token&client_id={yourClientId}&refresh_token=%7ByourRefreshToken%7D"
headers = { 'content-type': "application/x-www-form-urlencoded" }
conn.request("POST", "/{yourDomain}/oauth/token", payload, headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
```
```ruby Ruby theme={null}
require 'uri'
require 'net/http'
require 'openssl'
url = URI("https://{yourDomain}/oauth/token")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
request = Net::HTTP::Post.new(url)
request["content-type"] = 'application/x-www-form-urlencoded'
request.body = "grant_type=refresh_token&client_id={yourClientId}&refresh_token=%7ByourRefreshToken%7D"
response = http.request(request)
puts response.read_body
```
##### Parameters
| Parameter Name | Description |
| - | - |
| `grant_type` | Set this to `refresh_token`. |
| `client_id` | Your application's Client ID. You can find this value in your [Application Settings](https://manage.auth0.com/#/Applications/\{yourClientId}/settings). |
| `refresh_token` | The refresh token to use. |
| `scope` | (optional) A space-delimited list of requested scope permissions. If not sent, the original scopes will be used; otherwise you can request a reduced set of scopes. Note that this must be URL encoded. |
#### Response
If all goes well, you'll receive an `HTTP 200` response with a payload containing a new `access_token`, its lifetime in seconds (`expires_in`), granted `scope` values, and `token_type`.
```json lines theme={null}
{
"access_token": "eyJ...MoQ",
"expires_in": 86400,
"scope": "openid offline_access",
"token_type": "Bearer"
}
```
Validate your tokens before saving them. To learn how, read [Validate ID Tokens](/docs/secure/tokens/id-tokens/validate-id-tokens) and [Validate Access Tokens](/docs/secure/tokens/access-tokens/validate-access-tokens).
### Sample use cases
#### Customize tokens
You can use Actions to change the returned scopes of Access Tokens and/or add claims to Access and ID Tokens. (To learn more about Actions, read [Auth0 Actions](/docs/customize/actions).) To do so, add the following Action, which will run after the user authenticates:
```js lines theme={null}
exports.onExecutePostLogin = async (event, api) => {
// Add custom claims to Access Token and ID Token
api.accessToken.setCustomClaim('https://foo/bar', 'value');
api.idToken.setCustomClaim('https://fiz/baz', 'some other value');
// Modify the scope of the Access Token
api.accessToken.addScope('foo');
api.accessToken.addScope('bar');
};
```
Scopes will be available in the token after the Action has run.
Auth0 returns profile information in a structured claim format as defined by the [OpenID Connect (OIDC) specification](https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims). This means that custom claims added to ID tokens or access tokens must [conform to guidelines and restrictions](/docs/secure/tokens/json-web-tokens/create-custom-claims) to avoid possible collisions.
### Configure realm support
Auth0 provides an extension grant that offers similar functionality to the Resource Owner Password grant, but allows you to keep separate user directories (which map to separate connections) and specify which one to use during the flow.
To use this variation, you must:
* Set the `grant_type` request parameter to `http://auth0.com/oauth/grant-type/password-realm`.
* Send an additional request parameter called `realm`, and set it to the name of the realm to which the user belongs. For example, if you have configured a database connection for internal employees named `employees`, and your user belongs to it, then set `realm` to `employees`.
Any connection that supports active authentication can be configured as a realm, including [database connections](/docs/get-started/applications/set-up-database-connections), [passwordless connections](/docs/authenticate/passwordless), and [AD/LDAP](/docs/authenticate/identity-providers/enterprise-identity-providers/active-directory-ldap), [ADFS](/docs/authenticate/identity-providers/enterprise-identity-providers/adfs), and [Azure Active Directory](/docs/authenticate/identity-providers/enterprise-identity-providers/azure-active-directory/v2) enterprise connections.
### Configure MFA
If you need to use the Resource Owner Password Flow, but require stronger authentication, you can add multi-factor authentication (MFA). To learn how, read [Authenticate Using the Resource Owner Password Flow with MFA](/docs/secure/multi-factor-authentication/authenticate-using-ropg-flow-with-mfa).
### Configure attack protection
When using the Resource Owner Password Flow with brute-force protection, some attack protection features may fail. Some common issues, however, can be avoided. To learn more, read [Avoid Common Issues with Resource Owner Password Flow and Attack Protection](/docs/get-started/authentication-and-authorization-flow/resource-owner-password-flow/avoid-common-issues-with-resource-owner-password-flow-and-attack-protection).
## Learn more
* [OAuth 2.0 Authorization Framework](/docs/authenticate/protocols/oauth)
* [OpenID Connect Protocol](/docs/authenticate/protocols/openid-connect-protocol)
* [Tokens](/docs/secure/tokens)
# Custom Token Exchange Flow
Source: https://auth0.com/docs/get-started/authentication-and-authorization-flow/token-exchange-flow
Understand the token exchange flow (RFC 8693) in Auth0, including how to configure Custom Token Exchange profiles and Actions to issue Auth0 tokens.
Custom Token Exchange allows applications to exchange an existing security token—referred to as the `subject_token`—for Auth0 access, ID, and refresh tokens by calling the `/oauth/token` endpoint, in accordance with [RFC 8693](https://datatracker.ietf.org/doc/html/rfc8693).
## How it works
The Custom Token Exchange flow is governed by a single, dedicated [Custom Token Exchange Action](/docs/customize/actions/explore-triggers/signup-and-login-triggers/custom-token-exchange-trigger), which is uniquely selected based on the incoming `subject_token_type` parameter, as configured in a [Custom Token Exchange Profile](/docs/authenticate/custom-token-exchange/configure-custom-token-exchange).
As a prerequisite for the flow, you must define a [Custom Token Exchange Profile](/docs/authenticate/custom-token-exchange/configure-custom-token-exchange#create-custom-token-exchange-profile) that maps a specific `subject_token_type` to the Action that will handle the requests.
When the Custom Token Exchange flow is triggered:
1. The application sends a `POST` request to the `/oauth/token` endpoint with the security token to be exchanged (the `subject_token`) and its corresponding `subject_token_type`. The request can optionally include an `actor_token` and `actor_token_type` to identify a principal acting on behalf of the user.
2. Auth0 validates the client request and credentials.
3. The associated Custom Token Exchange Action is executed. Your custom code must decode and validate the `subject_token`, enforce any necessary authorization policies, and set the user for the transaction to approve the exchange. The Action can also set an actor for the transaction via `api.authentication.setActor()`, which results in an `act` claim in the issued tokens that identifies who is acting on behalf of the user.
4. The rest of the standard Auth0 pipeline executes to generate an Auth0 access token and optionally an ID token and refresh token for the set user.
5. The requesting application can then use these newly issued tokens to securely call APIs on behalf of the user that was set in the Action.
Using `audience` set to `urn:YOUR_AUTH0_TENANT_DOMAIN:session_transfer` returns a Session Transfer Token instead of an access token, which your application can redeem to establish a web session as another user. To learn more, read [Session Delegation](/docs/authenticate/single-sign-on/session-delegation).
## Get started
To use Custom Token Exchange, you need to [create a Custom Token Exchange Profile](/docs/authenticate/custom-token-exchange/configure-custom-token-exchange#create-custom-token-exchange-profile). The general workflow involves three main configuration steps followed by your API call:
1. [Create and deploy an Action](/docs/authenticate/custom-token-exchange/configure-custom-token-exchange#create-action-for-the-profile) that will contain the logic to control the token exchange. In this Action, write the custom code logic to:
* Securely decode and validate the incoming `subject_token`.
* Perform any required authorization steps for the transaction.
* Set the corresponding user for the transaction using the available methods in the [Custom Token Exchange Actions API Object](/docs/customize/actions/explore-triggers/signup-and-login-triggers/custom-token-exchange-trigger/custom-token-exchange-api-object).
2. [Create the Custom Token Exchange Profile](/docs/authenticate/custom-token-exchange/configure-custom-token-exchange#create-custom-token-exchange-profile) in your tenant. The profile establishes a one-to-one mapping between a specific `subject_token_type` you will use in your requests and the Action you just created.
3. [Enable Custom Token Exchange for your application](/docs/authenticate/custom-token-exchange/configure-custom-token-exchange#enable-custom-token-exchange-for-your-application).
Once you’ve created the Custom Token Exchange Profile, you are ready to:
1. Call your API: You can now make a `POST` request to the `/oauth/token` endpoint with the necessary parameters, including the `subject_token` and the `subject_token_type` that corresponds to your configured profile. To learn more, read [Call your API using Custom Token Exchange](/docs/get-started/authentication-and-authorization-flow/token-exchange-flow/call-your-api-using-the-custom-token-exchange-flow).
## Learn more
* [Custom Token Exchange](/docs/authenticate/custom-token-exchange)
* [Example Use Cases](/docs/authenticate/custom-token-exchange/cte-example-use-cases)
* [Configure Custom Token Exchange](/docs/authenticate/custom-token-exchange/configure-custom-token-exchange)
# Call Your API Using the Custom Token Exchange Flow
Source: https://auth0.com/docs/get-started/authentication-and-authorization-flow/token-exchange-flow/call-your-api-using-the-custom-token-exchange-flow
Learn how to call your API with a subject token to exchange it for Auth0 access, ID, and refresh tokens using Custom Token Exchange.
To use Custom Token Exchange, make a `POST` request to the `/oauth/token` endpoint with the following parameters:
Remember that subject and actor tokens used with Custom Token Exchange can be any token format or type, as long as your Action code can interpret them. You must implement strong validation of the tokens you receive and accept. If you fail to do so, you open yourself up to different attack vectors, such as spoofing or replay attacks, resulting in bad actors being able to authenticate with someone else's user ID or acting on their behalf in an unauthorized manner.
Each `subject_token_type` maps to a Custom Token Exchange Profile and is associated with an Action that will be executed to control that transaction.
| Parameter | Description |
| - | - |
| `grant_type` | For Custom Token Exchange, use `urn:ietf:params:oauth:grant-type:token-exchange`. |
| `subject_token_type` | The type of the subject token. For Custom Token Exchange, this can be any URI scoped under your own ownership, such as `http://acme.com/legacy-token` or `urn:acme:legacy-token`.
The following namespaces are reserved and cannot be used:
`http://auth0.com`
`https://auth0.com`
`http://okta.com`
`https://okta.com`
`urn:ietf`
`urn:auth0`
`urn:okta`
|
| `subject_token` | The subject token, which your action should validate and use to identify the user. |
| `client_id` | The client ID of the application you are using for the Token Exchange. As for other grant types, you can also pass the client ID in the Authorization header using HTTP Basic Auth. |
| `client_secret` | The client secret of the application you are using for the Token Exchange. As for other grant types, you can also pass the client secret in the Authorization header using HTTP Basic Auth.
Other alternatives are also available as explained in [Auth0 Authentication API reference docs](https://auth0.com/docs/api/authentication#authentication-methods).
Note Custom Token Exchange can be used by public Applications. Make sure to read [Attack Protection](#attack-protection) in that case. |
| `audience` | The API identifier defined in Auth0. The default tenant audience will be used when not present, as configured in [Tenant Settings](/docs/get-started/tenant-settings). |
| `scope` | (Optional) The OAuth2 scope parameter. |
| `organization` | (Optional) The organization identifier you want the request to be associated with. Alternatively, you can specify an organization name if [Use Organization Names in Authentication API](/docs/manage-users/organizations/configure-organizations/use-org-name-authentication-api) is allowed for your tenant. To learn more about how the request is processed, read about the [api.authentication.setOrganization() API method](/docs/customize/actions/explore-triggers/signup-and-login-triggers/custom-token-exchange-trigger/custom-token-exchange-api-object#api-authentication-setorganization-organization). |
| `actor_token` | (Optional) A token identifying the actor or the principal performing delegation on behalf of the subject user. Must be provided together with `actor_token_type`. |
| `actor_token_type` | (Optional) The type of the actor token. Must be provided together with `actor_token`. For Auth0 ID tokens, use `urn:ietf:params:oauth:token-type:id_token` for automatic server-side validation. For other values, follow the same namespace restrictions as `subject_token_type`. |
When an actor is set for the transaction, refresh tokens are not issued regardless of requested scopes. The `offline_access` scope is excluded from the response. This is by design: delegated tokens should not outlive the immediate exchange, ensuring that each subsequent access request goes through the CTE Action's authorization logic to re-validate the delegation.
Your CTE Action is responsible for securely validating the `actor_token` by applying the same rigor (e.g., cryptographic signature verification) as you would for the `subject_token`. When `actor_token_type` is `urn:ietf:params:oauth:token-type:id_token`, Auth0 performs this validation automatically.
Other extension parameters not listed above are included in the `event.request.body` in the corresponding Action.
## Sample request
```bash lines theme={null}
curl --location 'https://{yourDomain}/oauth/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=urn:ietf:params:oauth:grant-type:token-exchange' \
--data-urlencode 'audience=https://api.acme.com' \
--data-urlencode 'scopes=openid offline_access acme-scope1 acme-scope2' \
--data-urlencode 'subject_token_type=urn:acme:external-idp-migration' \
--data-urlencode 'subject_token=t8e7S2D9trQm73e .... iqBR3GjxDtbDVjpfQU' \
--data-urlencode 'client_id=' \
--data-urlencode 'client_secret='
--data-urlencode 'organization=periscope-acme'
```
## Sample request with actor token
When performing a delegated authorization exchange, include `actor_token` and `actor_token_type`:
```bash lines theme={null}
curl --location 'https://{yourDomain}/oauth/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=urn:ietf:params:oauth:grant-type:token-exchange' \
--data-urlencode 'audience=https://api.acme.com' \
--data-urlencode 'scopes=openid acme-scope1 acme-scope2' \
--data-urlencode 'subject_token_type=urn:acme:legacy-token' \
--data-urlencode 'subject_token=t8e7S2D9trQm73e .... iqBR3GjxDtbDVjpfQU' \
--data-urlencode 'actor_token=eyJhbGciOiJSUzI1NiI .... kXdF9tZ3c' \
--data-urlencode 'actor_token_type=urn:ietf:params:oauth:token-type:id_token' \
--data-urlencode 'client_id=' \
--data-urlencode 'client_secret='
```
# Which OAuth 2.0 Flow Should I Use?
Source: https://auth0.com/docs/get-started/authentication-and-authorization-flow/which-oauth-2-0-flow-should-i-use
Learn how to identify the right OAuth 2.0 flow for your application type, from server-side web apps and SPAs to machine-to-machine and device flows.
The [OAuth 2.0 Authorization Framework](/docs/authenticate/protocols/oauth) supports several different flows (or grants). Flow are ways of retrieving an Access Token. Deciding which one is suited for your use case depends mostly on your [application type](/docs/get-started/applications), but other parameters weigh in as well, like the level of trust for the client, or the experience you want your users to have.
## OAuth 2.0 terminology
* **Resource Owner**: Entity that can grant access to a protected resource. Typically, this is the end-user.
* **Client**: Application requesting access to a protected resource on behalf of the Resource Owner.
* **Resource Server**: Server hosting the protected resources. This is the API you want to access.
* **Authorization Server**: Server that authenticates the Resource Owner and issues Access Tokens after getting proper authorization. In this case, Auth0.
* **User Agent**: Agent used by the Resource Owner to interact with the Client (for example, a browser or a native application).
## Is the Client the Resource Owner?
The first decision point is about whether the party that requires access to resources is a machine. In the case of machine-to-machine authorization, the Client is also the Resource Owner, so no end-user authorization is needed. An example is a cron job that uses an API to import information to a database. In this example, the cron job is the Client and the Resource Owner since it holds the Client ID and Client Secret and uses them to get an Access Token from the Authorization Server.
If this case matches your needs, then to learn how this flow works and how to implement it, see [Client Credentials Flow](/docs/get-started/authentication-and-authorization-flow/client-credentials-flow).
## Is the Client a web app executing on the server?
If the Client is a regular web app executing on a server, then the Authorization Code Flow is the flow you should use. Using this the Client can retrieve an Access Token and, optionally, a Refresh Token. It's considered the safest choice since the Access Token is passed directly to the web server hosting the Client, without going through the user's web browser and risking exposure.
If this case matches your needs, then to learn how this flow works and how to implement it, see [Authorization Code Flow](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow).
## Is the Client absolutely trusted with user credentials?
This decision point may result in the Resource Owner Password Credentials Grant. In this flow, the end-user is asked to fill in credentials (identifier/password), typically using an interactive form. This information is sent to the backend and from there to Auth0. It is therefore imperative that the Client is absolutely trusted with this information.
This grant should only be used when redirect-based flows (like the [Authorization Code Flow](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow)) are not possible. If this is your case, then to learn about how this flow works and how to implement it, see [Resource Owner Password Flow](/docs/get-started/authentication-and-authorization-flow/resource-owner-password-flow).
## Is the Client a Single-Page App?
If the Client is a Single-Page App (SPA), an application running in a browser using a scripting language like JavaScript, there are two grant options: the Authorization Code Flow with Proof Key for Code Exchange (PKCE) and the Implicit Flow with Form Post. For most cases, we recommend using the Authorization Code Flow with PKCE because the Access Token is not exposed on the client side, and this flow can return [Refresh Tokens](/docs/secure/tokens/refresh-tokens).
To learn more about how this flow works and how to implement it, see [Authorization Code Flow with Proof Key for Code Exchange (PKCE)](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow-with-pkce). The [Auth0 Single-Page App SDK](/docs/libraries/auth0-single-page-app-sdk) provides high-level API for implementing Authorization Code Flow with PKCE in SPAs.
If your SPA doesn't need an Access Token, you can use the Implicit Flow with Form Post. To learn more about how this flow works and how to implement it, see [Implicit Flow with Form Post](/docs/get-started/authentication-and-authorization-flow/implicit-flow-with-form-post).
## Is the Client a Native/Mobile App?
If the Application is a native app, then use the **Authorization Code Flow with Proof Key for Code Exchange (PKCE)**.
To learn more about how this flow works and how to implement it, see [Authorization Code Flow with Proof Key for Code Exchange (PKCE)](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow-with-pkce).
## I have an application that needs to talk to different resource servers
If a single application needs access tokens for different resource servers, then multiple calls to `/authorize` (that is, multiple executions of the same or different Authorization Flow) needs to be performed. Each authorization will use a different value for `audience`, which will result in a different access token at the end of the flow. For more information, see the [OAuth 2.0: Audience Information Specification](https://tools.ietf.org/html/draft-tschofenig-oauth-audience-00#section-3).
## Can I try the endpoints before I implement my application?
Sure! You can use our [Authentication API Debugger Extension](/docs/customize/extensions/authentication-api-debugger-extension). You can find detailed instructions per `/grant` endpoint at our [Authentication API Reference](https://auth0.com/docs/api/authentication).
* For the Authorize endpoint, go to [Authorize Application](https://auth0.com/docs/api/authentication#authorize-application) and read the "Test this endpoint" paragraph for the grant you want to test.
* For the Token endpoint, go to [Get Token](https://auth0.com/docs/api/authentication#get-token) and read the "Test this endpoint" section for the grant you want to test.
## Does the Client Application need to challenge users for authentication without browser interaction?
Client-Initiated Backchannel Authentication is currently in Early Access. To enable CIBA, contact your Technical Account Manager.
Client-Initiated Backchannel Authentication (CIBA) is an OpenID Foundation standard for implementing an alternative authentication flow to [OpenID Connect](https://openid.net/developers/how-connect-works/). CIBA differs from the standard OpenID Connect flow in that:
* The client application initiates the authentication process on behalf of the end user.
* There's no need for a browser for user interaction.
* There's direct communication between the client application and the OpenID Provider.
CIBA is useful when the user can't trust the client application, the client application doesn't have a browser, or the user is not in front of the application that requires authentication. Here are some examples of where CIBA flows can be used:
* **User check-in at a retail sales terminal:** For click-collect scenarios, a user can authenticate at a public kiosk and confirm their presence.
* **Authenticating in a call center or at a clerk's desk:** A call center agent can initiate an authentication flow to authenticate a caller, typically using a custom mobile app on a smartphone.
* **Authenticating on a device with no input:** For example, a smart speaker (or another connected device) can use a backend service to contact the user for authentication, typically using a custom mobile app on a smartphone.
CIBA defines two devices:
* **Consumption device**: The device that helps the user consume a service.
* **Authentication device**: The device on which the user will authenticate and grant consent.
To learn more, read [Client-Initiated Backchannel Authentication Flow](/docs/get-started/authentication-and-authorization-flow/client-initiated-backchannel-authentication-flow).
# Identity Fundamentals
Source: https://auth0.com/docs/get-started/identity-fundamentals
Explore the core concepts of identity and access management (IAM), including authentication, authorization, and the protocols Auth0 uses.
# Authentication vs. Authorization
Source: https://auth0.com/docs/get-started/identity-fundamentals/authentication-and-authorization
Understand the difference between authentication and authorization, how they work together, and how Auth0 handles each in your applications.
While often used interchangeably, [authentication](/docs/authenticate) and authorization represent fundamentally different functions. In this article, we compare and contrast the two to show how they protect applications in complementary ways.
## What are authentication and authorization?
In simple terms, authentication is the process of verifying who a user is, while authorization is the process of verifying what they have access to.
Comparing these processes to a real-world example, when you go through security in an airport, you show your ID to authenticate your identity. Then, when you arrive at the gate, you present your boarding pass to the flight attendant, so they can authorize you to board your flight and allow access to the plane.
## Authentication vs. authorization
Here's a quick overview of the differences between authentication and authorization:
| Authentication | Authorization |
| - | - |
| Determines whether users are who they claim to be | Determines what users can and cannot access |
| Challenges the user to validate credentials (for example, through passwords, answers to security questions, or facial recognition) | Verifies whether access is allowed through policies and rules |
| Usually done before authorization | Usually done after successful authentication |
| Generally, transmits info through an ID Token | Generally, transmits info through an [Access Token](/docs/glossary?term=Access+Token) |
| Generally governed by the [OpenID Connect (OIDC) protocol](/docs/glossary?term=OpenID+Connect+%28OIDC%29+protocol) | Generally governed by the OAuth 2.0 framework |
| Example: Employees in a company are required to authenticate through the network before accessing their company email | Example: After an employee successfully authenticates, the system determines what information the employees are allowed to access |
In short, access to a resource is protected by both authentication and authorization. If you can't prove your identity, you won't be allowed into a resource. And even if you can prove your identity, if you are not authorized for that resource, you will still be denied access.
Auth0 has products and services for authentication, like [passwordless](/docs/authenticate/passwordless/passwordless-with-universal-login), [multi-factor authentication](/docs/secure/multi-factor-authentication) (MFA), and [Single-Sign On (SSO)](/docs/authenticate/single-sign-on) you can configure using Auth0 Dashboard or Management API. For authorization, Auth0 offers [role-based access control](/docs/manage-users/access-control/rbac) (RBAC) or [fine grained authorization](https://docs.fga.dev/fga) FGA).
# Introduction to Identity and Access Management (IAM)
Source: https://auth0.com/docs/get-started/identity-fundamentals/identity-and-access-management
Basic overview of the computer software field of identity and access management, written for those new to the space
## What is identity and access management (IAM)?
Identity and access management provides control over user validation and resource access. Commonly known as IAM, this technology ensures that the right people access the right digital resources at the right time and for the right reasons.
## IAM basic concepts
To understand IAM, you must be familiar with some fundamental concepts:
* A **digital resource** is any combination of applications and data in a computer system. Examples of digital resources include web applications, APIs, platforms, devices, or databases.
* The core of IAM is **identity**. Someone wants access to your resource. It could be a customer, employee, member, participant, and so on. In IAM, a **user** account is a digital identity. User accounts can also represent non-humans, such as software, Internet of Things devices, or robotics.
* **Authentication** is the verification of a digital identity. Someone (or something) authenticates to prove that they’re the user they claim to be.
* **Authorization** is the process of determining what resources a user can access.
## The difference between authentication and authorization
It’s common to confuse authentication and authorization because they seem like a single experience to users. They are two separate processes: authentication proves a user’s identity, while authorization grants or denies the user’s access to certain resources.
You can think of authentication and authorization as the security system for an office building. Users are the people who want to enter the building. Resources that people want to access are areas in the building: floors, rooms, and so on.
**Authentication:** When you enter the building, you must show your photo ID badge to the security guard. The guard compares the photo on the badge to your face. If they match, the guard lets you through the door to try to access different areas of the building. The guard doesn’t tell you what rooms you can access; they only get proof that you are who you claim to be. This is authentication: confirming user identity.
**Authorization:** In this scenario, imagine the elevators and doorways in the building have key sensors for access. The chip in your badge gives you access only to the first floor, which your company occupies. If you swipe your badge to enter any other floor, your access is denied. You can access your private office but not those belonging to your colleagues. You can enter the supply room but not the server room. This is authorization: granting and denying access to different resources based on identity.
To learn more about authentication and authorization, read [Authentication vs. Authorization](/docs/get-started/identity-fundamentals/authentication-and-authorization).
## What does IAM do?
Identity and access management gives you control over user validation and resource access:
* How users become a part of your system
* What user information to store
* How users can prove their identity
* When and how often users must prove their identity
* The experience of proving identity
* Who can and cannot access different resources
You integrate IAM with your application, API, device, data store, or other technology. This integration can be very simple. For example, your web application might rely entirely on Facebook for authentication, and have an all-or-nothing authorization policy. Your app performs a simple check: if a user isn’t currently logged in to Facebook in the current browser, you direct them to do so. Once authenticated, all users can access everything in your app.
It’s unlikely that such a simple IAM solution would meet the needs of your users, organization, industry, or compliance standards. In real life, IAM is complex. Most systems require some combination of these capabilities:
* **Seamless signup and login experiences:** Smooth and professional login and signup experiences occur within your app, with your brand’s look and language.
* **Multiple sources of user identities:** Users expect to be able to log in using a variety of social (such as Google or Linkedin), enterprise (such as Microsoft Active Directory), and other [identity providers](/docs/authenticate/identity-providers).
* **Multi-factor authentication (MFA):** In an age when passwords are often stolen, requiring additional proof of identity is the new standard. Fingerprint authentication and one-time passwords are examples of common authentication methods. To learn more, read [Multi-Factor Authentication (MFA)](/docs/secure/multi-factor-authentication).
* **Step-up authentication:** Access to advanced capabilities and sensitive information require stronger proof of identity than everyday tasks and data. Step-up authentication requires additional identity verification for selected areas and features. To learn more, read [Add Step-up Authentication](/docs/secure/multi-factor-authentication/step-up-authentication).
* **Attack protection:** Preventing bots and bad actors from breaking into your system is fundamental to cybersecurity. To learn more, read [Attack Protection](/docs/secure/attack-protection).
* **Role-based access control (RBAC):** As the number of users grows, managing the access of each individual quickly becomes impractical. With RBAC, people who have the same role have the same access to resources. To learn more, read [Role-Based Access Control](/docs/manage-users/access-control/rbac).
* **Fine-grained authorization (FGA):** When you need more options to manage user access to your resources or technologies, you can use relationship-based access control to go beyond role-based. You can give individual users access to certain resources and determine the best solution for your specific use case. To learn more, read [What Is Fine-Grained Authorization?](https://docs.fga.dev/authorization-concepts#what-is-fine-grained-authorization)
Facing this level of complexity, many developers rely on an IAM platform like Auth0 instead of building their own solutions.
## How does IAM work?
“Identity and access management” is not one clearly defined system. IAM is a discipline and a type of framework for solving the challenge of secure access to digital resources. There’s no limit to the different approaches for implementing an IAM system. This section explores elements and practices in common implementations.
### Identity providers
In the past, the standard for identity and access management was for a system to create and manage its own identity information for its users. Each time a user wanted to use a new web application, they filled in a form to create an account. The application stored all of their information, including login credentials, and performed its own authentication whenever a user signed in.
As the internet grew and more and more applications became available, most people amassed countless user accounts, each with its own account name and password to remember. There are many applications that continue to work this way. But many others now rely on identity providers to reduce their development and maintenance burden and their users’ effort.
An identity provider creates, maintains, and manages identity information, and can provide authentication services to other applications. For example, Google Accounts is an identity provider. They store account information such as your user name, full name, job title, and email address. Slate online magazine lets you log in with Google (or another identity provider) rather than go through the steps of entering and storing your information anew.
Identity providers don’t share your authentication credentials with the apps that rely on them. Slate, for example, doesn’t ever see your Google password. Google only lets Slate know that you’ve proven your identity.
Other identity providers include social media (such as Facebook or LinkedIn), enterprise (such as Microsoft Active Directory), and legal identity providers (such as Swedish BankID).
### Authentication factors
Authentication factors are methods for proving a user’s identity. They commonly fall into these basic types:
| Factor type | Examples |
| - | - |
| Knowledge (something you know) | Pin, password |
| Possession (something you have) | Mobile phone, encryption key device |
| Inherence (something you are) | Fingerprint, facial recognition, iris scan |
IAM systems require one or many authentication factors to verify identity.
### Authentication and authorization standards
Authentication and authorization standards are open specifications and protocols that provide guidance on how to:
* Design IAM systems to manage identity
* Move personal data securely
* Decide who can access resources
These IAM industry standards are considered the most secure, reliable, and practical to implement:
#### OAuth 2.0
OAuth 2.0 is a delegation protocol for accessing APIs and is the industry-standard protocol for IAM. An open authorization protocol, OAuth 2.0 lets an app access resources hosted by other web apps on behalf of a user without ever sharing the user’s credentials. It’s the standard that allows third-party developers to rely on large social platforms like Facebook, Google, and Twitter for login. To learn more, read [OAuth 2.0 Authorization Framework](/docs/authenticate/protocols/oauth).
#### Open ID Connect
A simple identity layer that sits on top of OAuth 2.0, OpenID Connect (OIDC) makes it easy to verify a user’s identity and obtain basic profile information from the identity provider. OIDC is another open standard protocol. To learn more, read [OpenID Connect Protocol](/docs/authenticate/protocols/openid-connect-protocol).
#### JSON web tokens
JSON web tokens (JWTs) are an open standard that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. JWTs can be verified and trusted because they’re digitally signed. They can be used to pass the identity of authenticated users between the identity provider and the service requesting the authentication. They also can be authenticated and encrypted. To learn more, read [JSON Web Tokens](/docs/secure/tokens/json-web-tokens).
#### Security Assertion Markup Language (SAML)
Security Assertion Markup Language (SAML) is an open-standard, XML-based data format that lets businesses communicate user authentication and authorization information to partner companies and enterprise applications that their employees use. To learn more, read [SAML](/docs/authenticate/protocols/saml).
#### Web Services Federation (WS-Fed)
Developed by Microsoft and used extensively in their applications, this standard defines the way security tokens can be transported between different entities to exchange identity and authorization information. To learn more, read [Web Services Federation Protocol](/docs/authenticate/protocols/ws-fed-protocol).
## Why use an IAM platform?
Why do so many developers choose to build on an identity and access management platform instead of building their own solution from the ground up?
User expectations, customer requirements, and compliance standards introduce significant technical challenges. With multiple user sources, authentication factors, and open industry standards, the amount of knowledge and work required to build a typical IAM system can be enormous. A strong IAM platform has built-in support for all identity providers and authentication factors, offers APIs for easy integration with your software, and relies on the most secure industry standards for authentication and authorization.
For those who haven’t yet decided whether to build or buy an IAM solution, [Build vs. Buy: Guide to Evaluating Identity Management](https://auth0.com/resources/whitepapers/build-vs-buy-evaluating-identity-management) is a useful resource.
# Introduction to Auth0
Source: https://auth0.com/docs/get-started/identity-fundamentals/introduction-to-auth0
Learn about what Auth0 does, how it handles authentication and authorization, and how to connect your users, applications, and APIs.
Auth0 is an identity access management (IAM) provider. But what does this mean? If you've read [Introduction to Identity and Access Management (IAM)](/docs/get-started/identity-fundamentals/identity-and-access-management), you know an IAM solution is a gatekeeper to the resources you provide to customers as web applications, APIs, etc. The gatekeeper initiates authorization as outlined in OAuth 2.0. The addition of the OpenID Connect layer adds authentication to secure your users’ digital identities and your product.
The Auth0 identity platform supports different application types and frameworks. Whether your application is a regular web app, a mobile app, or a machine-to-machine app, Auth0 provides configurations for the most secure authorization grant, or workflow, for each. You can read more about authorization grants and choose the one for your application in our article [Which OAuth 2.0 Flow Should I Use?](/docs/get-started/authentication-and-authorization-flow/which-oauth-2-0-flow-should-i-use)
Aside from supporting secure protocols, the Auth0 identity platform allows you to customize login services to fit your business, your technology, and your customer base. Using the Auth0 Dashboard and Management API, you can create your own Auth0 instance to authenticate and authorize your customers. You can configure login behaviors, connect your user data store, manage those users, choose an authorization grant, and establish authentication factors for a seamless, scalable product with an impactful user experience.
## Get Started
### Identity fundamentals
You don’t have to be an expert on IAM to integrate Auth0 into your application or API, but you can choose the right configuration for your use case if you know some key concepts. To learn more, read our [Introduction to Identity and Access Management (IAM)](/docs/get-started/identity-fundamentals/identity-and-access-management) article. If you still have questions about planning your implementation, review our [Architecture Scenarios](/docs/get-started/architecture-scenarios) section for walk-throughs of real world scenarios.
### Integrate with Auth0
To start integrating with Auth0, you can either start with our interactive [Quickstart guides](/docs/quickstarts) for initial set-up and quick configurations, or you can register your application manually in the Auth0 Dashboard. In Dashboard, you can create a tenant, or your Auth0 instance, from the ground up. If you prefer to use SDKs, Auth0 offers multiple options for each application type. To see the full offering, navigate to [Auth0 Libraries](/docs/libraries).
You can begin your configuration with general details in the Dashboard tenant settings, such as the name displayed to your users, your company logo, your callback URLs, or where Auth0 redirects your users after authentication. You can review our recommendations by reading [Tenant Settings](/docs/get-started/tenant-settings).
Once you’ve set up the tenant, then you can create and configure your application or API. You can use the instructions in our articles [Create Applications](/docs/get-started/auth0-overview/create-applications) or [Register APIs](/docs/get-started/auth0-overview/set-up-apis) as a starting point.
### Authenticate
The vehicle of authentication is the login form, or the intermediary to allow your users access to your application. Users provide pre-determined credentials, such as username or password, in the login form to verify their digital identities.
Auth0’s Universal Login is a login form you can customize to accommodate your brand and configure to provide secure access. Some benefits of using Universal Login are:
* Passwordless login with biometrics
* Choice of multi-factor authentication methods from email, voice, or Duo
* Single Sign-on (SSO) capabilities
* Localization support
To learn more, read [Universal Login](/docs/authenticate/login/auth0-universal-login). To find out more about available features, read [Universal Login vs. Classic Login](/docs/authenticate/login/auth0-universal-login/universal-login-vs-classic-login).
Once you have a login form, you can connect your user store to Auth0. You can connect an existing database, or use a social, legal, or enterprise identity provider such as X or Azure Active Directory. New users can sign up with the connection you have configured.
Once you have a login form and user store connection, you can set protocols that work behind the scenes when users log in to your application. The most common protocols are associated with the OAuth 2.0 and OpenID Connect (OIDC) specs you may have reviewed in our [Identity Fundamentals](/docs/get-started/identity-fundamentals) article.
Another protocol to securely transmit information during log in comes in the form of tokens. Tokens from the Authorization Server, Auth0’s Authentication API, transmit information between entities. When a user logs in and access is approved, the Authentication API sends an access token, an ID token, or both depending on the authentication grant you are using to create a session. Access tokens contain information about what scopes, or permissions, the requestor has in your application while ID tokens have requestor information, such as user metadata to better the user experience.
Tokens from the Authentication API are JSON Web Tokens (JWTs) structured with:
* a header that includes the signature
* the payload that contains statements and attributes about the requestor
* the signature that verifies the token is valid
To learn more about tokens, read [Access Tokens](/docs/secure/tokens/access-tokens), [ID Tokens](/docs/secure/tokens/id-tokens), or [JSON Web Tokens](/docs/secure/tokens/json-web-tokens).
Other protocols, like SAML (Security Assertion Markup Language) and WS-Fed (Web Service Federation) are used with more specific systems. SAML works with some identity providers while WS-Fed is used with Microsoft products. You can learn more by exploring the [Protocols](/docs/authenticate/protocols) section of our documentation.
### Manage users
Managing user profiles and access can be time-consuming. If you choose to manage users with your Auth0 instance, you can remove some of the pain points.
You can easily automate CRUD operations and query user profiles using Auth0 Dashboard or the Management API. You can categorize your users into categories with Auth0 Organizations to arrange your customer-base to fit your management style. To learn more, navigate to the [Manage Users](/docs/manage-users) section of our documentation.
Your business model may include levels of access for your users. You may want a subsection of users to have read-only permissions and another subsection with the ability to edit. Auth0’s Authorization Core allows you to implement role-based access control. You can create roles, assign roles to users, and define permissions.
If you want to manage access based on browser behaviors, you can limit the lifetime of a session. A session, or the interaction between the requesting entity and your application or resource, has a lifetime limit. A session can end when the user closes the browser or navigates away from your webpage. You can extend sessions with refresh tokens that renew access tokens. Configure refresh tokens in the Dashboard. To learn more, read [Session Lifetime Limits](/docs/manage-users/sessions/session-lifetime-limits) and [Get Refresh Tokens](/docs/secure/tokens/refresh-tokens/get-refresh-tokens).
Cookies, or strings of data, tie into the session and represent an authenticated user. Cookies allow your authenticated users to maintain a session and move between web pages without being forced to re-authenticate. Once the browser closes, the cookie is cleared by the browser.
### Customize
Your brand is important, and Auth0 offers customization to make the login experience more personalized to your business. You can add your logo and color scheme to your login form as well as use a custom domain to give you ownership of the login URL. To learn more about configuration, read [Custom Domains](/docs/customize/custom-domains).
Universal Login offers numerous features to configure authentication to fit your needs, like Multi-factor authentication, passwordless authentication with device biometrics, and localization. On a more granular level, you can adjust the text of prompts your user receives when an action needs to be completed. You can configure prompts for your users to signup, to enroll a device for authentication, or to send a code to an email/SMS for users to enter for verification. You can also customize email communications to welcome new users, verify enrollment, or reset passwords with email templates. To learn more, read [Customize Universal Login Text Elements](/docs/customize/login-pages/universal-login/customize-text-elements) and [Customize Email Templates](/docs/customize/email/email-templates).
You can also configure certain events with Auth0 Actions. Actions are secure functions that execute during runtime. Actions trigger at different points in the pipeline and have a variety of uses. You could add metadata before the user signs up or redirect users to an external site. To learn more about what Actions can do for you, read [Understand How Auth0 Actions Work](/docs/customize/actions/actions-overview).
### Secure
Malicious attacks can happen anytime. Auth0 offers several attack protection options, such as Bot Detection in combination with Google reCAPTCHA Enterprise to prevent cyber attacks. To learn more about Bot Detection configuration, read [Bot Detection](/docs/secure/attack-protection/bot-detection).
Even if you are using your own login page, Auth0 offers other security options you can enable in the Auth0 Dashboard:
* Breached Password Detection
* Brute-Force Protection
* Suspicious IP Throttling
Breached password detection is a security measure against malicious agents with stolen credentials. Brute-force protection safeguards a targeted user account by limiting the amount of login attempts that automatically block the malicious IP and send a notification to the flagged user account. Suspicious IP throttling works where brute force protection leaves off to block traffic from any IP address that attempts rapid signups or logins.
Other security measures depend on how you want your users to authenticate. Enabling multi-factor authentication (MFA) in Universal Login requires users to provide two or more authentication factors. With Auth0, you can customize MFA to trigger under certain circumstances, such as a user logging in from an unknown device or from a questionable IP address. To learn more about configuring MFA, read [Adaptive MFA](/docs/secure/multi-factor-authentication/adaptive-mfa).
### Deploy and monitor
When you’ve finished testing your Auth0 instance and are ready to deploy, you can use our public or private cloud offerings. To learn more about available offerings, read [Deployment Options](/docs/deploy-monitor/deployment-options). If you need a multi-tenant capable environment, you can read more about [Private Cloud on AWS](/docs/deploy-monitor/deploy-private-cloud/private-cloud-on-aws).
To keep your deployment on track, we provide guidance in the form of pre-deployment recommendations, a deployment checklist, best practices, common fixes, and other tips to help make deployment as seamless as possible.
Once you’ve established your production environment ready for users, you can be on the lookout with error tracking and alerts. The System Center Operations Manager allows you to monitor, while event logs can be exported to an analytical tool and allow you insight on trends, user behavior, or issues.
# AI Tools
Source: https://auth0.com/docs/get-started/ai-tools
Use Auth0's AI tools to integrate AI agents with Auth0 and accelerate your development workflows.
Auth0 provides a set of AI-powered tools to integrate AI agents with Auth0 services, measure and score AI agent performance, and explore the Auth0 knowledge base directly from your development environment.
# Implementation Planning Checklists
Source: https://auth0.com/docs/get-started/architecture-scenarios/checklists
Download SDLC phase checklists for your Auth0 architecture-scenario implementation, tracking all phases of your development in customizable spreadsheets to keep your project plan on schedule.
Click the links below to download a checklist that corresponds to a phase in the SDLC (Software Development Lifecycle). You can open the checklist in any spreadsheet application and customize them to suit your needs.
## Analyze Checklist
[Analyze Checklist Download](https://cdn.auth0.com/website/docs/checklists/Analyze-Checklist.xlsx)
In the Analyze phase, analyze end-user business requirements and determine project goals as part of the high-level plan for the project. Convert the requirements and goals into system functions that the organization intends to develop. Activities include:
* Gathering business requirements
* Creating process diagrams
* Performing detailed analysis
* Alignment to project plan
## Design Checklist
[Design Checklist Download](https://cdn.auth0.com/website/docs/checklists/Design-Checklist.xlsx)
In the Design phase, describe the desired features and operations of the system, including business rules, pseudo-code, screen layouts, and other necessary documentation. Activities include:
* Infrastructure design
* System model design
## Build Checklist
[Build Checklist Download](https://cdn.auth0.com/website/docs/checklists/Build-Checklist.xlsx)
In the Build phase, develop the actual system through implementation of infrastructure and code. Activities include:
* Infrastructure implementation
* Code implementation
## Test Checklist
[Test Checklist Download](https://cdn.auth0.com/website/docs/checklists/Test-Checklist.xlsx)
In the Test phase, integrate and deploy all implemented code in the testing environment infrastructure. Testing then follows Software Testing Life Cycle activities to check the system for errors, bugs, and defects to verify that system features work as expected (or not). Activities include:
* Write test cases
* Execute test cases
## Deploy Checklist
[Deploy Checklist Download](https://cdn.auth0.com/website/docs/checklists/Deploy-Checklist.xlsx)
In the Deploy phase, deploy the system to either a staging or production environment, where actual users begin to operate and interact with it.
Eventually, you deploy all components of the system to the production environment when you make a live release.
## Monitor Checklist
[Monitor Checklist Download](https://cdn.auth0.com/website/docs/checklists/Monitor-Checklist.xlsx)
In the Monitor phase, make enhancements, corrections, and changes to ensure the system continues to work and stays updated to meet the business objectives and support the needs of the users. Activities include:
* Monitoring
* Maintenance
* Changes and adjustments
* Upgrade and adapt to future needs
# Implementation Resources
Source: https://auth0.com/docs/get-started/architecture-scenarios/implementation-resources
Resources Auth0 provides to help you get started including videos, terminology, white papers, blog posts, quickstarts, APIs, SDKs, the Auth0 Community forum, and our Auth0 Support Center.
Auth0 provides a wealth of resources to help you effectively engage with our product and community. This list provides links to the resources available, by category.
## Get started
Resources designed to help you learn the basics of Auth0 include:
* [**Getting Started documentation**](/docs/get-started): Explore the Auth0 Dashboard and common terms used for components of the Auth0 service. Gain a broad understanding of Auth0 and learn the terminology you might hear when working with Auth0 staff or reading our docs.
* [**Architecture scenarios**](/docs/get-started/architecture-scenarios): Review common architecture scenarios and learn how to implement them with Auth0. Scenarios include tutorials for common architecture patterns, such as a Single-Page Application (SPA) calling an API. High-level descriptions are useful for architects, while tutorials will help development teams.
* [**Implementation guides**](/docs/): Learn how to implement commonly-used features, such as user management and multi-factor authentication (MFA). This information is useful for both architects and developers
## Learn
Auth0 provides numerous tutorials, guides, white papers, and blog posts that focus on both learning and providing quick reference checks.
* [**Docs site**](/docs/): Browse through our docs to explore a wealth of available topics, or use our search to quickly find content related to a topic or term.
* [**Feature descriptions and white papers**](https://auth0.com/learn/): Investigate short descriptions of features, industry case studies, and reference white papers. The Auth0 Learn site provides a quick overview of Auth0 features and their business value; it is helpful for project owners as well as architects and developers.
* [**Blog posts**](https://auth0.com/blog/): Read blog posts written by experts on a variety of topics--from time-honored advice to breaking news in the identity space. Many blog posts are oriented toward architects and developers.
## Run sample code
Once your development team is ready to build, Auth0 provides sample programs, SDKs, and libraries to speed your project along.
* [**Quickstarts**](/docs/quickstarts): Investigate a rich array of small sample programs that demonstrate how to implement the key features you’ll want to include in your program, such as authentication, session management, profile updates, and logout. Quickstarts will give developers a head start on understanding how to integrate applications with Auth0.
* [Libraries and SDKs](/docs/libraries): Simplify your custom application development by using our extensive set of libraries and SDKs, which abstract many of the details of identity protocols for you. Auth0 SDKs support numerous languages and frameworks to simplify your integration with Auth0. We also provide a library for Lock, a login widget, that you can use across several platforms, including iOS and Android.
* [**Management API**](https://auth0.com/docs/api/management/v2): Explore and manipulate objects, configurations, and settings within Auth0. The Management API Explorer allows you to quickly manipulate individual objects and settings on an ad-hoc basis and test API calls before coding them into your applications.
* [**Authentication API**](https://auth0.com/docs/api/authentication): Authenticate and authorize users via the OIDC, OAuth, and SAML protocols. The Authentication API Explorer allows you to experiment with authentication and authorization flows, and test API calls before coding them into your applications.
## Try out features and API calls
While building, Auth0 allows you to experiment with and test out various product features.
* **TRY buttons/links**: Quickly try out Auth0 product features. **TRY** buttons are located throughout Auth0 and allow you to experiment with connections, rules, hooks, and email templates.
* [**Authentication API Explorer**](https://auth0.com/docs/api/authentication#introduction): Experiment with authentication and authorization flows, and test API calls before coding them into your applications.
* [**Management API Explorer**](https://auth0.com/docs/api/management/v2): Quickly manipulate individual objects and settings on an ad-hoc basis and test API calls before coding them into your applications.
## Get help
Auth0 resources that help you troubleshoot your implementation include:
* [**Auth0 Community forum**](https://community.auth0.com/): Connect with the world of Auth0 via Auth0 posts, FAQs, and community Q\&As. Architects and developers find this a valuable source of information for learning and connecting with others as well as getting help on issues.
* [**Support Center**](https://support.auth0.com/): View and manage your subscription and tenants, file and view support requests, run automated production checks on a tenant, and view compliance information. Paid subscribers will find the support center a valuable resource if an issue or question cannot be solved by documentation or by searching the forum.
* [**Create support cases**](/docs/troubleshoot/customer-support/open-and-manage-support-tickets): Create and file a support case if you need help.
* [**Support Plans and Service Level Agreements**](/docs/troubleshoot/customer-support#defect-responses): Learn about multiple levels of support available for purchase.
* [**Troubleshooting tips**](/docs/deploy-monitor/deploy-private-cloud/private-cloud-on-aws#what-to-check-before-logging-an-issue) and [**Information to include in your support case**](/docs/deploy-monitor/deploy-private-cloud/private-cloud-on-aws#information-to-provide-when-logging-an-issue): Get advice to help your development and support teams analyze issues.
* [**Supported versions**](/docs/troubleshoot/customer-support/product-support-matrix): Understand which versions of SDKs, browsers, and languages are supported. Architects and developers should review this to ensure your project employs languages, libraries, and SDKs that will allow your implementation to work with Auth0.
* [**Feedback Portal**](https://auth0.com/feedback): Make product suggestions. (You can also do this via the Support Center if you want better visibility into what you’ve filed over time.) Architects and developers can use this site to provide feedback on the Auth0 product for consideration as enhancements in the future.
* [**Professional Services**](/docs/get-started/professional-services): Engage our world-wide professional services team to help speed your project to success. Project owners will find this useful for learning how Auth0 identity experts can help accelerate your project or fill in any temporary skill gaps.
## Set up and monitor operations
When you're ready to plan your launch, Auth0 provides the following resources:
* [**Pre-launch advice**](/docs/deploy-monitor/pre-deployment-checks) and [**Production check**](/docs/deploy-monitor/pre-deployment-checks/how-to-run-production-checks): Get tips and tools to help you plan your launch. Project managers and development and operations teams should explore these tips to leverage advice for a smooth launch.
* [**Operational policies**](/docs/troubleshoot/customer-support/operational-policies): Familiarize yourself with Auth0's policies, so you know lead times for operational requests. Policies are useful for an entire team, but project owners and operations teams in particular should be aware of Auth0's operational policies.
* [**Status Dashboard**](https://status.auth0.com/): Quickly determine the availability of Auth0 services and subscribe to status updates. Although service interruptions are rare, when one occurs Auth0 conducts a root cause analysis and publishes the results on this site. Operations and support teams should be familiar with how to check Auth0 status.
* [**Monitor endpoints**](/docs/deploy-monitor): Learn how to integrate our monitoring endpoints into your monitoring infrastructure. This information is of particular use to operations teams and project owners.
* [**Log data**](/docs/deploy-monitor/logs): Learn about the types of logs Auth0 provides, log data retention, and tools you can use to export log data to external analytical tools for analysis and long-term data storage. This information is useful for developers and operations teams, as well as compliance teams interested in data retention.
* [**Dashboard notices**](/docs/get-started/architecture-scenarios/business-to-consumer/operations#notifications): Stay informed about important announcements from Auth0. From time to time, Auth0 notifies you of important information via your Auth0 Dashboard and (depending on the severity of the information) via email to your registered Auth0 Dashboard Admins. You should regularly log in to the Dashboard and check the bell icon at the top for any important notices.
## Satisfy privacy, security, and compliance needs
View info on Auth0’s privacy policy, security policy, compliance certifications, and how Auth0 can help you with your compliance needs. This information is useful for project owners as well as security, privacy teams, and procurement teams.
* [Privacy and Cookie Policy](https://auth0.com/privacy)
* [Security, Privacy and Compliance](https://auth0.com/security/)
* [Compliance Frameworks and Certifications](/docs/secure/data-privacy-and-compliance)
# Mobile Applications with API
Source: https://auth0.com/docs/get-started/architecture-scenarios/mobile-api
Explains the architecture scenario with a mobile application communicating with an API.
In this scenario we will build a timesheet API for a fictitious company named ExampleCo. The API will allow management of timesheet entries for an employee or a contractor.
We will also be building a mobile application which will be used to view and log timesheet entries in the centralized timesheet database using the API.
### TL;DR
* Auth0 provides API Authentication and Authorization as a means to secure access to API endpoints (see [API Authentication and Authorization](/docs/get-started/architecture-scenarios/mobile-api/part-1#api-authentication-and-authorization))
* For authorizing a mobile app user and granting access to the API, Auth0 supports the [Authorization Code Flow with Proof Key for Code Exchange (PKCE)](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow-with-pkce) (see [Proof Key for Code Exchange](/docs/get-started/architecture-scenarios/mobile-api/part-1#proof-key-for-code-exchange-pkce-))
* Both the mobile app and the API must be configured in the Auth0 Dashboard (see [Auth0 Configuration](/docs/get-started/architecture-scenarios/mobile-api/part-2))
* User Permissions can be enforced using the Authorization Extension (see [Configure the Authorization Extension](/docs/get-started/architecture-scenarios/mobile-api/part-2#configure-the-authorization-extension))
* The API is secured by ensuring that a valid Access Token is passed in the HTTP Authorization header when calls are made to the API (see [Implement the API](/docs/get-started/architecture-scenarios/mobile-api/part-3#secure-the-endpoints))
* The Auth0.Android SDK can be used to authorize the user of the mobile app and obtain a valid Access Token which can be used to call the API (see [Authorize the User](/docs/get-started/architecture-scenarios/mobile-api/part-3#authorize-the-user))
* The mobile app can retrieve the user's profile information by decoding the ID Token (see [Get the User Profile](/docs/get-started/architecture-scenarios/mobile-api/part-3#get-the-user-profile))
* UI Elements can be displayed conditionally based on the scope that was granted to the user (see [Display UI Elements Conditionally Based on Scope](/docs/get-started/architecture-scenarios/mobile-api/part-3#display-ui-elements-conditionally-based-on-scope))
* The mobile app provides the Access Token in the HTTP Authorization header when making calls to the API (see [Call the API](/docs/get-started/architecture-scenarios/mobile-api/part-3#call-the-api))
* The mobile app user's Access Token can be renewed to ensure the user does not have to log in again during a session (see [Renew the Token](/docs/get-started/architecture-scenarios/mobile-api/part-3#renew-the-token))
## The Premise
ExampleCo is a consulting startup company. Currently they have approximately 100 employees and they also outsource several activities to external contractors. All employees and external contractors are required to fill in their timesheets every week.
The company has built a timesheets application, a scenario we covered in [Single Sign-On for Regular Web Apps](/docs/get-started/architecture-scenarios/sso-for-regular-web-apps). The internal employees use this web app to fill in their timesheets, but the company wants a mobile application for employees and contractors to use while not on the premises. The app will be used to log timesheet entries and send the data to the centralized timesheet database using the API. The app will also allow managers to approve timesheet entries.
### Goals & Requirements
ExampleCo wants to build a flexible solution. There are potential multiple employees and contractors who should be able to log timesheet entries, as well as batch processes which may upload timesheet entries from other, external systems.
Hence the company has decided to develop a single Timesheets API which will be used to log time not only by this mobile app, but by all other apps as well. They want to put in place a security architecture that is flexible enough to accommodate this. ExampleCo wants to ensure that a large part of the code and business logic for the application can be shared across the different applications.
It is required that only authorized users and applications are allowed access to the Timesheets API.
## Learn more
* [Solution Overview (Mobile Apps + API)](/docs/get-started/architecture-scenarios/mobile-api/part-1)
* [Auth0 Configuration (Mobile Apps + API)](/docs/get-started/architecture-scenarios/mobile-api/part-2)
* [API and Mobile Configuration (Mobile Apps + API)](/docs/get-started/architecture-scenarios/mobile-api/part-3)
* [Node.js API Implementation (Mobile Apps + API)](/docs/get-started/architecture-scenarios/mobile-api/api-implementation-nodejs)
* [Android Mobile Application Implementation (Mobile Apps + API)](/docs/get-started/architecture-scenarios/mobile-api/mobile-implementation-android)
* [Conclusion (Mobile Apps + API)](/docs/get-started/architecture-scenarios/mobile-api/part-4)
# Node.js API Implementation (Mobile Apps + API)
Source: https://auth0.com/docs/get-started/architecture-scenarios/mobile-api/api-implementation-nodejs
The Node.js implementation of the API for the Mobile + API architecture scenario
This document is part of the Mobile + API Architecture Scenario and it explains how to implement the API in Node.js. The full source code for the Node.js API implementation can be found in [this GitHub repository](https://github.com/auth0-samples/auth0-pnp-exampleco-timesheets/tree/master/timesheets-api/node).
Please refer to the scenario for information on the implemented solution.
This implementation uses the [Express web application framework](http://expressjs.com/) to build a Node.js API.
##### Create a package.json file
Create a folder for your API, navigate into it, and run `npm init`. This sets up your `package.json` file.
Leave the default settings or change them as you see fit.
Our sample's `package.json` looks like the following:
```json lines theme={null}
{
"name": "timesheets-api",
"version": "1.0.0",
"description": "API used to add timesheet entries for employees and contractors",
"main": "index.js",
"scripts": {
"start": "node index.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"dependencies": {
"body-parser": "^1.20.0",
"cors": "^2.8.5",
"express": "^4.18.0",
"express-oauth2-jwt-bearer": "^1.6.0"
},
"author": "Auth0",
"license": "MIT"
}
```
##### Install the dependencies
Next, set the dependencies with the following modules:
* **express**: This module adds the [Express web application framework](https://expressjs.com/).
* **cors**: This module adds support for enabling [CORS](https://en.wikipedia.org/wiki/Cross-origin_resource_sharing), which is required since the API is called from a Single-Page Application that runs on a different domain inside a web browser.
* **jwks-rsa**: This library retrieves RSA signing keys from a JWKS (JSON Web Key Set) endpoint. Using `expressJwtSecret`, we can generate a secret provider that provides the right signing key to `express-jwt` based on the `kid` in the JWT header. To learn more, refer to the [node-jwks-rsa GitHub repository](https://github.com/auth0/node-jwks-rsa).
* **express-jwt**: This module authenticates HTTP requests using JWT tokens in your Node.js applications. It provides several functions that make working with JWTs easier. For more information, refer to the [express-jwt GitHub repository](https://github.com/auth0/express-jwt).
* **body-parser**: This is a Node.js body parsing middleware. It extracts the entire body portion of an incoming request stream and exposes it on `req.body` as something easier with which to interface.
To install these dependencies run the following:
```bash wrap lines theme={null}
npm install express cors express-jwt jwks-rsa body-parser express-jwt-authz --save
```
##### Implement the endpoints
Navigate to your API directory and create a `server.js` file. Your code needs to:
* Get the dependencies.
* Implement the endpoint(s).
* Launch the API server.
This is our sample implementation:
```javascript lines theme={null}
const express = require('express');
const app = express();
const { expressjwt: jwt } = require('express-jwt');
const jwksRsa = require('jwks-rsa');
const cors = require('cors');
const bodyParser = require('body-parser');
// Enable CORS
app.use(cors());
// Enable the use of request body parsing middleware
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true
}));
// Create timesheets API endpoint
app.post('/timesheets', function(req, res){
res.status(201).send({message: "This is the POST /timesheets endpoint"});
})
// Launch the API Server at localhost:8080
app.listen(8080);
```
Launch your API server using `node server` and make an HTTP POST request to `localhost:8080/timesheets`. You should see a JSON response with the message `This is the POST /timesheets endpoint`.
So now we have our endpoint but anyone can call it. Continue to the next step to see how we can fix this.
In order to validate our token, use the `jwt` function, provided by the [express-jwt middleware](https://github.com/auth0/express-jwt#usage), and the `jwks-rsa` to retrieve our secret. The libraries do the following:
1. `express-jwt` decodes the token and pass the request, the header, and the payload to `jwksRsa.expressJwtSecret`.
2. `jwks-rsa` downloads all signing keys from the JWKS endpoint and see if a one of the signing keys matches the `kid` in the header of the JWT. If none of the signing keys match the incoming `kid`, an error will be thrown. If we have a match, pass the right signing key to `express-jwt`.
3. `express-jwt` continues its own logic to validate the signature of the token, the expiration, `audience` and the `issuer`.
The steps we will follow in our code are:
* Create the middleware function to validate the access token.
* Enable the use of the middleware in our routes.
You can also write some code to actually save the timesheet to a database. This is our sample implementation (some code is omitted for brevity):
If we launch our server now and do an HTTP POST to `localhost:8080/timesheets` we should get the error message `Missing or invalid token` (which is accurate since we didn’t send an access token in our request).
In order to test the working scenario as well we need to:
* Get an access token. For details on how to do so refer to: [Get an Access Token](/docs/secure/tokens/access-tokens/get-access-tokens).
* Invoke the API while adding an `Authorization` header to our request with the value `Bearer ACCESS_TOKEN` (where `ACCESS_TOKEN` is the value of the token we retrieved in the first step).
In this step, we add the ability to check if the application has permissions (or scopes) and use our endpoint in order to create a timesheet. In particular, we want to ensure that the token has the correct scope, which is `batch:upload`.
In order to do this, we make use of the `express-jwt-authz` Node.js package, so add that to your project:
```bash lines theme={null}
npm install express-jwt-authz --save
```
Now add a call to `jwtAuthz(...)` to your middleware to ensure that the JWT contain a particular scope in order to execute a particular endpoint.
We add an additional dependency. The **express-jwt-authz** library, which is used in conjunction with express-jwt, validates the [JWT](/docs/secure/tokens/json-web-tokens) and ensures it bears the correct permissions to call the desired endpoint. For more information, refer to the [express-jwt-authz GitHub repository](https://github.com/auth0/express-jwt-authz).
This is our sample implementation (some code is omitted for brevity):
```javascript lines theme={null}
// set dependencies - some code omitted
const jwtAuthz = require('express-jwt-authz');
// Enable CORS - code omitted
// Create middleware for checking the JWT - code omitted
// Enable the use of request body parsing middleware - code omitted
// create timesheets API endpoint
app.post('/timesheets', checkJwt, jwtAuthz(['create:timesheets'], { customUserKey: 'auth' }), function(req, res){
var timesheet = req.body;
// Save the timesheet to the database...
//send the response
res.status(201).send(timesheet);
})
// launch the API Server at localhost:8080 - code omitted
```
If we invoke our API with a token that does not include this scope, then we should get the error message Forbidden with the HTTP status code `403`. You can test this by removing this scope from your API.
The `express-jwt` middleware that is used to validate the JWT also sets `req.user` with the information contained in the JWT. If you want to use the `sub` claim to identify the user uniquely, you can use `req.user.sub`. For the timesheets application, we want to use the email address of the user as a unique identifier.
##### Create an Action
First, [create a new Action](/docs/customize/actions/write-your-first-action) that will add the email address of the user to the access token.
1. Navigate to [Auth0 Dashboard > Actions > Library](https://manage.auth0.com/#/actions/library), and select **Build Custom**.
2. Enter a descriptive **Name** for your Action (for example, `Add email to access token`), select the **Login / Post Login** trigger, and select **Create**.
3. Locate the Actions Code Editor, copy the following JavaScript code into it, and select **Save Draft** to save your changes:
```text lines theme={null}
exports.onExecutePostLogin = async (event, api) => {
const namespace = 'https://my-app.example.com';
api.accessToken.setCustomClaim(`${namespace}/email`, event.user.email);
}
```
The `namespace` is used to ensure the claim has a unique name that does not clash with standard OIDC claims or internal services. To learn more about restrictions and guidelines with namespaced and non-namespaced claims, read [Create Custom Claims](/docs/secure/tokens/json-web-tokens/create-custom-claims).
4. From the Actions Code Editor sidebar, select Test (play icon), then select **Run** to [test your code](/docs/customize/actions/test-actions).
5. When you’re ready for the Action to go live, select **Deploy**.
##### Add your Action to the Post-Login Trigger
Next, add the Action you created to the [Post-Login Trigger](https://manage.auth0.com/#/actions/triggers/post-login/). To learn how to attach Actions to Triggers, read [Write Your First Action](/docs/customize/actions/write-your-first-action).
##### Retrieve the unique identifier
Finally, from inside your API, retrieve the value of the claim from `req.auth`. Use that value as the unique user identifier to associate with timesheet entries.
```js lines theme={null}
app.get('/timesheets', checkJwt, jwtAuthz(['read:timesheets'], { customUserKey: 'auth' }), function(req, res) {
var timesheet = req.body;
// Associate the timesheet entry with the current user
var userId = req.auth['https://api.exampleco.com/email'];
timesheet.user_id = userId;
// Save the timesheet to the database...
//send the response
res.status(201).send(timesheet);
});
```
# Android Mobile Application Implementation (Mobile Apps + API)
Source: https://auth0.com/docs/get-started/architecture-scenarios/mobile-api/mobile-implementation-android
The Android implementation of the API for the Mobile + API architecture scenario
This document is part of the Mobile + API Architecture Scenario and it explains how to implement the mobile application in Android. Please refer to the scenario for information on the implemented solution.
## Step 1. Set Up the Application
### Sample Project
Download a sample project specific to this tutorial to get started.
[Download](./timesheets-mobile_android.zip)
[Fork on Github](https://github.com/auth0-samples/auth0-pnp-exampleco-timesheets/tree/master/timesheets-mobile/android)
System Requirements
* Android Studio 2.3
* Android SDK 25
* Emulator - Nexus 5X - Android 6.0
Show requirements
### Set the Dependencies
For this implementation, we will use the following dependencies within the app’s `build.gradle` file:
* [Auth0.Android](https://github.com/auth0/Auth0.Android): this package enables integration with Auth0 to authenticate users.
* [OkHttp](http://square.github.io/okhttp/): this package provides an HTTP application to make requests to the Node.JS API.
* [JWTDecode.Android](https://github.com/auth0/JWTDecode.Android): this package will assist with decoding JWTs.
* AppCompat: this package lets us use the toolbar widget for navigation in our activities.
```groovy lines theme={null}
dependencies {
compile 'com.squareup.okhttp:okhttp:2.7.5'
compile 'com.auth0.android:auth0:1.10.0'
compile 'com.auth0.android:jwtdecode:1.1.1'
compile 'com.android.support:appcompat-v7:25.3.1'
testCompile 'junit:junit:4.12'
}
```
### Update the Manifest
Open the application's `AndroidManifest.xml` and add the internet permission:
```xml lines theme={null}
```
We’ll also update the application details to utilize the Toolbar widget:
```xml lines theme={null}
```
### Set Configuration Values
Set your Auth0 Client ID, Auth0 Domain, and API’s url in the `strings.xml` resource located in `/res/values/strings.xml`:
```xml lines theme={null}
ExampleCo TimesheetsLog in......http://10.0.2.2:8080/timesheets
```
For this implementation, create directories for activities, models, and utils in the application package.
* `activities/`: this package will contain the `LoginActivity.java`, `TimeSheetActivity.java`, `FormActivity.java`, and `UserActivity.java`.
* `models/`: this package will contain the `TimeSheet.java` and `User.java` data models.
* `utils/`: this package will contain the `UserProfileManager.java`, `TimeSheetAdapter.java`, and `ImageTask.java`
## Step 2. Authorize the User
### Update the Manifest
Open the app's `AndroidManifest.xml` and add the `LoginActivity`:
```xml lines theme={null}
```
### Create the Login Activity
The `LoginActivity` will handle user authorization and be the initial screen users see. We'll create a `login()` method to initialize a `WebAuthProvider` and start authentication. Ensure you provide the correct scheme, audience, and scope to the `WebAuthProvider`. For this implementation we will use:
* **scheme**: `demo`
* **audience**: `https://api.exampleco.com/timesheet`s (the Node.JS API)
* **response\_type**: `code`
* **scope**: `create:timesheets read:timesheets openid profile email offline_access`. These scopes will enable us to `POST` and `GET` to the Node.JS API, as well as retrieve the user profile and a Refresh Token.
```java lines theme={null}
private void login() {
Auth0 auth0 = new Auth0(getString(R.string.auth0_client_id), getString(R.string.auth0_domain));
auth0.setOIDCConformant(true);
WebAuthProvider.init(auth0)
.withScheme("demo")
.withAudience("https://api.exampleco.com/timesheets")
.withResponseType(ResponseType.CODE)
.withScope("create:timesheets read:timesheets openid profile email offline_access")
.start(
// ...
);
}
```
In the `login()` method, upon successful authentication we'll redirect the user to the `TimeSheetActivity`.
```java lines expandable theme={null}
package com.auth0.samples.activities;
import android.app.Activity;
import android.app.Dialog;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import com.auth0.android.Auth0;
import com.auth0.android.authentication.AuthenticationException;
import com.auth0.android.jwt.JWT;
import com.auth0.android.provider.AuthCallback;
import com.auth0.android.provider.ResponseType;
import com.auth0.android.provider.WebAuthProvider;
import com.auth0.android.result.Credentials;
import com.auth0.samples.R;
import com.auth0.samples.models.User;
import com.auth0.samples.utils.CredentialsManager;
import com.auth0.samples.utils.UserProfileManager;
public class LoginActivity extends Activity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.login_activity);
Button loginWithTokenButton = (Button) findViewById(R.id.loginButton);
loginWithTokenButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
login();
}
});
}
@Override
protected void onNewIntent(Intent intent) {
if (WebAuthProvider.resume(intent)) {
return;
}
super.onNewIntent(intent);
}
private void login() {
Auth0 auth0 = new Auth0(getString(R.string.auth0_client_id), getString(R.string.auth0_domain));
auth0.setOIDCConformant(true);
WebAuthProvider.init(auth0)
.withScheme("demo")
.withAudience("https://api.exampleco.com/timesheets")
.withResponseType(ResponseType.CODE)
.withScope("create:timesheets read:timesheets openid profile email")
.start(LoginActivity.this, new AuthCallback() {
@Override
public void onFailure(@NonNull final Dialog dialog) {
runOnUiThread(new Runnable() {
@Override
public void run() {
dialog.show();
}
});
}
@Override
public void onFailure(final AuthenticationException exception) {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(LoginActivity.this, "Error: " + exception.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
@Override
public void onSuccess(@NonNull final Credentials credentials) {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(LoginActivity.this, "Log In - Success", Toast.LENGTH_SHORT).show();
}
});
startActivity(new Intent(LoginActivity.this, TimeSheetActivity.class));
}
});
}
}
```
### Store the Credentials
To store the credentials received after login, we’ll use the `CredentialsManager` from the Auth0.Android library and [SharedPreferences](https://developer.android.com/reference/android/content/SharedPreferences.html) for storage.
Before initializing the `WebAuthProvider` in the `login()` method, we can create the `CredentialsManager`. Passing an `AuthenticationAPIClient` to the `CredentialsManager` enables it to refresh the Access Tokens if they are expired.
```java lines theme={null}
private void login() {
Auth0 auth0 = new Auth0(getString(R.string.auth0_client_id), getString(R.string.auth0_domain));
auth0.setOIDCConformant(true);
AuthenticationAPIClient authAPIClient = new AuthenticationAPIClient(auth0);
SharedPreferencesStorage sharedPrefStorage = new SharedPreferencesStorage(this);
final CredentialsManager credentialsManager = new CredentialsManager(authAPIClient, sharedPrefStorage);
WebAuthProvider.init(auth0)
// ...
}
```
Now update the `login()` method so that credentials are stored via the `CredentialsManager` after a successful authentication.
```java lines theme={null}
// ...
@Override
public void onSuccess(@NonNull final Credentials credentials) {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(LoginActivity.this, "Log In - Success", Toast.LENGTH_SHORT).show();
}
});
credentialsManager.saveCredentials(credentials);
startActivity(new Intent(LoginActivity.this, TimeSheetActivity.class));
// ...
}
```
## Step 3. Get the User Profile
### Create the User Model
Create a simple User model that will be utilized by the `UserProfileManager` and `UserActivity`.
```java lines theme={null}
package com.auth0.samples.models;
public class User {
private String email;
private String name;
private String pictureURL;
public User(String email, String name, String pictureURL) {
this.email = email;
this.name = name;
this.pictureURL = pictureURL;
}
public String getEmail() {
return email;
}
public String getName() {
return name;
}
public String getPictureURL() {
return pictureURL;
}
}
```
### Store the User Profile
To handle storing user profile information we'll create a manager class `UserProfileManager`. The `UserProfileManager` will use [SharedPreferences](https://developer.android.com/reference/android/content/SharedPreferences.html) to store data.
```java lines expandable theme={null}
package com.auth0.samples.utils;
import android.content.Context;
import android.content.SharedPreferences;
import com.auth0.android.result.UserProfile;
import com.auth0.samples.models.User;
public class UserProfileManager {
private static final String PREFERENCES_NAME = "auth0_user_profile";
private static final String EMAIL = "email";
private static final String NAME = "name";
private static final String PICTURE_URL = "picture_url";
public static void saveUserInfo(Context context, User userInfo) {
SharedPreferences sp = context.getSharedPreferences(
PREFERENCES_NAME, Context.MODE_PRIVATE);
sp.edit()
.putString(EMAIL, userInfo.getEmail())
.putString(NAME, userInfo.getName())
.putString(PICTURE_URL, userInfo.getPictureURL())
.apply();
}
public static User getUserInfo(Context context) {
SharedPreferences sp = context.getSharedPreferences(
PREFERENCES_NAME, Context.MODE_PRIVATE);
return new User(
sp.getString(EMAIL, null),
sp.getString(NAME, null),
sp.getString(PICTURE_URL, null)
);
}
public static void deleteUserInfo(Context context) {
SharedPreferences sp = context.getSharedPreferences(
PREFERENCES_NAME, Context.MODE_PRIVATE);
sp.edit()
.putString(EMAIL, null)
.putString(NAME, null)
.putString(PICTURE_URL, null)
.apply();
}
}
```
Next, update the `login()` method in the `LoginActivity` to retrieve the ID Token and get the user profile from the token with the JWTDecode.Android library. Then store the user profile with the `UserProfileManager`.
```java lines theme={null}
// ...
@Override
public void onSuccess(@NonNull final Credentials credentials) {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(LoginActivity.this, "Log In - Success", Toast.LENGTH_SHORT).show();
}
});
credentialsManager.saveCredentials(credentials);
JWT jwt = new JWT(credentials.getIdToken());
User user = new User(
jwt.getClaim("email").asString(),
jwt.getClaim("name").asString(),
jwt.getClaim("picture").asString()
);
UserProfileManager.saveUserInfo(LoginActivity.this, user);
startActivity(new Intent(LoginActivity.this, TimeSheetActivity.class));
}
// ...
```
## Step 4. Display UI Elements Conditionally Based on Scope
To determine whether a user has permissions to perform certain actions, we can look at the `scope` that was granted to the user during the authentication process. The `scope` will contain a string with all the scopes granted to a user, so to determine whether a particular scope was granted, we simply need to look whether the string of scopes contain the substring for that particular scope.
### Store the Scope
First, we can update the `User` class to store the granted scopes, and then provide a helper method, `hasScope()` which can be used to determine whether the granted scopes contain a particular scope:
```java lines expandable theme={null}
public class User {
private String email;
private String name;
private String pictureURL;
private String grantedScope;
public User(String email, String name, String pictureURL, String grantedScope) {
this.email = email;
this.name = name;
this.pictureURL = pictureURL;
this.grantedScope = grantedScope;
}
public String getEmail() {
return email;
}
public String getGrantedScope() {
return grantedScope;
}
public String getName() {
return name;
}
public String getPictureURL() {
return pictureURL;
}
public Boolean hasScope(String scope) {
return grantedScope.contains(scope);
}
}
```
Also remember to update the `UserProfileManager` to store the extra field:
```java lines expandable theme={null}
public class UserProfileManager {
private static final String PREFERENCES_NAME = "auth0_user_profile";
private static final String EMAIL = "email";
private static final String NAME = "name";
private static final String PICTURE_URL = "picture_url";
private static final String SCOPE = "scope";
public static void saveUserInfo(Context context, User userInfo) {
SharedPreferences sp = context.getSharedPreferences(
PREFERENCES_NAME, Context.MODE_PRIVATE);
sp.edit()
.putString(EMAIL, userInfo.getEmail())
.putString(NAME, userInfo.getName())
.putString(PICTURE_URL, userInfo.getPictureURL())
.putString(SCOPE, userInfo.getGrantedScope())
.apply();
}
public static User getUserInfo(Context context) {
SharedPreferences sp = context.getSharedPreferences(
PREFERENCES_NAME, Context.MODE_PRIVATE);
return new User(
sp.getString(EMAIL, null),
sp.getString(NAME, null),
sp.getString(PICTURE_URL, null),
sp.getString(SCOPE, null)
);
}
public static void deleteUserInfo(Context context) {
SharedPreferences sp = context.getSharedPreferences(
PREFERENCES_NAME, Context.MODE_PRIVATE);
sp.edit()
.putString(EMAIL, null)
.putString(NAME, null)
.putString(PICTURE_URL, null)
.putString(SCOPE, null)
.apply();
}
}
```
Next, update the `LoginActivity` to pass along the `scope` so it can be stored in the `User` object:
```java lines theme={null}
// ...
@Override
public void onSuccess(@NonNull final Credentials credentials) {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(LoginActivity.this, "Log In - Success", Toast.LENGTH_SHORT).show();
}
});
credentialsManager.saveCredentials(credentials);
JWT jwt = new JWT(credentials.getIdToken());
String scopes = credentials.getScope();
User user = new User(
jwt.getClaim("email").asString(),
jwt.getClaim("name").asString(),
jwt.getClaim("picture").asString(),
credentials.getScope()
);
UserProfileManager.saveUserInfo(LoginActivity.this, user);
startActivity(new Intent(LoginActivity.this, TimeSheetActivity.class));
}
// ...
```
### Display Approval Menu Based on Scope
Now, we can display certain UI elements based on whether the user was granted a particular scope. As an example, we have an approval menu item which should only be visible to users who have been granted the `approve:timesheets` scope.
Below you can see the code from the `BaseActivity` class which checks whether a user has the `approve:timesheets` scope, and based on that will set the visibility of the menu item which displays the approval activity:
```java lines theme={null}
// ...
@Override
public boolean onCreateOptionsMenu(Menu menu) {
Boolean canApprove = UserProfileManager.getUserInfo(this).hasScope("approve:timesheets");
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.actions, menu);
MenuItem item = menu.findItem(R.id.action_approve);
item.setVisible(canApprove);
return super.onCreateOptionsMenu(menu);
}
// ...
```
## Step 5. Call the API
### Update the Manifest
Open the app's `AndroidManifest.xml` and add the `TimeSheetActivity`:
```xml wrap lines theme={null}
```
### Create the Timesheets Activity Layouts
Next create `timesheet_activity.xml`, the layout for the `TimeSheetsActivity`:
```xml lines theme={null}
```
The `ListView` widget will contain individual entries which are represented by the `item_entry.xml` layout:
```xml lines expandable theme={null}
```
And for the Toolbar navigation on the `TimeSheetActivity`, we’ll create the `timesheet_action_menu.xml` menu resource (`/res/menu/`):
```xml lines theme={null}
```
### Create the Timesheet Model
Create a model for working with timesheet data in our views:
```java lines expandable theme={null}
package com.auth0.samples.models;
import java.util.Date;
/**
* Created by ej on 7/9/17.
*/
public class TimeSheet {
private String userID;
private String projectName;
private String date;
private double hours;
private int ID;
public TimeSheet(String gUserID, String gProjectName, String gDate, double gHours, int gID) {
this.userID = gUserID;
this.projectName = gProjectName;
this.date = gDate;
this.hours = gHours;
this.ID = gID;
}
public String getUserID() {
return userID;
}
public String getProjectName() {
return projectName;
}
public String getDateString() {
return date;
}
public double getHours() {
return hours;
}
public int getID() {
return ID;
}
}
```
### Create the Timesheet Adapter
The `TimeSheetAdapter` is a utility class which will take an array of timesheet entries and apply them to the `ListView` on the `TimeSheetActivity`.
```java lines expandable theme={null}
package com.auth0.samples.utils;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
import com.auth0.samples.R;
import com.auth0.samples.models.TimeSheet;
import java.util.ArrayList;
public class TimeSheetAdapter extends ArrayAdapter {
public TimeSheetAdapter(Context context, ArrayList timesheets) {
super(context, 0, timesheets);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
TimeSheet timesheet = getItem(position);
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.item_entry, parent, false);
}
TextView tvUserID = (TextView) convertView.findViewById(R.id.tvUserID);
TextView tvDate = (TextView) convertView.findViewById(R.id.tvDate);
TextView tvProjectName = (TextView) convertView.findViewById(R.id.tvProjectName);
TextView tvHours = (TextView) convertView.findViewById(R.id.tvHours);
tvUserID.setText(timesheet.getUserID());
tvDate.setText(timesheet.getDateString());
tvProjectName.setText(timesheet.getProjectName());
tvHours.setText(Double.toString(timesheet.getHours()));
return convertView;
}
}
```
### Create the Timesheet Activity
The `TimeSheetActivity` displays the timesheet entries for the logged in user which are stored on the server.
* The `@string/api_url` is set to `http://10.0.2.2:8080/timesheets` so the Android Emulator can connect to the Node.JS API running on `http://localhost:8080`.
* The `callAPI()` method retrieves timesheets from the Node.JS API.
* The `processResults()` method takes the JSON response from `callAPI()` and converts it `TimeSheet` objects.
* The `onCreateOptionsMenu(`) and `onOptionsItemSelected(`) methods handle the Toolbar widget navigation functionality.
```java lines expandable theme={null}
package com.auth0.samples.activities;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.ListView;
import android.widget.Toast;
import com.auth0.android.Auth0;
import com.auth0.android.authentication.AuthenticationAPIClient;
import com.auth0.android.authentication.storage.CredentialsManager;
import com.auth0.android.authentication.storage.CredentialsManagerException;
import com.auth0.android.authentication.storage.SharedPreferencesStorage;
import com.auth0.android.callback.BaseCallback;
import com.auth0.android.result.Credentials;
import com.auth0.samples.R;
import com.auth0.samples.utils.TimeSheetAdapter;
import com.auth0.samples.models.TimeSheet;
import com.squareup.okhttp.Callback;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.Response;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import java.util.ArrayList;
public class TimeSheetActivity extends AppCompatActivity {
private ArrayList timesheets = new ArrayList<>();
private String accessToken;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.timesheet_activity);
Toolbar navToolbar = (Toolbar) findViewById(R.id.navToolbar);
setSupportActionBar(navToolbar);
Auth0 auth0 = new Auth0(getString(R.string.auth0_client_id), getString(R.string.auth0_domain));
auth0.setOIDCConformant(true);
AuthenticationAPIClient authAPIClient = new AuthenticationAPIClient(auth0);
SharedPreferencesStorage sharedPrefStorage = new SharedPreferencesStorage(this);
CredentialsManager credentialsManager = new CredentialsManager(authAPIClient, sharedPrefStorage);
credentialsManager.getCredentials(new BaseCallback() {
@Override
public void onSuccess(Credentials payload) {
accessToken = payload.getAccessToken();
callAPI();
}
@Override
public void onFailure(CredentialsManagerException error) {
Toast.makeText(TimeSheetActivity.this, "Error: " + error.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
private void callAPI() {
final Request.Builder reqBuilder = new Request.Builder()
.get()
.url(getString(R.string.api_url))
.addHeader("Authorization", "Bearer " + accessToken);
OkHttpClient client = new OkHttpClient();
Request request = reqBuilder.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Request request, IOException e) {
Log.e("API", "Error: ", e);
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(TimeSheetActivity.this, "An error occurred", Toast.LENGTH_SHORT).show();
}
});
}
@Override
public void onResponse(final Response response) throws IOException {
timesheets = processResults(response);
final TimeSheetAdapter adapter = new TimeSheetAdapter(TimeSheetActivity.this, timesheets);
runOnUiThread(new Runnable() {
@Override
public void run() {
if (response.isSuccessful()) {
ListView listView = (ListView) findViewById(R.id.timesheetList);
listView.setAdapter(adapter);
adapter.addAll(timesheets);
} else {
Toast.makeText(TimeSheetActivity.this, "API call failed.", Toast.LENGTH_SHORT).show();
}
}
});
}
});
}
private ArrayList processResults (Response response) {
ArrayList timesheets = new ArrayList<>();
try {
String jsonData = response.body().string();
if (response.isSuccessful()) {
JSONArray timesheetJSONArray = new JSONArray(jsonData);
for (int i = 0; i < timesheetJSONArray.length(); i++) {
JSONObject timesheetJSON = timesheetJSONArray.getJSONObject(i);
String userID = timesheetJSON.getString("user_id");
String projectName = timesheetJSON.getString("project");
String dateStr = timesheetJSON.getString("date");
Double hours = timesheetJSON.getDouble("hours");
int id = timesheetJSON.getInt("id");
TimeSheet timesheet = new TimeSheet(userID, projectName, dateStr, hours, id);
timesheets.add(timesheet);
}
}
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
return timesheets;
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.timesheet_action_menu, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_new:
startActivity(new Intent(TimeSheetActivity.this, FormActivity.class));
break;
case R.id.action_profile:
startActivity(new Intent(TimeSheetActivity.this, UserActivity.class));
break;
default:
return super.onOptionsItemSelected(item);
}
return true;
}
}
```
## Step 6. View the User Profile
To display the logged in user’s profile we’ll create the `UserActivity`, a corresponding `user_activity.xml` layout, and the `user_action_menu.xml` for the Toolbar navigation. The view will display the user’s name, email, and profile picture.
### Update the Manifest
Open the app's `AndroidManifest.xml` and add the `UserActivity`:
```xml wrap lines theme={null}
```
#### Create the User Activity Layouts
Next create `user_activity.xml`, the layout for the `UserActivity`, with an `ImageView` for the profile picture and `TextViews` for the user's name and email.
```xml lines expandable theme={null}
```
And create the `user_actions_menu.xml` for the `UserActivity` Toolbar:
```xml lines theme={null}
```
### Load the Profile Picture from URL
In order to load the user profile picture from the URL, create a task which extends `AsyncTask` and executes in the background.
```java lines expandable theme={null}
package com.auth0.samples.utils;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.util.Log;
import android.widget.ImageView;
import java.io.InputStream;
import java.net.URL;
public class ImageTask extends AsyncTask {
private ImageView bmImage;
public ImageTask(ImageView bmImage) {
this.bmImage = bmImage;
}
protected Bitmap doInBackground(String... urls) {
String urldisplay = urls[0];
Bitmap mIcon11 = null;
try {
InputStream in = new URL(urldisplay).openStream();
mIcon11 = BitmapFactory.decodeStream(in);
} catch (Exception e) {
Log.e("Error", e.getMessage());
e.printStackTrace();
}
return mIcon11;
}
protected void onPostExecute(Bitmap result) {
bmImage.setImageBitmap(result);
}
}
```
### Create the User Activity
In the `onCreate()` method we'll retrieve the user information from the `UserProfileManager` and set the values in the view. As before, the `onCreateOptionsMenu()` and `onOptionsItemSelected()` methods handle the Toolbar widget navigation functionality.
```java lines expandable theme={null}
package com.auth0.samples.activities;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.ImageView;
import android.widget.TextView;
import com.auth0.samples.R;
import com.auth0.samples.utils.ImageTask;
import com.auth0.samples.utils.UserProfileManager;
public class UserActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.user_activity);
Toolbar navToolbar = (Toolbar) findViewById(R.id.navToolbar);
setSupportActionBar(navToolbar);
TextView tvName = (TextView) findViewById(R.id.tvName);
TextView tvEmail = (TextView) findViewById(R.id.tvEmail);
tvName.setText(UserProfileManager.getUserInfo(this).getName());
tvEmail.setText(UserProfileManager.getUserInfo(this).getEmail());
new ImageTask((ImageView) findViewById(R.id.ivPicture))
.execute(UserProfileManager.getUserInfo(this).getPictureURL());
UserProfileManager.getUserInfo(this).getName();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu items for use in the action bar
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.user_action_menu, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_new:
startActivity(new Intent(UserActivity.this, FormActivity.class));
break;
case R.id.action_view:
startActivity(new Intent(UserActivity.this, TimeSheetActivity.class));
break;
default:
// If we got here, the user's action was not recognized.
// Invoke the superclass to handle it.
return super.onOptionsItemSelected(item);
}
return true;
}
}
```
## Step 7. Form for New Timesheets
Next create the `FormActivity` and layout to handle creating new timesheet entries.
### Update the Manifest
Open the app's `AndroidManifest.xml` and add the `FormActivity`:
```xml wrap lines theme={null}
```
### Create the Form Activity Layouts
Create the `form_activity.xml` layout with `EditText` for the project name and hours worked inputs, and a `DatePicker` for the day worked.
```xml lines expandable theme={null}
```
And create the `form_actions_menu.xml` for the `FormActivity` Toolbar:
```xml lines theme={null}
```
### Create the Form Activity
* The `@string/api_url` is set to `http://10.0.2.2:8080/timesheets` so the Android Emulator can connect to the Node.JS API running on `http://localhost:8080`.
* The `onCreate()` method initializes the form and collects the input for the `postAPI()` method when the submit button is pressed.
* The `postAPI()` method will send the user input retrieved from the form to the Node.JS API in JSON format.
* The `clearForm()` method clears the input forms.
* The `onCreateOptionsMenu()` and `onOptionsItemSelected()` methods handle the Toolbar widget navigation functionality.
```java lines expandable theme={null}
package com.auth0.samples.activities;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.DatePicker;
import android.widget.EditText;
import android.widget.Toast;
import com.auth0.android.Auth0;
import com.auth0.android.authentication.AuthenticationAPIClient;
import com.auth0.android.authentication.storage.CredentialsManager;
import com.auth0.android.authentication.storage.CredentialsManagerException;
import com.auth0.android.authentication.storage.SharedPreferencesStorage;
import com.auth0.android.callback.BaseCallback;
import com.auth0.android.result.Credentials;
import com.auth0.samples.R;
import com.squareup.okhttp.Callback;
import com.squareup.okhttp.MediaType;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.RequestBody;
import com.squareup.okhttp.Response;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import java.util.Calendar;
import java.util.Date;
public class FormActivity extends AppCompatActivity {
private static final MediaType MEDIA_TYPE_JSON = MediaType.parse("application/json; charset=utf-8");
private String accessToken;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.form_activity);
Toolbar navToolbar = (Toolbar) findViewById(R.id.navToolbar);
setSupportActionBar(navToolbar);
Auth0 auth0 = new Auth0(getString(R.string.auth0_client_id), getString(R.string.auth0_domain));
auth0.setOIDCConformant(true);
AuthenticationAPIClient authAPIClient = new AuthenticationAPIClient(auth0);
SharedPreferencesStorage sharedPrefStorage = new SharedPreferencesStorage(this);
CredentialsManager credentialsManager = new CredentialsManager(authAPIClient, sharedPrefStorage);
credentialsManager.getCredentials(new BaseCallback() {
@Override
public void onSuccess(Credentials payload) {
accessToken = payload.getAccessToken();
}
@Override
public void onFailure(CredentialsManagerException error) {
Toast.makeText(FormActivity.this, "Error: " + error.getMessage(), Toast.LENGTH_SHORT).show();
}
});
Button submitTimeSheetButton = (Button) findViewById(R.id.submitTimeSheetButton);
final EditText editProjectName = (EditText) findViewById(R.id.editProjectName);
final EditText editHours = (EditText) findViewById(R.id.editHours);
final DatePicker datePicker = (DatePicker) findViewById(R.id.datePicker);
submitTimeSheetButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
int day = datePicker.getDayOfMonth();
int month = datePicker.getMonth();
int year = datePicker.getYear();
Calendar calendar = Calendar.getInstance();
calendar.set(year, month, day);
postAPI(
editProjectName.getText().toString(),
calendar.getTime(),
editHours.getText().toString()
);
}
});
}
private void postAPI(String projectName, Date date, String hours) {
JSONObject postBody = new JSONObject();
try {
postBody.put("project", projectName);
} catch (JSONException e) {
e.printStackTrace();
}
try {
postBody.put("date", date);
} catch (JSONException e) {
e.printStackTrace();
}
try {
postBody.put("hours", hours);
} catch (JSONException e) {
e.printStackTrace();
}
String postStr = postBody.toString();
final Request.Builder reqBuilder = new Request.Builder()
.post(RequestBody.create(MEDIA_TYPE_JSON, postStr))
.url(getString(R.string.api_url))
.addHeader("Authorization", "Bearer " + accessToken);
OkHttpClient client = new OkHttpClient();
Request request = reqBuilder.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Request request, IOException e) {
Log.e("API", "Error: ", e);
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(FormActivity.this, "An error occurred", Toast.LENGTH_SHORT).show();
}
});
}
@Override
public void onResponse(final Response response) throws IOException {
final String resBody = response.body().string();
runOnUiThread(new Runnable() {
@Override
public void run() {
if (response.isSuccessful()) {
clearForm((ViewGroup) findViewById(R.id.mainForm));
Intent intent = new Intent(FormActivity.this, TimeSheetActivity.class);
FormActivity.this.startActivity(intent);
} else {
Toast.makeText(FormActivity.this, "Timesheet creation failed.", Toast.LENGTH_SHORT).show();
}
}
});
}
});
}
private void clearForm(ViewGroup group) {
for (int i = 0, count = group.getChildCount(); i < count; ++i) {
View view = group.getChildAt(i);
if (view instanceof EditText) {
((EditText)view).setText("");
}
if(view instanceof ViewGroup && (((ViewGroup)view).getChildCount() > 0))
clearForm((ViewGroup)view);
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.form_action_menu, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_view:
startActivity(new Intent(FormActivity.this, TimeSheetActivity.class));
break;
case R.id.action_profile:
startActivity(new Intent(FormActivity.this, UserActivity.class));
break;
default:
return super.onOptionsItemSelected(item);
}
return true;
}
}
```
## Test the App
Before continuing, ensure you have [implemented the Node.JS API](/docs/get-started/architecture-scenarios/mobile-api/api-implementation-nodejs).
1. Start the API by navigating to the API's directory in your terminal and entering the `node server` command.
2. Open the mobile app in Android Studio and press the **Run** button.
3. Select the Nexus 5X API 23 virtual device.
4. Once the emulator has loaded the mobile app, you can login user then, create and view timesheet entries from the running Node.JS API.
That's it! You are done!
# Solution Overview (Mobile Apps + API)
Source: https://auth0.com/docs/get-started/architecture-scenarios/mobile-api/part-1
Solutions Overview for the Mobile + API architecture scenario
In order to ensure that only authorized users and applications are allowed access to the Timesheets API, ExampleCo has decided to make use of the [OAuth 2.0 authorization framework](https://tools.ietf.org/html/rfc6749). The framework provides the flexibility the company wants since the different grants can allow them to easily authorize the various types of applications which need to communicate with the Timesheets API.
## API Authentication and Authorization
An API is a way to expose functionality of your application to other applications. An application can make a request by sending a message to an endpoint on an API and receive information as a response.
An API endpoint can be secured or not. In our case, since the timesheets are sensitive information that affect reviews and payments, it is important to ensure that only authorized users and applications can call the endpoints on our API. When a client application wants to access protected endpoints on an API, it needs to present an Access Token as proof that it has the required permissions for making the call to the endpoint.
An Access Token is obtained by authenticating the user with an Authorization Server and the user can then, in turn, authorize the application to access the API on their behalf.
An Access Token (also referred to as `access_token`) is an opaque string representing an authorization issued to the application. It may denote an identifier used to retrieve the authorization information or may self-contain the authorization information (for example, the user's identity, permissions, and so forth) in a verifiable manner.
It is quite common for Access Tokens to be implemented as [JSON Web Tokens](/docs/secure/tokens/json-web-tokens).
For more information on Auth0 Access Tokens refer to [Access Token](/docs/secure/tokens/access-tokens).
An API can enforce fine-grained control over who can access the various endpoints exposed by the API. These permissions are expressed as scopes.
When a user authorizes a client application, the application can also indicate which permissions it requires. The user is then allowed to review and grant these permissions. These permissions are then included in the Access Token as part of the `scope` claim.
Subsequently, when the client passes along the Access Token when making requests to the API, the API can inspect the `scope` claim to ensure that the required permissions were granted in order to call the particular API endpoint.
Each Access Token may include a list of the permissions that have been granted to the client. When a client authenticates with Auth0, it will specify the list of scopes (or permissions) it is requesting. If those scopes are authorized, then the Access Token will contain a list of authorized scopes.
For example, the timesheet API may accept four different levels of authorization: reading timesheets (scope `read:timesheets`), creating timesheets (scope `create:timesheets`), deleting timesheets (scope `delete:timesheets`) and approving timesheets (scope `approve:timesheets`).
When a client asks the API to create a new timesheet entry, then the Access Token should contain the `create:timesheets` scope. In a similar fashion, in order to delete existing timesheets, the Access Token should contain the `delete:timesheets` scope.
For more information on scopes refer to [Scopes](/docs/get-started/apis/scopes).
By using the OAuth 2.0 authorization framework, you can give your own applications or third-party applications limited access to your APIs on behalf of the application itself. Using Auth0, you can easily support different flows in your own APIs without worrying about the OAuth 2.0/OpenID Connect (OIDC) specification, or the many other technical aspects of API authorization.
In any OAuth 2.0 flow we can identify the following roles:
* **Resource Owner**: the entity that can grant access to a protected resource. Typically this is the end-user.
* **Resource Server**: the server hosting the protected resources. This is the API you want to access.
* **Client**: an application requesting access to a protected resource on behalf of the Resource Owner.
* **Authorization Server**: the server that authenticates the Resource Owner, and issues Access Tokens after getting proper authorization. In this case, Auth0's Authentication API.
[Grants types (or flows)](/docs/get-started/authentication-and-authorization-flow/which-oauth-2-0-flow-should-i-use) determine how these participants interact to grant to the applications limited access to the APIs you are building. As a result, the app will obtain an access token that can be used to call the API on behalf of the user.
## Proof Key for Code Exchange (PKCE)
OAuth 2 provides several grant types for different use cases. In this particular use case, we want to access the API from a mobile application, which will use the [Authorization Code Flow with Proof Key for Code Exchange (PKCE)](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow-with-pkce) to do so.
The [Authorization Code Flow](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow) has some security issues when implemented on native applications. For instance, a malicious attacker can intercept the `authorization_code` returned by Auth0 and exchange it for an [Access Token](/docs/secure/tokens/access-tokens) (and possibly a [Refresh Token](/docs/secure/tokens/refresh-tokens)).
The Proof Key for Code Exchange (PKCE) (defined in [RFC 7636](https://tools.ietf.org/html/rfc7636)) is a technique used to mitigate this authorization code interception attack.
With PKCE, the Application creates, for every authorization request, a cryptographically random key called `code_verifier` and its transformed value called `code_challenge`, which is sent to Auth0 to get the `authorization_code`. When the Application receives the `authorization_code`, it will send the code and the `code_verifier` to Auth0's token endpoint to exchange them for the requested tokens.
1. The native app initiates the flow and redirects the user to Auth0 (specifically to the [/authorize endpoint](https://auth0.com/docs/api/authentication#authorization-code-grant-pkce-)), sending the `code_challenge` and `code_challenge_method` parameters.
2. Auth0 redirects the user to the native app with an `authorization_code` in the query string.
3. The native app sends the `authorization_code` and `code_verifier` together with the `redirect_uri` and the `client_id` to Auth0. This is done using the [/oauth/token endpoint](https://auth0.com/docs/api/authentication?http#authorization-code-pkce-).
4. Auth0 validates this information and returns an Access Token (and optionally a Refresh Token).
5. The native app can use the Access Token to call the API on behalf of the user.
If you have [Refresh Token Rotation](/docs/secure/tokens/refresh-tokens/refresh-token-rotation) enabled, a new Refresh Token is generated with each request and issued along with the Access Token. When a Refresh Token is exchanged, the previous Refresh Token is invalidated but information about the relationship is retained by the authorization server.
## Authorization Extension
The [Auth0 Authorization Extension](/docs/customize/extensions/authorization-extension) allows you to provide authorization support in your application, by assigning Roles, Groups and Permissions to Users.
The Authorization Extension creates a [Rule](/docs/customize/rules) which will augment the User profile during the authentication flow with the Roles, Groups and Permissions assigned to the user. You can then use this information to ensure that the Access Token issued to a user only contains scopes which are allowed according to the permissions defined in the Authorization Extension.
PREVIOUS TUTORIAL [Introduction](/docs/get-started/architecture-scenarios/mobile-api)
NEXT TUTORIAL [2. Auth0 Configuration](/docs/get-started/architecture-scenarios/mobile-api/part-2)
# Auth0 Configuration (Mobile Apps + API)
Source: https://auth0.com/docs/get-started/architecture-scenarios/mobile-api/part-2
Auth0 Configuration for the Mobile + API architecture scenario
In this section we will review all the configurations we need to apply at the [Auth0 Dashboard](https://manage.auth0.com/#).
## Create the API
Click on the [APIs menu option](https://manage.auth0.com/#/apis) on the left, and click the Create API button.
You will be required to supply the following details for your API:
* **Name**: a friendly name for the API. Does not affect any functionality.
* **Identifier**: a unique identifier for the API. We recommend using a URL but note that this doesn't have to be a publicly available URL, Auth0 will not call your API at all. This value cannot be modified afterwards.
* **Signing Algorithm**: the algorithm to sign the tokens with. The available values are `HS256` and `RS256`. When selecting RS256 the token will be signed with the tenant's private key. To learn more about signing algorithms, see [Signing Algorithms](/docs/get-started/applications/signing-algorithms).
Fill in the required information and click the **Create** button.
#### Signing Algorithms
When you create an API you have to select the algorithm your tokens will be signed with. The signature is used to verify that the sender of the JWT is who it says it is and to ensure that the message wasn't changed along the way.
The signature is part of a JWT. If you are unfamiliar with JWT structure, please see [JSON Web Token Structure](/docs/secure/tokens/json-web-tokens/json-web-token-structure).
To create the signature part you have to take the encoded header, the encoded payload, a secret, the algorithm specified in the header, and sign that. That algorithm, which is part of the JWT header, is the one you select for your API: `HS256` or `RS256`.
* **RS256** is an [asymmetric algorithm](https://en.wikipedia.org/wiki/Public-key_cryptography) which means that there are two keys: one public and one private (secret). Auth0 has the secret key, which is used to generate the signature, and the consumer of the JWT has the public key, which is used to validate the signature.
* **HS256** is a [symmetric algorithm](https://en.wikipedia.org/wiki/Symmetric-key_algorithm) which means that there is only one secret key, shared between the two parties. The same key is used both to generate the signature and to validate it. Special care should be taken in order for the key to remain confidential.
The most secure practice, and our recommendation, is to use **RS256**. Some of the reasons are:
* With RS256 you are sure that only the holder of the private key (Auth0) can sign tokens, while anyone can check if the token is valid using the public key.
* Under HS256, If the private key is compromised you would have to re-deploy the API with the new secret. With RS256 you can request a token that is valid for multiple audiences.
* With RS256 you can implement key rotation without having to re-deploy the API with the new secret.
For a more detailed overview of the JWT signing algorithms refer to: [JSON Web Token (JWT) Signing Algorithms Overview](https://auth0.com/blog/json-web-token-signing-algorithms-overview/).
### Configure the Permissions
Once the application has been created you will need to configure the Permissions which applications can request during authorization.
In the settings for your API, go to the **Permissions** tab. In this section you can add all four of the scopes which were discussed before, namely `read:timesheets`, `create:timesheets`, `delete:timesheets`, `approve:timesheets`.
## Create the Application
There are four application types in Auth0: **Native App** (used by mobile or desktop apps), **Single-Page Web App**, **Regular Web App**, and **Machine to Machine App** (used by CLIs, Daemons, or services running on your backend). For this scenario we want to create a new Application for our mobile application, hence we will use Native as the application type.
To create a new Application, navigate to the [dashboard](https://manage.auth0.com/#) and click on the [Applications](https://manage.auth0.com/#/applications) menu option on the left. Click the **+ Create Application** button.
Set a name for your Application (we will use `Timesheets Mobile`) and select `Native App` as the type.
Click **Create**.
## Configure the Authorization Extension
You will need to ensure that the Authorization Extension is installed for your tenant. You can refer to the [Authorization Extension documentation](/docs/customize/extensions/authorization-extension) for details on how to do this.
### Define Permissions
You will need to define Permissions which correlates with the scopes you have already defined. In the Authorization Extension, click the Permissions tab, and then click on the **Create Permission** button. In the dialog, capture the details for each permission. Ensure that the name of the permission is exactly the same as the corresponding scope:
Proceed to create the permissions for all the remaining scopes:
### Define Roles
Head over to the Roles tab and create two Roles. Click the **Create Role** button and select the **Timesheets SPA** application. Give the Role a name and description of Employee, and select the `delete:timesheets`, `create:timesheets` and `read:timesheets` permissions. Click on **Save**.
Next, follow the same process to create a **Manager** role, and ensure that you have selected all the permissions:
### Assign Users to Roles
You will need to assign all users to either the Manager or the User role. You can do this by going to the Users tab in the Authorization Extension and selecting a user. On the user information screen, go to the Roles tab. You can add a role to the user by clicking the **Add Role to User** button, and selecting the appropriate role for the user.
### Configuring the Authorization Extension
You will also need to ensure that the Rule for the Authorization Extension is published. You can do this by clicking on your user avatar in to top right of the Authorization Extension, and selecting the **Configuration** option:
Ensure that you have enabled **Permissions** and then click the **Publish Rule** button.
### Create a Rule to validate token scopes
The final step in this process is to create a Rule which will validate that the scopes contained in an Access Token is valid based on the permissions assigned to the user. Any scopes which are not valid for a user should be removed from the Access Token.
In your Auth0 Dashboard, go to the Rules tab. You should see the Rule created by the Authorization Extension.
Click on the **Create Rule** button and select the **Empty Rule** template. You can give the Rule a name, such as **Access Token Scopes**, and then specify the following code for the Rule:
```javascript lines theme={null}
function (user, context, callback) {
if (context.clientName !== 'Timesheets SPA') {
return callback(null, user, context);
}
var permissions = user.permissions || [];
var requestedScopes = context.request.body.scope || context.request.query.scope;
var filteredScopes = requestedScopes.split(' ').filter( function(x) {
return x.indexOf(':') < 0;
});
Array.prototype.push.apply(filteredScopes, permissions);
context.accessToken.scope = filteredScopes.join(' ');
callback(null, user, context);
}
```
The code above will ensure that all Access Tokens will only contain the properly-formatted scopes (e.g., `action:area` or `delete:timesheets`) which are valid according to a user's permissions. Once you are done you can click on the **Save** button.
Rules execute in the order they are displayed on the Rules page, so ensure that the new rule you created is positioned below the rule for the Authorization Extension, so it executes after the Authorization Extension rule.
PREVIOUS TUTORIAL [1. Solution Overview](/docs/get-started/architecture-scenarios/mobile-api/part-1)
NEXT TUTORIAL [3. API + Mobile Implementation](/docs/get-started/architecture-scenarios/mobile-api/api-implementation-nodejs)
# API and Mobile Configuration (Mobile Apps + API)
Source: https://auth0.com/docs/get-started/architecture-scenarios/mobile-api/part-3
API and Mobile Configuration for the Mobile + API architecture scenario
In this section we will see how we can implement an API for our scenario.
For simplicity, we will keep our implementation solely focused on authentication and authorization. As you will see in the samples, the input timesheet entry will be hard-coded, and the API will not persist the timesheet entry. Instead, it will simply echo back some of the info.
## Define the API endpoints
First we need to define the endpoints of our API.
An **API endpoint** is a unique URL that represents an object. To interact with this object, you need to point your application to its URL. For example, if you had an API that could return either orders or customers, you might configure two endpoints: `/orders` and `/customers`. Your application would interact with these endpoints using different HTTP methods; for example, `POST /orders` could create a new order or `GET /orders` could retrieve the dataset of one or more orders.
For this implementation we will only define two endpoints; one for retrieving a list of all timesheets for an employee, and another which will allow an employee to create a new timesheet entry.
An `HTTP GET` request to the `/timesheets` endpoint will allow a user to retrieve their timesheets, and an `HTTP POST` request to the `/timesheets` endpoint will allow a user to add a new timesheet.
See the implementation in [Node.js](/docs/get-started/architecture-scenarios/mobile-api/api-implementation-nodejs#1-define-the-api-endpoints)
### Secure the Endpoints
When an API receives a request with a bearer Access Token as part of the header, the first thing to do is to validate the token. This consists of a series of steps, and if any of these fails then the request must be rejected with a `Missing or invalid token` error message to the calling app.
The validations that the API should perform are:
* Check that the JWT is well formed
* Check the signature
* Validate the standard claims
[JWT.io](https://jwt.io/) provides a list of libraries that can do most of the work for you: parse the JWT, verify the signature and the claims.
Part of the validation process is to also check the Client permissions (scopes), but we will address this separately in the next paragraph of this document.
For more information on validating Access Tokens, see [Validate Access Tokens](/docs/secure/tokens/access-tokens/validate-access-tokens).
See the implementation in [Node.js](/docs/get-started/architecture-scenarios/mobile-api/api-implementation-nodejs#2-secure-the-api-endpoints)
### Check the Client's Permissions
By now we have verified that the JWT is valid. The last step is to verify that the client has the permissions required to access the protected resources.
To do so, the API needs to check the [scopes](/docs/get-started/apis/scopes) of the decoded JWT. This claim is part of the payload and it is a space-separated list of strings.
See the implementation in [Node.js](/docs/get-started/architecture-scenarios/mobile-api/api-implementation-nodejs#3-check-the-client-permissions)
### Determine user identity
For both endpoints (retrieving the list of timesheets, and adding a new timesheet) we will need to determine the identity of the user.
For retrieving the list of timesheets this is to ensure that we only return the timesheets belonging to the user making the request, and for adding a new timesheet this is to ensure that the timesheet is associated with the user making the request.
One of the standard JWT claims is the `sub` claim which identifies the principal that is the subject to the claim. In the case of the Implicit Grant flow this claim will contain the user's identity, which will be the unique identifier for the Auth0 user. You can use this to associate any information in external systems with a particular user.
You can also use a custom claim to add another attribute of the user - such as their email address - to the Access Token and use that to uniquely identify the user.
See the implementation in [Node.js](/docs/get-started/architecture-scenarios/mobile-api/api-implementation-nodejs#4-determine-the-user-identity)
## Implement the Mobile App
In this section we will see how we can implement a mobile application for our scenario.
[See the implementation in Android.](/docs/get-started/architecture-scenarios/mobile-api/mobile-implementation-android#1-set-up-the-application)
### Authorize the User
To authorize the user we will implement the [Authorization Code Flow with Proof Key for Code Exchange (PKCE)](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow-with-pkce/call-your-api-using-the-authorization-code-flow-with-pkce). The mobile application should first send the user to the [authorization URL](https://auth0.com/docs/api/authentication#authorization-code-grant-pkce-) along with the `code_challenge` and the method used to generate it:
The `GET` request to the authorization URL should include the following values:
| Parameter | Description |
| - | - |
| **client\_id** | The value of your Auth0 Client Id. You can retrieve it from the Settings of your Application at the [Auth0 Dashboard](https://manage.auth0.com/#/applications). |
| **audience** | The value of your API Identifier. You can retrieve it from the Settings of your API at the [Auth0 Dashboard](https://manage.auth0.com/#/apis). |
| **scope** | The [scopes](/docs/get-started/apis/scopes) which determine the claims to be returned in the ID Token and Access Token. For example, a scope of `openid` will return an ID Token in the response. In our example mobile app, we use the following scopes: `create:timesheets read:timesheets openid profile email offline_access`. These scopes allow the mobile app to call the API, obtain a [Refresh Token](/docs/glossary?term=Refresh+Token), and return the user's `name`, `picture`, and `email` claims in the ID Token. |
| **response\_type** | Indicates the Authentication Flow to use. For a mobile application using PKCE, this should be set to `code`. |
| **code\_challenge** | The generated code challenge from the code verifier. You can find instructions on generating a code challenge [here](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow-with-pkce/call-your-api-using-the-authorization-code-flow-with-pkce#authorize-the-user%23create-a-code-verifier). |
| **code\_challenge\_method** | Method used to generate the challenge. Auth0 supports only `S256`. |
| **redirect\_uri** | The URL which Auth0 will redirect the browser to after authorization has been granted by the user. The Authorization Code will be available in the code URL parameter. This URL must be specified as a valid callback URL under your [Application's Settings](https://manage.auth0.com/#/applications). |
[See the implementation in Android.](/docs/get-started/architecture-scenarios/mobile-api/mobile-implementation-android#2-authorize-the-user)
### Get the Credentials
After a successful request to the authorization URL, you should receive the following response:
Next you can exchange the `authorization_code` from the response for an Access Token that can be used to call your API. Perform a `POST` request to the [Token URL](https://auth0.com/docs/api/authentication#authorization-code-pkce-) including the following data:
```bash cURL theme={null}
curl --request POST \
--url 'https://{yourDomain}/oauth/token' \
--header 'content-type: application/x-www-form-urlencoded' \
--data grant_type=authorization_code \
--data 'client_id={yourClientId}' \
--data code_verified=YOUR_GENERATED_CODE_VERIFIER \
--data code=YOUR_AUTHORIZATION_CODE \
--data 'redirect_uri=https://{https://yourApp/callback}'
```
```csharp C# theme={null}
var client = new RestClient("https://{yourDomain}/oauth/token");
var request = new RestRequest(Method.POST);
request.AddHeader("content-type", "application/x-www-form-urlencoded");
request.AddParameter("application/x-www-form-urlencoded", "grant_type=authorization_code&client_id={yourClientId}&code_verified=YOUR_GENERATED_CODE_VERIFIER&code=YOUR_AUTHORIZATION_CODE&redirect_uri=https%3A%2F%2F{https://yourApp/callback}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```
```go Go theme={null}
package main
import (
"fmt"
"strings"
"net/http"
"io/ioutil"
)
func main() {
url := "https://{yourDomain}/oauth/token"
payload := strings.NewReader("grant_type=authorization_code&client_id={yourClientId}&code_verified=YOUR_GENERATED_CODE_VERIFIER&code=YOUR_AUTHORIZATION_CODE&redirect_uri=https%3A%2F%2F{https://yourApp/callback}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("content-type", "application/x-www-form-urlencoded")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := ioutil.ReadAll(res.Body)
fmt.Println(res)
fmt.Println(string(body))
}
```
```java Java theme={null}
HttpResponse response = Unirest.post("https://{yourDomain}/oauth/token")
.header("content-type", "application/x-www-form-urlencoded")
.body("grant_type=authorization_code&client_id={yourClientId}&code_verified=YOUR_GENERATED_CODE_VERIFIER&code=YOUR_AUTHORIZATION_CODE&redirect_uri=https%3A%2F%2F{https://yourApp/callback}")
.asString();
```
```javascript Node.JS theme={null}
var axios = require("axios").default;
var options = {
method: 'POST',
url: 'https://{yourDomain}/oauth/token',
headers: {'content-type': 'application/x-www-form-urlencoded'},
data: new URLSearchParams({
grant_type: 'authorization_code',
client_id: '{yourClientId}',
code_verified: 'YOUR_GENERATED_CODE_VERIFIER',
code: 'YOUR_AUTHORIZATION_CODE',
redirect_uri: 'https://{https://yourApp/callback}'
})
};
axios.request(options).then(function (response) {
console.log(response.data);
}).catch(function (error) {
console.error(error);
});
```
```php PHP theme={null}
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://{yourDomain}/oauth/token",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "grant_type=authorization_code&client_id={yourClientId}&code_verified=YOUR_GENERATED_CODE_VERIFIER&code=YOUR_AUTHORIZATION_CODE&redirect_uri=https%3A%2F%2F{https://yourApp/callback}",
CURLOPT_HTTPHEADER => [
"content-type: application/x-www-form-urlencoded"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
```
```python Python theme={null}
import http.client
conn = http.client.HTTPSConnection("")
payload = "grant_type=authorization_code&client_id={yourClientId}&code_verified=YOUR_GENERATED_CODE_VERIFIER&code=YOUR_AUTHORIZATION_CODE&redirect_uri=https%3A%2F%2F{https://yourApp/callback}"
headers = { 'content-type': "application/x-www-form-urlencoded" }
conn.request("POST", "/{yourDomain}/oauth/token", payload, headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
```
```ruby Ruby theme={null}
require 'uri'
require 'net/http'
require 'openssl'
url = URI("https://{yourDomain}/oauth/token")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
request = Net::HTTP::Post.new(url)
request["content-type"] = 'application/x-www-form-urlencoded'
request.body = "grant_type=authorization_code&client_id={yourClientId}&code_verified=YOUR_GENERATED_CODE_VERIFIER&code=YOUR_AUTHORIZATION_CODE&redirect_uri=https%3A%2F%2F{https://yourApp/callback}"
response = http.request(request)
puts response.read_body
```
| Parameter | Description |
| - | - |
| **grant\_type** | This must be set to `authorization_code`. |
| **client\_id** | The value of your Auth0 Client Id. You can retrieve it from the Settings of your Application at the [Auth0 Dashboard](https://manage.auth0.com/#/applications). |
| **code\_verifier** | Cryptographically random key that was used to generate the `code_challenge` passed to [authorization URL](https://auth0.com/docs/api/authentication#authorization-code-grant-pkce-) (`/authorize`). |
| **code** | The `authorization_code` received from the previous authorize call. |
| **redirect\_uri** | The URL must match the `redirect_uri` passed in the previous section to `/authorize`. |
The response from the Token URL will contain:
```json lines theme={null}
{
"access_token": "eyJz93a...k4laUWw",
"refresh_token": "GEbRxBN...edjnXbL",
"id_token": "eyJ0XAi...4faeEoQ",
"token_type": "Bearer",
"expires_in":86400
}
```
* **access\_token**: An Access Token for the API, specified by the `audience`.
* **refresh\_token**: A [Refresh Token](/docs/secure/tokens/refresh-tokens) will only be present if you included the `offline_access` scope AND enabled **Allow Offline Access** for your API in the Dashboard.
* **id\_token**: An ID Token JWT containing user profile information.
* **token\_type**: A string containing the type of token, this will always be a Bearer token.
* **expires\_in**: The amount of seconds until the Access Token expires.
You will need to store the above credentials in local storage for use in calling your API and retrieving the user profile.
[See the implementation in Android](/docs/get-started/architecture-scenarios/mobile-api/mobile-implementation-android#store-credentials).
### Get the User Profile
To retrieve the [User Profile](https://auth0.com/docs/api/authentication?http#user-profile), your mobile application can decode the [ID Token](/docs/secure/tokens/id-tokens) using one of the [JWT libraries](https://jwt.io/#libraries-io). This is done by [verifying the signature](/docs/secure/tokens/id-tokens/validate-id-tokens#verify-the-signature) and [verifying the claims](/docs/secure/tokens/id-tokens/validate-id-tokens#verify-the-claims) of the token. After validating the ID Token, you can access its payload containing the user information:
```json lines theme={null}
{
"email_verified": false,
"email": "test.account@userinfo.com",
"clientID": "q2hnj2iu...",
"updated_at": "2016-12-05T15:15:40.545Z",
"name": "test.account@userinfo.com",
"picture": "https://s.gravatar.com/avatar/dummy.png",
"user_id": "auth0|58454...",
"nickname": "test.account",
"created_at": "2016-12-05T11:16:59.640Z",
"sub": "auth0|58454..."
}
```
[See the implementation in Android.](/docs/get-started/architecture-scenarios/mobile-api/mobile-implementation-android#3-get-the-user-profile)
### Display UI Elements Conditionally Based on Scope
Based on the `scope` of the user, you may want to show or hide certain UI elements. To determine the scope issued to a user, you will need to inspect the `scope` which was granted when the user was authenticated. This will be a string containing all the scopes, so you therefore need to inspect this string to see whether it contains the required `scope` and based on that make a decision whether to display a particular UI element.
[See the implementation in Android](/docs/get-started/architecture-scenarios/mobile-api/mobile-implementation-android#4-display-ui-elements-conditionally-based-on-scope)
### Call the API
To access secured resources from your API, the authenticated user's Access Token needs to be included in requests that are sent to it. This is accomplished by sending the Access Token in an `Authorization` header using the `Bearer` scheme.
[See the implementation in Android.](/docs/get-started/architecture-scenarios/mobile-api/mobile-implementation-android#5-call-the-api)
### Renew the Token
Refresh Tokens must be stored securely by an application since they do not expire and allow a user to remain authenticated essentially forever. If Refresh Tokens are compromised or you no longer need them, you can revoke the Refresh Tokens using the [Authentication API](https://auth0.com/docs/api/authentication#revoke-refresh-token).
To refresh your Access Token, perform a `POST` request to the `/oauth/token` endpoint using the Refresh Token from your authorization result.
A [Refresh Token](/docs/secure/tokens/refresh-tokens) will only be present if you included the `offline_access` scope in the previous authorization request and enabled **Allow Offline Access** for your API in the Dashboard.
Your request should include:
```bash cURL theme={null}
curl --request POST \
--url 'https://{yourDomain}/oauth/token' \
--header 'content-type: application/x-www-form-urlencoded'
```
```csharp C# theme={null}
var client = new RestClient("https://{yourDomain}/oauth/token");
var request = new RestRequest(Method.POST);
request.AddHeader("content-type", "application/x-www-form-urlencoded");
IRestResponse response = client.Execute(request);
```
```go Go theme={null}
package main
import (
"fmt"
"net/http"
"io/ioutil"
)
func main() {
url := "https://{yourDomain}/oauth/token"
req, _ := http.NewRequest("POST", url, nil)
req.Header.Add("content-type", "application/x-www-form-urlencoded")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := ioutil.ReadAll(res.Body)
fmt.Println(res)
fmt.Println(string(body))
}
```
```java Java theme={null}
HttpResponse response = Unirest.post("https://{yourDomain}/oauth/token")
.header("content-type", "application/x-www-form-urlencoded")
.asString();
```
```javascript Node.JS theme={null}
var axios = require("axios").default;
var options = {
method: 'POST',
url: 'https://{yourDomain}/oauth/token',
headers: {'content-type': 'application/x-www-form-urlencoded'}
};
axios.request(options).then(function (response) {
console.log(response.data);
}).catch(function (error) {
console.error(error);
});
```
```php PHP theme={null}
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://{yourDomain}/oauth/token",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_HTTPHEADER => [
"content-type: application/x-www-form-urlencoded"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
```
```python Python theme={null}
import http.client
conn = http.client.HTTPSConnection("")
headers = { 'content-type': "application/x-www-form-urlencoded" }
conn.request("POST", "/{yourDomain}/oauth/token", headers=headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
```
```ruby Ruby theme={null}
require 'uri'
require 'net/http'
require 'openssl'
url = URI("https://{yourDomain}/oauth/token")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
request = Net::HTTP::Post.new(url)
request["content-type"] = 'application/x-www-form-urlencoded'
response = http.request(request)
puts response.read_body
```
| Parameter | Description |
| - | - |
| **grant\_type** | This must be set to `refresh_token`. |
| **client\_id** | The value of your Auth0 Client Id. You can retrieve it from the Settings of your Application at the [Auth0 Dashboard](https://manage.auth0.com/#/applications). |
| **refresh\_token** | the Refresh Token to use, from the previous authentication result. |
The response will include the new Access Token:
```json lines theme={null}
{
"access_token": "eyJz93a...k4laUWw",
"refresh_token": "GEbRxBN...edjnXbL",
"id_token": "eyJ0XAi...4faeEoQ",
"token_type": "Bearer",
"expires_in":86400
}
```
[See the implementation in Android.](/docs/get-started/architecture-scenarios/mobile-api/mobile-implementation-android#store-the-credentials)
# Conclusion (Mobile Apps + API)
Source: https://auth0.com/docs/get-started/architecture-scenarios/mobile-api/part-4
Conclusion for the Mobile + API architecture scenario
In this document we covered a simple scenario: an API, used by a mobile application to allow employees to capture their timesheets.
We learned about the Authorization Code Grant with PKCE, what an Access Token is, how to configure an API in Auth0, how to configure a mobile application to communicate securely with this API, how to define and secure our API endpoints, how to use the provided libraries to validate the Access Token and how to retrieve a new one from Auth0.
We started by describing the business case and the requirements and went on explaining how each requirement can be met and the thought process behind each choice that was made.
We used Node.js for the API implementation and Android for the mobile application. Hopefully though after going through this document you are able to build this using the technologies you prefer.
Don't forget to check back for new business cases and more complex architecture scenarios!
# Node.js API Implementation (SPAs + API)
Source: https://auth0.com/docs/get-started/architecture-scenarios/spa-api/api-implementation-nodejs
The Node.js implementation of the API for the SPA + API architecture scenario
# Node.js API Implementation (SPAs + API)
This document is part of the SPA + API Architecture Scenario and it explains how to implement the API in Node.js. Please refer to the scenario for information on the implemented solution.
The full source code for the Node.js API implementation can be found in [this GitHub repository](https://github.com/auth0-samples/auth0-pnp-exampleco-timesheets/tree/master/timesheets-api/node).
## Step 1. Define the API endpoints
We will use the [Express web application framework](http://expressjs.com/) to build our Node.js API.
### Create a package.json File
Create a folder for your API, navigate into it and run `npm init`. This will setup your `package.json` file.
You can leave the default settings or change them as you see fit.
Our sample's `package.json` looks like the following:
```json lines theme={null}
{
"name": "timesheets-api",
"version": "1.0.0",
"description": "API used to add timesheet entries for employees and contractors",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/auth0-samples/auth0-pnp-timesheets.git"
},
"author": "Auth0",
"license": "MIT",
"bugs": {
"url": "https://github.com/auth0-samples/auth0-pnp-timesheets/issues"
},
"homepage": "https://github.com/auth0-samples/auth0-pnp-timesheets#readme"
}
```
### Install the Dependencies
Next, we need to set our dependencies. We will use the following modules:
* **express**: This module adds the [Express web application framework](https://expressjs.com/).
* **cors**: This module adds support for enabling [CORS](https://en.wikipedia.org/wiki/Cross-origin_resource_sharing) which is required since the API will be called from a Single-Page Application running on a different domain inside a web browser.
* **jwks-rsa**: This library retrieves RSA signing keys from a JWKS (JSON Web Key Set) endpoint. Using `expressJwtSecret` we can generate a secret provider that will provide the right signing key to `express-jwt` based on the `kid` in the JWT header. For more information refer to the [node-jwks-rsa GitHub repository](https://github.com/auth0/node-jwks-rsa).
* **express-jwt**: This module lets you authenticate HTTP requests using JWT tokens in your Node.js applications. It provides several functions that make working with JWTs easier. For more information refer to the [express-jwt GitHub repository](https://github.com/auth0/express-jwt).
* **body-parser**: This is a Node.js body parsing middleware. It extracts the entire body portion of an incoming request stream and exposes it on `req.body` as something easier to interface with.For more information and several alternatives refer to the body-parser GitHub repository.
To install these dependencies run the following:
```bash wrap lines theme={null}
npm install express cors express-jwt jwks-rsa body-parser express-jwt-authz --save
```
### Implement the Endpoints
Navigate to your API directory and create a `server.js` file. Your code needs to:
* Get the dependencies.
* Implement the endpoint(s).
* Launch the API server.
This is our sample implementation:
```javascript lines theme={null}
const express = require('express');
const app = express();
const { expressjwt: jwt } = require('express-jwt');
const jwksRsa = require('jwks-rsa');
const cors = require('cors');
const bodyParser = require('body-parser');
// Enable CORS
app.use(cors());
// Enable the use of request body parsing middleware
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true
}));
// Create timesheets API endpoint
app.post('/timesheets', function(req, res){
res.status(201).send({message: "This is the POST /timesheets endpoint"});
})
// Launch the API Server at localhost:8080
app.listen(8080);
```
Launch your API server using `node server` and make an HTTP POST request to `localhost:8080/timesheets`. You should see a JSON response with the message `This is the POST /timesheets endpoint`.
So now we have our endpoint but anyone can call it. Continue to the next paragraph to see how we can fix this.
## Step 2. Secure the API endpoints
In order to validate our token we will use the `jwt` function, provided by the [express-jwt middleware](https://github.com/auth0/express-jwt#usage), and the `jwks-rsa` to retrieve our secret. The libraries do the following:
1. `express-jwt` will decode the token and pass the request, the header and the payload to `jwksRsa.expressJwtSecret`.
2. `jwks-rsa` will then download all signing keys from the JWKS endpoint and see if a one of the signing keys matches the `kid` in the header of the JWT. If none of the signing keys match the incoming `kid`, an error will be thrown. If we have a match, we will pass the right signing key to `express-jwt`.
3. `express-jwt` will the continue its own logic to validate the signature of the token, the expiration, `audience` and the `issuer`.
The steps we will follow in our code are:
* Create the middleware function to validate the Access Token.
* Enable the use of the middleware in our routes.
You can also write some code to actually save the timesheet to a database. This is our sample implementation (some code is omitted for brevity):
If we launch our server now and do an HTTP POST to `localhost:8080/timesheets` we should get the error message `Missing or invalid token` (which is perfectly fine since we didn’t send an Access Token in our request).
In order to test the working scenario as well we need to:
* Get an Access Token. For details on how to do so refer to: [Get an Access Token](/docs/get-started/architecture-scenarios/server-application-api#get-an-access-token).
* Invoke the API while adding an `Authorization` header to our request with the value `Bearer ACCESS_TOKEN` (where `ACCESS_TOKEN` is the value of the token we retrieved in the first step).
## Step 3. Check the application permissions
In this step we will add to our implementation the ability to check if the application has permissions (or `scope`) to use our endpoint in order to create a timesheet. In particular we want to ensure that the token has the correct scope, which is `batch:upload`.
In order to do this we will make use of the `express-jwt-authz` Node.js package, so go ahead and add that to your project:
```bash lines theme={null}
npm install express-jwt-authz --save
```
Now it is as simple as adding a call to `jwtAuthz(...)` to your middleware to ensure that the JWT contain a particular scope in order to execute a particular endpoint.
We will add an additional dependency. The **express-jwt-authz** library, which is used in conjunction with express-jwt, validates the [JWT](/docs/secure/tokens/json-web-tokens) and ensures it bears the correct permissions to call the desired endpoint. For more information refer to the [express-jwt-authz GitHub repository](https://github.com/auth0/express-jwt-authz).
This is our sample implementation (some code is omitted for brevity):
```javascript lines theme={null}
// set dependencies - some code omitted
const jwtAuthz = require('express-jwt-authz');
// Enable CORS - code omitted
// Create middleware for checking the JWT - code omitted
// Enable the use of request body parsing middleware - code omitted
// create timesheets API endpoint
app.post('/timesheets', checkJwt, jwtAuthz(['create:timesheets'], { customUserKey: 'auth' }), function(req, res){
var timesheet = req.body;
// Save the timesheet to the database...
//send the response
res.status(201).send(timesheet);
})
// launch the API Server at localhost:8080 - code omitted
```
If we invoke our API with a token that does not include this scope we should get the error message Forbidden with the HTTP status code `403`. You can test this by removing this scope from your API.
## Step 4. Determine the User Identity
The `express-jwt` middleware which is used to validate the JWT, also sets the `req.auth` with the information contained in the JWT. If you want to use the `sub` claim to identify the user uniquely, you can simply use `req.auth.sub`.
In the case of the timesheets application however, we want to use the email address of the user as the unique identifier.
The first thing we need to do is to write a rule which will add the email address of the user to the Access Token. Go to the [Rules section](https://manage.auth0.com/#/rules%7D) of the Dashboard and click on the **Create Rule** button.
You can give the rule a descriptive name, for example `Add email to Access Token`, and then use the following code for the rule:
```javascript lines theme={null}
function (user, context, callback) {
const namespace = 'https://api.exampleco.com/';
context.accessToken[namespace + 'email'] = user.email;
callback(null, user, context);
}
```
The `namespace` is used to ensure the claim has a unique name and does not clash with the names of any of the standard OIDC claims. However, Auth0 supports namespaced and non-namespaced custom claims. For more info on custom claims, see [Create Custom Claims](/docs/secure/tokens/json-web-tokens/create-custom-claims).
Next, inside your API, you can retrieve the value of the claim from `req.auth`, and use that as the unique user identity which you can associate with timesheet entries.
```js lines theme={null}
app.get('/timesheets', checkJwt, jwtAuthz(['read:timesheets'], { customUserKey: 'auth' }), function(req, res) {
var timesheet = req.body;
// Associate the timesheet entry with the current user
var userId = req.auth['https://api.exampleco.com/email'];
timesheet.user_id = userId;
// Save the timesheet to the database...
//send the response
res.status(201).send(timesheet);
});
```
# Auth0 Configuration (SPAs + API)
Source: https://auth0.com/docs/get-started/architecture-scenarios/spa-api/part-2
Auth0 Configuration for the SPA + API architecture scenario
In this section we will review all the configurations we need to apply at the [Auth0 Dashboard](https://manage.auth0.com/#).
## Create the API
Navigate to the [APIs section](https://manage.auth0.com/#/apis) of the dashboard, and click the **Create API** button.
You will be asked to supply the following details for your API:
* **Name**: a friendly name for the API. Does not affect any functionality.
* **Identifier**: a unique identifier for the API. We recommend using a URL but note that this doesn't have to be a publicly available URL, Auth0 will not call your API at all. This value cannot be modified afterwards.
* **Signing Algorithm**: the algorithm to sign the tokens with. The available values are `HS256` and `RS256`. When selecting RS256 the token will be signed with the tenant's private key. To learn more about signing algorithms, see [Signing Algorithms](/docs/get-started/applications/signing-algorithms).
Fill in the required information and click the **Create** button.
## Configure the Scopes
Once the application has been created you will need to configure the Scopes which applications can request during authorization.
In the settings for your API, go to the Permissions tab. In this section you can add the scopes for our business case: `read:timesheets`, `create:timesheets`, `delete:timesheets`, and `approve:timesheets`.
## Create the Application
There are four application types in Auth0:
* **Native App** (used by mobile or desktop apps),
* **Single-Page Web App**,
* **Regular Web App** and
* **Machine to Machine App** (used by CLIs, Daemons, or services running on your backend).
For this scenario we want to create a new Application for our SPA, hence we will use Single-Page Application as the application type.
To create a new Application, navigate to the [dashboard](https://manage.auth0.com/#) and click on the [Applications](https://manage.auth0.com/#/applications) menu option on the left. Click the **+ Create Application** button.
Set a name for your Application (we will use `Timesheets SPA`) and select `Single-Page Web App` as the type.
Click **Create**.
That's it for now. When we are done with the SPA implementation we will revisit the dashboard and this Application's settings to make some changes in its configuration.
## Configure the Authorization Extension
You will need to ensure that the Authorization Extension is installed for your tenant. You can refer to the [Authorization Extension documentation](/docs/customize/extensions/authorization-extension) for details on how to do this.
### Define Permissions
You will now define the required Permissions, according to the scopes you have already defined: `read:timesheets`, `create:timesheets`, `delete:timesheets`, and `approve:timesheets`.
In the Authorization Extension, click the **Permissions** tab, and then click on the **Create Permission** button.
In the dialog, capture the details for each permission.
Ensure that the name of the permission is exactly the same as the corresponding scope:
Proceed to create the permissions for all the remaining scopes:
### Define Roles
Next let's configure the two Roles: employee and manager.
Head over to the **Roles** tab, click the **Create Role** button, and select the **Timesheets SPA** application.
Set the **Name** and **Description** to `Employee`, and select the `delete:timesheets`, `create:timesheets` and `read:timesheets` permissions. Click on **Save**.
Next, follow the same process to create a `Manager` role, and ensure that you have selected all the permissions.
### Assign Users to Roles
You need to assign all users to either the `Manager` or the `Employee` role.
You can do this by going to the **Users** tab in the Authorization Extension and selecting a user.
On the user information screen, go to the **Roles** tab. Click **Add Role to User**, and select the appropriate role.
### Configuring the Authorization Extension
You will also need to ensure that the Rule for the Authorization Extension is published.
To do so, click on your user avatar in the top right of the Authorization Extension, and select **Configuration**.
Make sure that **Permissions** are enabled and then click **Publish Rule**.
### Create a Rule to validate token scopes
The final step in this process is to create a Rule to check if the scopes contained in an Access Token are valid based on the permissions assigned to the user. Any scopes which are not valid for a user should be removed from the Access Token.
In your Auth0 Dashboard, go to the **Rules** tab. You should see the Rule created by the Authorization Extension. Click on the **Create Rule** button and select the **Empty Rule** template. You can give the Rule a name, such as **Access Token Scopes**, and then specify the following code for the Rule:
```javascript lines theme={null}
function (user, context, callback) {
var permissions = user.permissions || [];
var requestedScopes = context.request.body.scope || context.request.query.scope;
var filteredScopes = requestedScopes.split(' ').filter( function(x) {
return x.indexOf(':') < 0;
});
var allScopes = filteredScopes.concat(permissions);
context.accessToken.scope = allScopes.join(' ');
callback(null, user, context);
}
```
The code above will ensure that all Access Tokens will only contain the properly-formatted scopes (e.g., `action:area` or `delete:timesheets`) which are valid according to a user's permissions. Once you are done you can click on the **Save** button.
Rules execute in the order they are displayed on the Rules page, so ensure that the new rule you created is positioned below the rule for the Authorization Extension, so it executes after the Authorization Extension rule.
# API and SPA Configuration (SPAs + API)
Source: https://auth0.com/docs/get-started/architecture-scenarios/spa-api/part-3
API and SPA Configuration for the SPA + API architecture scenario
In this section we will see how we can implement an API for our scenario.
For simplicity, we will keep our implementation solely focused on authentication and authorization. As you will see in the samples, the input timesheet entry will be hard-coded, and the API will not persist the timesheet entry. Instead, it will simply echo back some of the info.
## Define the API endpoints
First we need to define the endpoints of our API.
An **API endpoint** is a unique URL that represents an object. To interact with this object, you need to point your application to its URL. For example, if you had an API that could return either orders or customers, you might configure two endpoints: `/orders` and `/customers`. Your application would interact with these endpoints using different HTTP methods; for example, `POST /orders` could create a new order or `GET /orders` could retrieve the dataset of one or more orders.
For this implementation we will only define 2 endpoints; one for retrieving a list of all timesheets for an employee, and another which will allow an employee to create a new timesheet entry.
An `HTTP GET` request to the `/timesheets` endpoint will allow a user to retrieve their timesheets, and an `HTTP POST` request to the `/timesheets` endpoint will allow a user to add a new timesheet.
**See the implementation in** [**Node.js**](/docs/get-started/architecture-scenarios/spa-api/api-implementation-nodejs#1-define-the-api-endpoints).
### Secure the Endpoints
When an API receives a request with a bearer Access Token as part of the header, the first thing to do is to validate the token. This consists of a series of steps, and if any of these fails then the request must be rejected with a `Missing or invalid token` error message to the calling app.
The validations that the API should perform are:
* Check that the JWT is well formed
* Check the signature
* Validate the standard claims
[JWT.io](https://jwt.io/) provides a list of libraries that can do most of the work for you: parse the JWT, verify the signature and the claims.
Part of the validation process is to also check the Application permissions (scopes), but we will address this separately in the next paragraph of this document.
For more information on validating Access Tokens, see [Validate Access Tokens](/docs/secure/tokens/access-tokens/validate-access-tokens).
**See the implementation in** [**Node.js**](/docs/get-started/architecture-scenarios/spa-api/api-implementation-nodejs#2-secure-the-api-endpoints).
### Check the Application's Permissions
By now we have verified that the JWT is valid. The last step is to verify that the application has the permissions required to access the protected resources.
To do so, the API needs to check the [scopes](/docs/get-started/apis/scopes) of the decoded JWT. This claim is part of the payload and it is a space-separated list of strings.
**See the implementation in** [**Node.js**](/docs/get-started/architecture-scenarios/spa-api/api-implementation-nodejs#3-check-the-client-permissions).
### Determine user identity
For both endpoints (retrieving the list of timesheets, and adding a new timesheet) we will need to determine the identity of the user.
For retrieving the list of timesheets this is to ensure that we only return the timesheets belonging to the user making the request, and for adding a new timesheet this is to ensure that the timesheet is associated with the user making the request.
One of the standard JWT claims is the `sub` claim which identifies the principal that is the subject to the claim. In the case of the Implicit Grant flow this claim will contain the user's identity, which will be the unique identifier for the Auth0 user. You can use this to associate any information in external systems with a particular user.
You can also use a custom claim to add another attribute of the user - such as their email address - to the Access Token and use that to uniquely identify the user.
**See the implementation in** [**Node.js**](/docs/get-started/architecture-scenarios/spa-api/api-implementation-nodejs#4-determine-the-user-identity).
## Implement the SPA
In this section we will see how we can implement a SPA for our scenario.
### Authorize the user
To authorize the user we will be using the [auth0.js library](/docs/libraries/auth0js). You can initialize a new instance of the Auth0 application as follows:
You need to pass the following configuration values:
* **clientID**: The value of your Auth0 Client Id. You can retrieve it from the Settings of your Application at the [Dashboard](https://manage.auth0.com/#/applications%7D).
* **domain**: The value of your Auth0 Domain. You can retrieve it from the Settings of your Application at the [Dashboard](https://manage.auth0.com/#/applications%7D).
* **responseType**: Indicates the Authentication Flow to use. For a SPA which uses the **Implicit Flow**, this should be set to `token id_token`. The `token` part, triggers the flow to return an Access Token in the URL fragment, while the `id_token` part, triggers the flow to return an ID Token as well.
* **audience**: The value of your API Identifier. You can retrieve it from the [Settings of your API](https://manage.auth0.com/#/apis%7D) at the Dashboard.
* **redirectUri**: The URL to which Auth0 should redirect to after the user has authenticated.
* **scope**: The [scopes](/docs/get-started/apis/scopes) which determine the information to be returned in the ID Token and Access Token. A scope of `openid profile` will return all the user profile information in the ID Token. You also need to request the scopes required to call the API, in this case the `read:timesheets create:timesheets` scopes. This will ensure that the Access Token has these scopes.
To initiate the authentication flow you can call the `authorize()` method:
```js lines theme={null}
auth0.authorize();
```
After the authentication, Auth0 will redirect back to the **redirectUri** you specified when configuring the new instance of the Auth0 application. At this point you will need to call the `parseHash()` method which parses a URL hash fragment to extract the result of an Auth0 authentication response.
The contents of the authResult object returned by parseHash depend upon which authentication parameters were used. It may include the following:
* **idToken**: An ID Token JWT containing user profile information
* **accessToken**: An Access Token for the API, specified by the **audience**.
* **expiresIn**: A string containing the expiration time (in seconds) of the Access Token.
Determine where best to [store the tokens](/docs/secure/security-guidance/data-security/token-storage). If your single-page app has a backend server at all, then tokens should be handled server-side using the [Authorization Code Flow](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow) or [Authorization Code Flow with Proof Key for Code Exchange (PKCE)](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow-with-pkce).
If you have a single-page app (SPA) with no corresponding backend server, your SPA should request new tokens on login and store them in memory without any persistence. To make API calls, your SPA would then use the in-memory copy of the token.
For an example of how to handle sessions in SPAs, check out the [Handle Authentication Tokens](/docs/quickstart/spa/vanillajs#handle-authentication-tokens) section of the [JavaScript Single-Page App Quickstart](/docs/quickstart/spa/vanillajs).
**See the implementation in** [**Angular 2**](/docs/get-started/architecture-scenarios/spa-api/spa-implementation-angular2#2-authorize-the-user).
### Get the User Profile
This section shows how to retrieve the user info using the Access Token and the [/userinfo endpoint](https://auth0.com/docs/api/authentication#get-user-info). To avoid this API call, you can just decode the ID Token [using a library](https://jwt.io/#libraries-io) (make sure you validate it first). If you need additional user information consider using [our Management API](https://auth0.com/docs/api/management/v2#!/Users/get_users_by_id) from your backend.
The `client.userInfo` method can be called passing the returned `authResult.accessToken` in order to retrieve the user's profile information. It will make a request to the [/userinfo endpoint](https://auth0.com/docs/api/authentication#get-user-info) and return the `user` object, which contains the user's information, similar to the example below:
```json lines theme={null}
{
"email_verified": "false",
"email": "test@example.com",
"clientID": "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHH",
"updated_at": "2017-02-07T20:50:33.563Z",
"name": "tester9@example.com",
"picture": "https://gravatar.com/avatar/example.png",
"user_id": "auth0|123456789012345678901234",
"nickname": "tester9",
"created_at": "2017-01-20T20:06:05.008Z",
"sub": "auth0|123456789012345678901234"
}
```
You can access any of these properties in the callback function passed when calling the `userInfo` function:
```javascript lines theme={null}
const accessToken = authResult.accessToken;
auth0.client.userInfo(accessToken, (err, profile) => {
if (profile) {
// Get the user’s nickname and profile image
var nickname = profile.nickname;
var picture = profile.picture;
}
});
```
**See the implementation in** [**Angular 2**](/docs/get-started/architecture-scenarios/spa-api/spa-implementation-angular2#3-get-the-user-profile).
### Display UI Elements Conditionally Based on Scope
Based on the `scope` of the user, you may want to show or hide certain UI elements. To determine the scope issued to a user, you will need to store the scope which was initially requested during the authorization process. When a user is authorized, the `scope` will also be returned in the `authResult`.
If the `scope` in the `authResult` is empty, then all the scopes which was requested was granted. If the `scope` in the `authResult` is not empty, it means a different set of scopes were granted, and you should use the ones in `authResult.scope`.
**See the implementation in** [**Angular 2**](/docs/get-started/architecture-scenarios/spa-api/spa-implementation-angular2#4-display-ui-elements-conditionally-based-on-scope).
### Call the API
To access secured resources from your API, the authenticated user's Access Token needs to be included in requests that are sent to it. This is accomplished by sending the Access Token in an `Authorization` header using the `Bearer` scheme.
**See the implementation in** [**Angular 2**](/docs/get-started/architecture-scenarios/spa-api/spa-implementation-angular2#5-call-the-api).
### Renew the Access Token
As a security measure, it is recommended that the lifetime of a user's Access Token be kept short. When you create an API in the Auth0 dashboard, the default lifetime is `7200` seconds (2 hours), but this can be controlled on a per-API basis.
Once expired, an Access Token can no longer be used to access an API. In order to obtain access again, a new Access Token needs to be obtained.
Obtaining a new Access Token can be done by repeating the authentication flow, used to obtain the initial Access Token. In a SPA this is not ideal, as you may not want to redirect the user away from their current task to complete the authentication flow again.
In cases like this you can make use of [Silent Authentication](/docs/authenticate/login/configure-silent-authentication). Silent authentication lets you perform an authentication flow where Auth0 will only reply with redirects, and never with a login page. This does however require that the user was already logged in via [Single Sign-on (SSO)](/docs/authenticate/single-sign-on).
**See the implementation in** [**Angular 2**](/docs/get-started/architecture-scenarios/spa-api/spa-implementation-angular2#6-renew-the-access-token).
# Conclusion (SPAs + API)
Source: https://auth0.com/docs/get-started/architecture-scenarios/spa-api/part-4
Conclusion for the SPA + API architecture scenario
In this document we covered a simple scenario involving an API used by a Single-Page Application (SPA) to allow employees to capture their timesheets.
We learned about the Implicit Grant, what an Access Token is, how to configure an API in Auth0, how to configure a SPA application to communicate securely with this API, how to define and secure our API endpoints, how to use the provided libraries to validate the Access Token and how to retrieve a new one from Auth0.
We started by describing the business case and the requirements and went on explaining how each requirement can be met and the thought process behind each choice that was made.
We used Node.js for the API implementation and Angular for the SPA. Hopefully though after going through this document you are able to build this using the technologies you prefer.
# SPA Angular 2 Implementation (SPAs + API)
Source: https://auth0.com/docs/get-started/architecture-scenarios/spa-api/spa-implementation-angular2
The Angular 2 implementation of the SPA for the SPA + API architecture scenario
This document is part of the SPA + API Architecture Scenario and it explains how to implement the SPA in Angular 2. Please refer to the scenario for information on the implemented solution.
The full source code for the Angular 2 implementation of the SPA can be found in [this GitHub repository](https://github.com/auth0-samples/auth0-pnp-exampleco-timesheets/tree/master/timesheets-spa/angular).
## Step 1. Configuration
Your application will require certain configuration information. Before carrying on with the rest of the implementation, create an `AuthConfig` interface which will contain various configuration values. Place this interface in a file called `auth0-variables.ts`.
```ts lines theme={null}
interface AuthConfig {
clientID: string;
domain: string;
callbackURL: string;
apiUrl: string;
}
export const AUTH_CONFIG: AuthConfig = {
clientID: '',
domain: '',
callbackURL: 'http://localhost:4200/callback',
apiUrl: ''
};
```
## Step 2. Authorize the User
### Create an Authorization Service
The best way to manage and coordinate the tasks necessary for user authentication is to create a reusable service. With the service in place, you'll be able to call its methods throughout your application. An instance of the `WebAuth` object from [auth0.js](/docs/libraries/auth0js) can be created in the service.
```jsx lines expandable theme={null}
import { Injectable } from '@angular/core';
import { AUTH_CONFIG } from './auth0-variables';
import { Router } from '@angular/router';
import 'rxjs/add/operator/filter';
import auth0 from 'auth0-js';
@Injectable()
export class AuthService {
userProfile: any;
requestedScopes: string = 'openid profile read:timesheets create:timesheets';
auth0 = new auth0.WebAuth({
clientID: AUTH_CONFIG.clientID,
domain: AUTH_CONFIG.domain,
responseType: 'token id_token',
audience: AUTH_CONFIG.apiUrl,
redirectUri: AUTH_CONFIG.callbackURL,
scope: this.requestedScopes
});
constructor(public router: Router) {}
public login(): void {
this.auth0.authorize();
}
public handleAuthentication(): void {
this.auth0.parseHash((err, authResult) => {
if (authResult && authResult.accessToken && authResult.idToken) {
window.location.hash = '';
this.setSession(authResult);
this.router.navigate(['/home']);
} else if (err) {
this.router.navigate(['/home']);
console.log(err);
alert('Error: <%= "${err.error}" %>. Check the console for further details.');
}
});
}
private setSession(authResult): void {
// Set the time that the Access Token will expire at
const expiresAt = JSON.stringify((authResult.expiresIn * 1000) + new Date().getTime());
// If there is a value on the scope param from the authResult,
// use it to set scopes in the session for the user. Otherwise
// use the scopes as requested. If no scopes were requested,
// set it to nothing
const scopes = authResult.scope || this.requestedScopes || '';
localStorage.setItem('access_token', authResult.accessToken);
localStorage.setItem('id_token', authResult.idToken);
localStorage.setItem('expires_at', expiresAt);
localStorage.setItem('scopes', JSON.stringify(scopes));
}
public logout(): void {
// Remove tokens and expiry time from localStorage
localStorage.removeItem('access_token');
localStorage.removeItem('id_token');
localStorage.removeItem('expires_at');
localStorage.removeItem('scopes');
// Go back to the home route
this.router.navigate(['/']);
}
public isAuthenticated(): boolean {
// Check whether the current time is past the
// Access Token's expiry time
const expiresAt = JSON.parse(localStorage.getItem('expires_at'));
return new Date().getTime() < expiresAt;
}
public userHasScopes(scopes: Array): boolean {
const grantedScopes = JSON.parse(localStorage.getItem('scopes')).split(' ');
return scopes.every(scope => grantedScopes.includes(scope));
}
}
```
The service includes several methods for handling authentication.
* **login**: calls `authorize` from auth0.js which initiates Universal Login
* **handleAuthentication**: looks for an authentication result in the URL hash and processes it with the `parseHash` method from auth0.js
* **setSession**: sets the user's Access Token, ID Token, and a time at which the Access Token will expire
* **logout**: removes the user's tokens from browser storage
isAuthenticated: checks whether the expiry time for the Access Token has passed
### Process the Authentication Result
When a user authenticates via Universal Login and is then redirected back to your application, their authentication information will be contained in a URL hash fragment. The `handleAuthentication` method in the `AuthService` is responsible for processing the hash.
Call `handleAuthentication` in your app's root component so that the authentication hash fragment can be processed when the app first loads after the user is redirected back to it.
```javascript lines theme={null}
// src/app/app.component.ts
import { Component } from '@angular/core';
import { AuthService } from './auth/auth.service';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
constructor(public auth: AuthService) {
auth.handleAuthentication();
}
}
```
### Add the Callback Component
Using Universal Login means that users are taken away from your application to a page hosted by Auth0. After they successfully authenticate, they are returned to your application where a client-side session is set for them.
You can choose to have users return to any URL in your application that you like; however, it is recommended that you create a dedicated callback route to serve as a central location that the user will be returned to upon successful authentication. Having a single callback route is beneficial for two main reasons:
* It prevents the need to allowlist multiple (and sometimes unknown) callback URLs
* It serves as a place to show a loading indicator while your application sets the user's client-side session
Create a component named `CallbackComponent` and populate it with a loading indicator.
```jsx lines theme={null}
```
This example assumes some kind of loading spinner is available in an `assets` directory. See the downloadable sample for a demonstration.
After authentication, users will be taken to the `/callback` route for a brief time where they will be shown a loading indicator. During this time, their client-side session will be set, after which they will be redirected to the `/home` route.
## Step 3. Get the User Profile
This section shows how to retrieve the user info using the Access Token and the [/userinfo endpoint](https://auth0.com/docs/api/authentication#get-user-info). Alternatively, you can just decode the ID Token [using a library](https://jwt.io/#libraries-io) (make sure you validate it first). The output will be the same. If you need additional user information consider using the [our Management API](https://auth0.com/docs/api/management/v2#!/Users/get_users_by_id).
To obtain the user's profile, update the existing `AuthService` class. Add a `getProfile` function which will extract the user's Access Token from local storage, and then pass that call the `userInfo` function to retrieve the user's information.
```javascript lines theme={null}
// Existing code from the AuthService class is omitted in this code sample for brevity
@Injectable()
export class AuthService {
public getProfile(cb): void {
const accessToken = localStorage.getItem('access_token');
if (!accessToken) {
throw new Error('Access Token must exist to fetch profile');
}
const self = this;
this.auth0.client.userInfo(accessToken, (err, profile) => {
if (profile) {
self.userProfile = profile;
}
cb(err, profile);
});
}
}
```
You can now simply call this function from any service where you want to retrieve and display information about the user.
For example you may choose to create a new component to display the user's profile information:
```jsx lines theme={null}
import { Component, OnInit } from '@angular/core';
import { AuthService } from './../auth/auth.service';
@Component({
selector: 'app-profile',
templateUrl: './profile.component.html',
styleUrls: ['./profile.component.css']
})
export class ProfileComponent implements OnInit {
profile: any;
constructor(public auth: AuthService) { }
ngOnInit() {
if (this.auth.userProfile) {
this.profile = this.auth.userProfile;
} else {
this.auth.getProfile((err, profile) => {
this.profile = profile;
});
}
}
}
```
The template for this component looks as follows:
```jsx lines theme={null}
Profile
{{ profile?.nickname }}
{{ profile | json }}
```
## Step 4. Display UI Elements Conditionally Based on Scope
During the authorization process we already stored the actual scopes which a user was granted in the local storage. If the `scope` returned in the `authResult` is not empty, it means that a user was issued a different set of scopes than what was initially requested, and we should therefore use `authResult.scope` to determine the scopes granted to the user.
If the `scope` returned in `authResult` is issued is empty, it means the user was granted all the scopes that were requested, and we can therefore use the requested scopes to determine the scopes granted to the user.
Here is the code we wrote earlier for the `setSession` function that does that check:
```jsx lines theme={null}
private setSession(authResult): void {
// Set the time that the Access Token will expire at
const expiresAt = JSON.stringify((authResult.expiresIn * 1000) + new Date().getTime());
// If there is a value on the `scope` param from the authResult,
// use it to set scopes in the session for the user. Otherwise
// use the scopes as requested. If no scopes were requested,
// set it to nothing
const scopes = authResult.scope || this.requestedScopes || '';
localStorage.setItem('access_token', authResult.accessToken);
localStorage.setItem('id_token', authResult.idToken);
localStorage.setItem('expires_at', expiresAt);
localStorage.setItem('scopes', JSON.stringify(scopes));
this.scheduleRenewal();
}
```
Next we need to add a function to the `AuthService` class which we can call to determine if a user was granted a specific scope:
```jsx lines theme={null}
@Injectable()
export class AuthService {
// some code omitted for brevity
public userHasScopes(scopes: Array): boolean {
const grantedScopes = JSON.parse(localStorage.getItem('scopes')).split(' ');
return scopes.every(scope => grantedScopes.includes(scope));
}
}
```
You can call this method to determine whether we should display a specific UI element, or not. As an example we only want to display the **Approve Timesheets** link if the user has the `approve:timesheets` scope. Note in the code below that we added a call to the `userHasScopes` function to determine whether that link should be displayed or not.
```xml lines theme={null}
```
### Protect a route
We should also protect a route to not allow a route to be navigated to if a user has not been granted the correct scopes. For this we can add a new `ScopeGuardService` service class:
```jsx lines theme={null}
import { Injectable } from '@angular/core';
import { Router, CanActivate, ActivatedRouteSnapshot } from '@angular/router';
import { AuthService } from './auth.service';
@Injectable()
export class ScopeGuardService implements CanActivate {
constructor(public auth: AuthService, public router: Router) {}
canActivate(route: ActivatedRouteSnapshot): boolean {
const scopes = (route.data as any).expectedScopes;
if (!this.auth.isAuthenticated() || !this.auth.userHasScopes(scopes)) {
this.router.navigate(['']);
return false;
}
return true;
}
}
```
And then use that when we configure the routes to determine whether a route can be activated. Notice the use of the new `ScopeGuardService` in the definition for the `approval` route below:
```javascript lines theme={null}
// app.routes.ts
import { Routes, CanActivate } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { ProfileComponent } from './profile/profile.component';
import { CallbackComponent } from './callback/callback.component';
import { AuthGuardService as AuthGuard } from './auth/auth-guard.service';
import { ScopeGuardService as ScopeGuard } from './auth/scope-guard.service';
import { TimesheetListComponent } from './timesheet-list/timesheet-list.component';
import { TimesheetAddComponent } from './timesheet-add/timesheet-add.component';
import { ApprovalComponent } from './approval/approval.component';
export const ROUTES: Routes = [
{ path: '', component: HomeComponent },
{ path: 'profile', component: ProfileComponent, canActivate: [AuthGuard] },
{ path: 'callback', component: CallbackComponent },
{ path: 'timesheets/add', component: TimesheetAddComponent, canActivate: [AuthGuard] },
{ path: 'timesheets', component: TimesheetListComponent, canActivate: [AuthGuard] },
{ path: 'approval', component: ApprovalComponent, canActivate: [ScopeGuard], data: { expectedScopes: ['approve:timesheets']} },
{ path: '**', redirectTo: '' }
];
```
## Step 5. Call the API
The [angular2-jwt](https://github.com/auth0/angular2-jwt) module can be used to automatically attach JSON Web Tokens to requests made to your API. It does this by providing an `AuthHttp` class which is a wrapper over Angular's `Http` class.
Install `angular2-jwt`:
```bash lines theme={null}
# installation with npm
npm install --save angular2-jwt
# installation with yarn
yarn add angular2-jwt
```
Create a factory function with some configuration values for `angular2-jwt` and add it to the `providers` array in your application's `@NgModule`. The factory function should have a `tokenGetter` function which fetches the `access_token` from local storage.
```jsx lines theme={null}
import { Http, RequestOptions } from '@angular/http';
import { AuthHttp, AuthConfig } from 'angular2-jwt';
export function authHttpServiceFactory(http: Http, options: RequestOptions) {
return new AuthHttp(new AuthConfig({
tokenGetter: (() => localStorage.getItem('access_token'))
}), http, options);
}
@NgModule({
declarations: [...],
imports: [...],
providers: [
AuthService,
{
provide: AuthHttp,
useFactory: authHttpServiceFactory,
deps: [Http, RequestOptions]
}
],
bootstrap: [...]
})
```
After `angular2-jwt` is configured, you can use the `AuthHttp` class to make secure calls to your API from anywhere in the application. To do so, inject `AuthHttp` in any component or service where it is needed and use it just as you would use Angular's regular `Http` class.
```jsx lines theme={null}
import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import { AuthHttp } from 'angular2-jwt';
import 'rxjs/add/operator/map';
import { NewTimesheetModel } from '../models/new-timesheet-model';
@Injectable()
export class TimesheetsService {
constructor(public authHttp: AuthHttp) { }
addTimesheet(model: NewTimesheetModel) {
return this.authHttp.post('http://localhost:8080/timesheets', JSON.stringify(model));
}
getAllTimesheets() {
return this.authHttp.get('http://localhost:8080/timesheets')
.map(res => res.json())
}
}
```
## Step 6. Renew the Access Token
Renewing the user's Access Token requires to update the Angular SPA. Add a method to the `AuthService` which calls the `checkSession` method from auth0.js. If the renewal is successful, use the existing `setSession` method to set the new tokens in local storage.
```ts lines theme={null}
public renewToken() {
this.auth0.checkSession({
audience: AUTH_CONFIG.apiUrl
}, (err, result) => {
if (!err) {
this.setSession(result);
}
});
}
```
In the `AuthService` class, add a method called `scheduleRenewal` to set up a time at which authentication should be silently renewed. In the sample below this is set up to happen 30 seconds before the actual token expires. Also add a method called `unscheduleRenewal` which will unsubscribe from the Observable.
```ts lines expandable theme={null}
public scheduleRenewal() {
if (!this.isAuthenticated()) return;
const expiresAt = JSON.parse(window.localStorage.getItem('expires_at'));
const source = Observable.of(expiresAt).flatMap(
expiresAt => {
const now = Date.now();
// Use the delay in a timer to
// run the refresh at the proper time
var refreshAt = expiresAt - (1000 * 30); // Refresh 30 seconds before expiry
return Observable.timer(Math.max(1, refreshAt - now));
});
// Once the delay time from above is
// reached, get a new JWT and schedule
// additional refreshes
this.refreshSubscription = source.subscribe(() => {
this.renewToken();
});
}
public unscheduleRenewal() {
if (!this.refreshSubscription) return;
this.refreshSubscription.unsubscribe();
}
```
Finally you need to initiate the schedule renewal. This can be done by calling `scheduleRenewal` inside your `AppComponent` which will happen when the page is loaded. This will occur after every authentication flow, either when the user explicitly logs in, or when the silent authentication happens.
### Refresh Token Rotation
Recent advancements in user privacy controls in browsers adversely impact the user experience by preventing access to third-party cookies. Auth0 recommends using [Refresh Token Rotation](/docs/secure/tokens/refresh-tokens/refresh-token-rotation), which provides a secure method for using refresh tokens in SPAs while providing end-users with seamless access to resources without the disruption in UX caused by browser privacy technology like ITP.
# Auth0 Agent Experience Score
Source: https://auth0.com/docs/get-started/auth0-agent-experience
Learn how Auth0 scores AI agent performance across models and frameworks, including the dimensions, grading system, and methodology behind the Agent Experience Score.
The [Agent Experience Score](https://auth0.com/agent-experience) measures how well AI agents implement Auth0 across different models and frameworks. It allows you to compare current scores from agents implementing Auth0 services and features — such as Multi-factor Authentication (MFA) or Auth0 Actions — in development and testing environments to review how Auth0 tools improve agent performance.
Use this resource to learn about the scoring methodology, including how scores are calculated, what dimensions are measured, and how grades are assigned.
## Test specifications
AI agents — Claude Code, GitHub Copilot, Gemini CLI — run Auth0 integration tasks in isolated development environments. Each agent uses the same tools a developer would in a realistic environment: a workspace, a shell, and file tools like Auth0 CLI. The prompts are short and realistic: "add authentication to my Next.js app," not step-by-step recipes.
Each model is tested with and without Auth0 tools ([MCP Server](/docs/get-started/auth0-mcp-server/getting-started-with-auth0-mcp-server) and [Agent Skills](/docs/quickstart/agent-skills)). The difference between those scores is the measurable impact of Auth0's AI tooling on the developer experience.
## Score dimensions
Every run is scored across 8 dimensions split into two categories — 50% process, 50% output. Five dimensions address the agent process from end-to-end with Auth0 tools. Three dimensions score the final output. Each dimension is scored 0–100 individually, then weighted and combined into the overall score.
| Dimension | Category | Weight | Description |
| - | - | - | - |
| **Setup Friction** | Process | 12% | Score determined by the agent's ability to complete the task autonomously. If the agent paused to ask questions or encountered errors, the score decreased. |
| **Setup Speed** | Process | 12% | Score determined by the agent's active execution time. Results are comparable across environments. |
| **Efficiency** | Process | 12% | Score determined by the proportion of wasteful tool calls — duplicate reads, errored calls, retries, and overwritten writes. Fewer wasted calls means less cost and less complexity. |
| **Error Recovery** | Process | 7% | Score determined by infrastructure errors (rate limits, timeouts) that disrupted the execution. |
| **Docs Quality** | Process | 7% | Score determined by how well the agent used external documentation during the task — whether it looked up valid, relevant sources, successfully retrieved content, and incorporated that information into the implementation rather than discarding it. |
| **Correctness** | Output | 25% | Score determined by whether the generated code imports real packages, calls real methods, and wires components correctly. |
| **Hallucination** | Output | 15% | Score determined by whether the agent invented packages that don't exist or used incorrect SDK variants. |
| **Security** | Output | 10% | Score determined by whether the agent hardcoded secrets, stored tokens insecurely, or committed credentials to source code. |
## Grades
Overall scores map to letter grades:
| Grade | Score range | Description |
| - | - | - |
| A | 90+ | Production-ready with 1–2 minor issues. |
| B | 75–89 | Sound fundamentals with notable gaps. |
| C | 60–74 | Usable but needs significant cleanup. |
| D | 40–59 | Major failures or severe process problems. |
| F | \< 40 | Not useful — faster to start from scratch. |
Grades are calibrated to match developer intuition. A score of 91 should feel like code you'd accept with minimal review. A score of 55 should feel like something that needs real work to fix.
## Result validation
Every grader verifies generated code — not prose or explanations. Graders check that code compiles, imports real packages, calls actual SDK methods, and doesn't introduce security vulnerabilities.
Results are validated at multiple levels:
* **Presence checks**: Required SDK symbols, imports, and config keys exist in the output.
* **Hallucination detection**: Invented packages, wrong SDK variants, and fabricated API methods are caught.
* **Security checks**: Hardcoded credentials, tokens in insecure storage, and secrets in source code are flagged.
* **Structural validation**: Code is correctly wired — right components in right files, lifecycle hooks handled, middleware in the correct order.
* **Version correctness**: The agent uses current APIs, not deprecated patterns (only checked when the agent has access to current docs).
* **Holistic review**: An LLM judge evaluates overall correctness of the implementation.
## Estimated cost and time
The results page displays estimated cost and estimated time for each configuration. These values represent a single eval run with Auth0 MCP + Skills enabled.
### Estimated cost
Cost is calculated from the total tokens consumed during the eval run (input tokens + output tokens) multiplied by the model provider's published per-token pricing. Auth0 does not charge for running evals — the cost reflects what you would pay your model provider for equivalent token usage.
Token pricing varies by model and provider. For current rates, refer to your provider's pricing page:
* [Anthropic (Claude) pricing](https://docs.anthropic.com/en/docs/about-claude/models#model-comparison-table)
* [OpenAI (GPT) pricing](https://openai.com/api/pricing/)
* [Google (Gemini) pricing](https://ai.google.dev/gemini-api/docs/pricing/)
### Estimated time
Time is the wall-clock duration of the eval run from prompt submission to final output. It includes all agent activity: reading files, making tool calls, waiting for API responses, and writing code.
Time may vary based on:
* Model provider API latency and rate limits
* Number of tool calls required (varies by task complexity)
* Network conditions between the eval environment and the model provider
* Provider-side queue depth and load
Time is not normalized across providers. A faster time reflects both model efficiency and provider infrastructure performance.
## Learn more
* [Agent Experience Score](https://auth0.com/agent-experience)
* [Auth0 MCP Server](/docs/get-started/auth0-mcp-server/getting-started-with-auth0-mcp-server)
* [Agent Skills](/docs/quickstart/agent-skills)
# Auth0 Guide
Source: https://auth0.com/docs/get-started/auth0-guide
Ask an AI-powered chatbot questions using natural language to learn about Auth0.
Guide is currently in Early Access and is being rolled out to users in the US Public Cloud region. As Guide may occasionally provide incomplete or inaccurate responses, always [review and validate](#how-does-guide-avoid-ai-hallucinations%3F) them using the provided links. To learn more about Auth0 releases, read [Product Release Stages](/docs/troubleshoot/product-lifecycle/product-release-stages).
Guide is an AI-powered chatbot that answers your questions about Auth0. It sources information from our [Documentation](https://auth0.com/docs), [Blog](https://auth0.com/blog), and [Community](http://community.auth0.com). For Enterprise subscription customers, Guide also leverages Auth0 tenant data from [Security Center](/docs/secure/security-center) to help you monitor, troubleshoot, and implement tenant security best practices.
Guide answers your questions, such as "How do I set up passkeys?" with a summarized answer and links to relevant documentation and [incident playbooks](/docs/secure/attack-protection/playbooks) for tenant and user security.
## How Guide works
Guide processes your message to determine what you’re asking for, searches Auth0 sources for relevant information, then generates a summarized response based on what it found along with links to the referenced materials.
You can ask follow-up questions, [validate its responses](#how-does-guide-avoid-ai-hallucinations%3F) using the provided links, and give feedback on Guide by rating its responses.
For Enterprise subscription customers: If you [configure security monitoring alerts](/docs/secure/security-center/security-alerts) in Security Center, Guide helps you troubleshoot incidents and suggests security guidance from a relevant [incident playbook](/docs/secure/attack-protection/playbooks).
For example, as shown in the following screenshot, when a significant bot surge triggers your Bot Detection alert, Guide recommends remediation steps from the [Bot Detection Attack playbook](/docs/secure/attack-protection/playbooks/bot-detection-playbook), such as activating CAPTCHA for affected authentication flows, and prompts you to inspect relevant events in the tenant logs.
## Use Guide
You can access Guide by selecting the **Ask Guide** button in the top-right corner of the Auth0 Dashboard.
When you select **Ask Guide**, Guide pops up, prompting you to ask about Auth0 features. It may suggest questions relevant to your current location in the Auth0 Dashboard. For example, if you’re under **Branding > Universal Login**, Guide will prompt you with questions about Universal Login, such as:
* What is Universal Login?
* What are the Benefits of Universal Login?
### Questions Guide can answer
Guide can answer questions that relate to the Auth0 product and platform, such as:
* What is Universal Login?
* How do I enable single sign-on integrations?
* How do I set up passkeys?
For Enterprise subscription customers, Guide can answer Auth0 tenant-related questions pertaining to Security Center metrics and data, such as:
* How do I troubleshoot this failed MFA challenge?
* What triggered my bot protection alert threshold?
* What are the remediation steps for a "credential stuffing" alert?
### Questions Guide cannot answer
Guide cannot answer questions that do not relate to the Auth0 product or platform, or are specific to your tenant or configuration, such as:
* What connections do I have enabled?
* How many users logged in to my application last month?
* Which is better? Vim or Emacs?
Do not submit personal or other sensitive data to Guide.
## Disable Guide
You can disable Guide in your tenant by contacting [Auth0 Support](https://support.auth0.com/).
## Data security in Guide
Your messages are safeguarded by Okta’s enterprise-grade security and compliance standards.
Guide does:
* Use provided messages to search public Auth0 sources for relevant information.
Guide does not:
* Access your account or tenant data.
* Use provided messages for LLM training purposes.
* Share your messages with third parties.
## How does Guide avoid AI hallucinations?
Guide builds responses using content authored by Auth0 and includes links to the documents referenced in all responses. You can follow any referenced link to verify the original source data and learn additional information.
# Auth0 Model Context Protocol (MCP) Server Guides
Source: https://auth0.com/docs/get-started/auth0-mcp-server/auth0-mcp-server-guides
Learn about common operations and use cases for Auth0 Model Context Protocol (MCP) Server.
Learn about common operations and use cases for Auth0 Model Content Protocol (MCP) Server. Below are the guides currently available:
# Implement Advanced Security Monitoring with Auth0 Model Context Protocol (MCP) Server
Source: https://auth0.com/docs/get-started/auth0-mcp-server/auth0-mcp-server-guides/implement-advanced-security-monitoring-with-auth0-model-context-protocol-mcp
Leverage Auth0 Model Context Protocol (MCP) Server and Claude to implement a sophisticated security monitoring and automated response system.
Learn how to:
1. Set up advanced log monitoring for security threats
2. Create intelligent security actions that respond to suspicious activities
3. Implement adaptive authentication challenges based on risk assessment
4. Configure automated notifications for security events
5. Fine-tune your security system based on real-world data
1. Create an Auth0 account with administrative access
2. Install Auth0 MCP Server and integrate with Claude Desktop
Leverage [Auth0 MCP Server](/docs/get-started/auth0-mcp-server) and [Claude](https://claude.ai/) to implement a sophisticated security monitoring and automated response system for your Auth0 tenant. Using natural language interactions, you can quickly set up security measures that would typically require complex scripting and dashboard navigation.
### Step 1: Set up advanced log monitoring
The first step in building a security monitoring system is to understand what normal authentication patterns look like in your environment. With Auth0 MCP Server, you can quickly analyze your logs to establish this baseline.
Ask Claude:
```bash wrap lines theme={null}
Analyze my Auth0 logs from the past week to identify normal authentication patterns. Look for common IP ranges, devices, browsers, and time-of-day patterns.
```
Claude will use the `auth0_list_logs` tool to retrieve and analyze your logs. This analysis gives you a baseline understanding of normal authentication patterns, which is essential for identifying anomalies.
### Step 2: Create security detection Actions
Now that you understand normal patterns, you can create Actions that detect suspicious activities. Instead of writing complex code manually, you can describe the security rules in natural language.
Ask Claude:
```bash lines theme={null}
Create an action that detects the following suspicious activities:
1. Multiple failed login attempts within a short time period
2. Logins from unusual geographic locations for a user
3. Logins at unusual times based on the user's history
4. Rapid account switching from the same IP address
```
Claude will use the `auth0_create_action` tool to generate and create an Action with sophisticated detection logic.
### Step 3: Create automated response Actions
After you have detection in place, next you'll need to create Actions that respond to detected threats. These Actions will implement your security policies based on the risk level.
Ask Claude:
```bash lines theme={null}
Create an action that responds to security threats based on risk score:
1. For low risk (score < 30), allow the login but log the event
2. For medium risk (score 30-60), require additional verification like MFA
3. For high risk (score > 60), block the login and notify security team
```
Claude will use the `auth0_create_action` tool again to create a response Action.
### Step 4: Deploy the security Actions
With your security Actions created, you need to deploy them in the correct sequence to ensure they work together properly.
Ask Claude:
```bash wrap lines theme={null}
Deploy the security detection action first, followed by the response action. They should run in sequence during the login flow.
```
Claude will use the `auth0_deploy_action` tool twice to deploy both Actions in the correct order.
### Step 5: Create custom security challenge Forms
For medium-risk logins that require additional verification, you'll want to create a custom [Form](/docs/customize/forms) that explains the situation to the user.
Ask Claude:
```bash wrap lines theme={null}
Create a custom form for additional security verification that explains to the user why additional verification is needed and provides clear instructions.
```
Claude will use the `auth0_create_form` tool to create a custom Form.
## Step 6: Monitor security events
To ensure your security system is working effectively, you need to monitor security events and analyze patterns.
Ask Claude:
```bash wrap lines theme={null}
Show me all high-risk security events from the past 24 hours, and identify any patterns or trends, using score-based categorization.
```
Claude will use the `auth0_list_logs` tool with specific criteria to find security events.
## Step 7: Fine-tune the security system
Based on your monitoring, you may need to fine-tune your security system to reduce false positives or address specific threats.
Ask Claude:
```bash wrap lines theme={null}
Update the security detection action to be more sensitive to logins from Russia and China, and less sensitive to unusual login times for users in the IT department.
```
Claude will use `auth0_get_action` to retrieve the current Action code, then use `auth0_update_action` to modify it. After updating the Action, deploy it with `auth0_deploy_action`.
Ask Claude:
```bash lines theme={null}
Deploy the action to my tenant.
```
## Conclusion
By using Auth0 MCP Server with Claude, you've implemented a sophisticated security monitoring and response system by:
* Setting up advanced threat detection based on user behavior patterns
* Creating intelligent response mechanisms that adapt to different risk levels
* Implementing custom security challenges for suspicious logins
* Establishing a monitoring system to track security events
* Fine-tuning your security rules based on real-world data
This natural language approach not only saves time but also allows you to implement security best practices without deep expertise in Auth0's Actions system or log query syntax.
## Next steps
* Integrate your security system with external threat intelligence feeds
* Implement automated remediation for compromised accounts
* Create security dashboards for real-time monitoring
* Develop custom risk models based on your organization's specific needs
# Streamline API Authorization Flows with Auth0 Model Context Protocol (MCP) Server
Source: https://auth0.com/docs/get-started/auth0-mcp-server/auth0-mcp-server-guides/streamline-api-authorization-flows-with-auth0-model-context-protocol-mcp
Streamline your API authorization flows with Auth0 Model Context Protocol (MCP) Server.
Learn how to:
1. Explore your current API configurations
2. Create new API definitions with appropriate scopes
3. Implement custom authorization logic with Auth0 Actions
4. Deploy and test your authorization system
5. Monitor and refine your authorization rules
1. Create an Auth0 account with administrative access
2. Install Auth0 MCP Server and integrate with Claude Desktop
Use natural language interactions with [Auth0 MCP Server](/docs/get-started/auth0-mcp-server) to quickly set up and manage a comprehensive API authorization system. By leveraging [Claude's](https://claude.ai/) ability to interact with Auth0 through the Model Context Protocol, you can implement complex authorization patterns in minutes instead of hours.
### Step 1: Explore current API configuration
Before creating new APIs, it's important to understand what's already configured in your tenant. With Auth0 MCP Server, you can quickly get this information through natural language.
Ask Claude:
```bash wrap lines theme={null}
Show me all the resource servers (APIs) currently configured in my Auth0 tenant.
```
Claude will use the `auth0_list_resource_servers` tool to retrieve and display your existing APIs. This gives you a quick overview of your API landscape without having to navigate through the Auth0 dashboard.
### Step 2: Create new API definitions
Now that you understand your current configuration, you can create new APIs for your microservices architecture. Instead of configuring each API separately through the dashboard, you can define them all at once.
Ask Claude:
```bash lines theme={null}
I need to create three new APIs for our microservices:
1. An inventory API with read and write scopes
2. An orders API with read and write scopes
3. A customers API with read, write, and admin scopes
Each API should enforce scope validation.
```
Claude will use the `auth0_create_resource_server` tool multiple times to set up these APIs.
### Step 3: Implement authorization logic
After your APIs are defined, you'll need to implement custom authorization logic. With Auth0 MCP Server, you can describe your business rules in natural language and Claude will generate the appropriate Auth0 [Actions](/docs/customize/actions) code.
Ask Claude:
```bash lines theme={null}
Create an Action that enforces the following authorization rules:
1. Verify the requesting application has the appropriate scopes for the API being accessed.
2. For the customers API, requests using the admin scope should only come from our internal IP ranges (10.0.0.0/8 and 172.16.0.0/12).
3. Log all authorization decisions for audit purposes.
```
Claude will use the `auth0_create_action` tool to generate and create an Action with the appropriate code.
### Step 4: Deploy the authorization Action
Once you're satisfied with the Action code, you can deploy it to your production environment with a simple instruction.
Ask Claude:
```bash lines theme={null}
Deploy this action to run during the token issuance process.
```
Claude will use the `auth0_deploy_action` tool to deploy the Action.
### Step 5: Configure client applications
Next, you'll need to configure your client applications to access the appropriate APIs with the correct scopes.
Ask Claude:
```bash wrap lines theme={null}
Create an 'inventory-manager' application on my Auth0 tenant and update the app to access the inventory and orders APIs with read and write permissions, but not the customers API.
```
Claude will first use `auth0_get_application` to retrieve the current configuration, then use `auth0_update_application` to update it.
### Step 6: Verify configuration
To ensure your authorization system is working correctly, you can check the logs for any authorization issues.
Ask Claude:
```bash wrap lines theme={null}
Check the logs for any failed API access attempts in the last hour. Focus on authorization failures.
```
Claude will use `auth0_list_logs` to find relevant log entries.
### Step 7: Refine the authorization rules
Based on the log analysis, you might need to refine your authorization rules. For example, you might need to allow access from additional IP ranges.
Ask Claude:
```bash wrap lines theme={null}
Update the authorization action to also allow requests from our development VPN range 192.168.100.0/24.
```
Claude will use `auth0_get_action` to retrieve the current Action code, then use `auth0_update_action` to modify it.
Finally, Claude will use `auth0_deploy_action` to deploy the updated Action.
### Conclusion
By using Auth0 MCP Server with Claude, you've implemented a comprehensive API authorization system by:
* Creating multiple API definitions with appropriate scopes
* Implementing custom authorization logic with IP-based restrictions
* Configuring client applications to access specific APIs
* Monitoring and refining your authorization rules
This natural language approach not only saves time but also allows you to implement security best practices without deep expertise in Auth0's Actions system or log query syntax.
## Next steps
* Implement additional authorization rules based on user attributes
* Set up regular log monitoring for security analysis
* Create custom dashboards to visualize API usage patterns
# Understanding Scopes
Source: https://auth0.com/docs/get-started/auth0-mcp-server/auth0-mcp-server-guides/understanding-scopes
Learn which management scopes are required for each Auth0 MCP Server tool and how to configure them using glob patterns during initialization.
For security purposes, the Auth0 Model Context Protocol server grants no scopes by default and required scopes must be requested during initialization. After your server is initialized, you can manually set scopes using a glob pattern, an example of which is below:
```bash lines theme={null}
# Select all read scopes
npx @auth0/auth0-mcp-server init --scopes 'read:*'
# Select multiple scope patterns (comma-separated)
npx @auth0/auth0-mcp-server init --scopes 'read:*,create:clients,update:actions'
```
Depending on the type of management operation or tool you wish to use, you may need to request additional scopes to successfully execute the MCP operation on your client. Below are the available scopes.
| Management Operation | MCP Tool | Required Scope | Potential Implications |
| - | - | - | - |
| Get details about a specific Auth0 application | `auth0_get_application` | `read:clients` | Allows viewing potentially sensitive application configuration details |
| Create a new Auth0 application | `auth0_create_application` | `create:clients` | Enables creating new applications that could be used for authentication flows |
| Update an existing Auth0 application | `auth0_update_application` | `update:clients` | Can modify critical application settings, potentially disrupting authentication for users |
| Create a client grant for an application | `auth0_create_application_grant` | `create:client_grants` | Authorizes an application to access an API, enabling machine-to-machine authentication flows |
| Save application credentials to a file | `auth0_save_credentials_to_file` | `read:client_credentials` | Allows reading application client credentials to save them to a local environment file |
| List all resource servers (APIs) in the Auth0 tenant | `auth0_list_resource_servers` | `read:resource_servers` | Exposes all API configurations and their scopes |
| Get details about a specific Auth0 resource server | `auth0_create_resource_server` | `create:resource_servers` | Reveals API configuration details including signing algorithms and token settings |
| Create a new Auth0 resource server (API) | `auth0_get_resource_server` | `read:resource_servers` | Allows defining new APIs and scopes that could be used for access control |
| Update an existing Auth0 resource server (API) | `auth0_update_resource_server` | `update:resource_servers` | Can modify API configurations, potentially affecting applications that rely on those APIs |
| List all actions in the Auth0 tenant | `auth0_list_actions` | `read:actions` | Reveals all custom code that runs during authentication flows |
| Get details about a specific Auth0 action | `auth0_get_action` | `read:actions` | Exposes custom code and logic for authentication flows |
| Create a new Auth0 action | `auth0_create_action` | `create:actions` | Allows creation of custom code that can modify authentication flows and user data |
| Update an existing Auth0 action | `auth0_update_action` | `update:actions` | Can modify custom code that affects authentication security and behavior |
| Deploy an Auth0 action | `auth0_deploy_action` | `update:actions` | Pushes custom code into production, potentially affecting all users' authentication experience |
| List logs from the Auth0 tenant | `auth0_list_logs` | `read:logs` | Exposes detailed information about user activity, failed logins, and security events |
| Get a specific log entry by ID | `auth0_get_log` | `read:logs` | Provides detailed data about specific authentication events, potentially including PII |
| List all forms in the Auth0 tenant | `auth0_list_forms` | `read:forms` | Reveals custom form configurations for login, registration, and password reset |
| Get details about a specific Auth0 form | `auth0_get_form` | `read:forms` | Exposes detailed form configuration including field validation and design |
| Create a new Auth0 form | `auth0_create_form` | `create:forms` | Allows creation of custom authentication forms that collect user data |
| Update an existing Auth0 form | `auth0_update_form` | `update:forms` | Can modify user-facing forms, potentially affecting authentication experience |
# Auth0 Model Context Protocol (MCP) Server Tools Reference
Source: https://auth0.com/docs/get-started/auth0-mcp-server/auth0-mcp-tools-reference
Reference guide for all tools available in the Auth0 MCP Server, including operations for applications, APIs, actions, logs, and forms.
Consult this reference guide for natural language examples that enable you to interact with your Auth0 tenant using Auth0 MCP Server and any [MCP Client](https://modelcontextprotocol.io/clients).
## Application management
| Tool | Description | Natural language examples |
| - | - | - |
| `auth0_list_applications` | List all applications in the Auth0 tenant or search by name. | "Show me all my Auth0 applications."
"Find applications with 'api' in their name."
"What applications do I have in my Auth0 tenant?" |
| `auth0_get_application ` | Get details about a specific Auth0 application. | "Show me details for the application called 'Customer Portal'."
"Get information about my application with client ID ."
"What are the callback URLs for my 'Mobile App'?" |
| `auth0_create_application ` | Create a new Auth0 application. | "Create a new single-page application called 'Analytics Dashboard'."
"Set up a new native mobile app called 'iOS Client'."
"Create a machine-to-machine application for our background service." |
| `auth0_update_application` | Update an existing Auth0 application. | "Update the callback URLs for my 'Web App' to include `https://staging.example.com/callback`."
"Change the logout URL for the 'Customer Portal'."
"Add development environment metadata to my 'Admin Dashboard' application." |
| `auth0_create_application_grant` | Create a client grant authorizing an application to access an API with specified scopes. | "Authorize my 'Background Service' app to access the 'Inventory API'."
"Grant my machine-to-machine app access to the user management API."
"Set up client credentials access for my backend service to the payments API." |
## Resource server (API) management
| Tool | Description | Natural language examples |
| - | - | - |
| `auth0_list_resource_servers` | List all resource servers (APIs) in the Auth0 tenant. | "Show me all the APIs in my Auth0 tenant."
"List my resource servers."
"What APIs have I configured in Auth0?" |
| `auth0_get_resource_server` | Get details about a specific Auth0 resource server. | "Show me details for the 'User API'."
"What scopes are defined for my 'Payment API'?"
"Get information about the resource server with identifier `https://api.example.com`." |
| `auth0_create_resource_server` | Create a new Auth0 resource server (API). | "Create a new API called 'Inventory API' with read and write scopes."
"Set up a resource server for our customer data API."
"Create an API with the identifier `https://orders.example.com`." |
| `auth0_update_resource_server` | Update an existing Auth0 resource server. | "Add an 'admin' scope to the 'User API'."
"Update the token lifetime for my 'Payment API' to 1 hour."
"Change the signing algorithm for my API to RS256." |
## Actions management
| Tool | Description | Natural language examples |
| - | - | - |
| `auth0_list_actions` | List all Actions in the Auth0 tenant. | "Show me all my Auth0 Actions."
"What Actions do I have configured?"
"List the Actions in my tenant." |
| `auth0_get_action` | Get details about a specific Auth0 Action. | "Show me the code for my 'Enrich User Profile' Action."
"Get details about my login flow Action."
"What does my 'Add Custom Claims' Action do?" |
| `auth0_create_action` | Create a new Auth0 Action. | "Create an Action that adds user roles to tokens."
"Set up an Action to log failed login attempts."
"Create a post-login Action that checks user location." |
| `auth0_update_action` | Update an existing Auth0 Action. | "Update my 'Add Custom Claims' Action to include department information."
"Modify the IP filtering logic in my security Action."
"Fix the bug in my user enrichment Action." |
| `auth0_deploy_action` | Deploy an Auth0 Action. | "Deploy my 'Add Custom Claims' Action to production."
"Make my new security Action live."
"Deploy the updated user enrichment Action." |
## Logs management
| Tool | Description | Natural language examples |
| - | - | - |
| `auth0_list_logs` | List logs from the Auth0 tenant | "Show me recent login attempts."
"Find failed logins from the past 24 hours."
"Get authentication logs from yesterday."
"Show me successful logins for user [john@example.com](mailto:john@example.com)." |
| `auth0_get_log` | Get a specific log entry by ID. | "Show me details for log entry ."
"Get more information about this failed login attempt."
"What caused this authentication error?" |
## Forms management
| Tool | Description | Natural language examples |
| - | - | - |
| `auth0_list_forms` | List all Forms in the Auth0 tenant. | "Show me all my Auth0 Forms."
"What login Forms do I have configured?"
"List the custom Forms in my tenant." |
| `auth0_get_form` | Get details about a specific Auth0 Form. | "Show me the details of my 'Corporate Login' Form."
"What does my password reset Form look like?"
"Get the configuration for my signup Form." |
| `auth0_create_form` | Create a new Auth0 Form. | "Create a new login Form with our company branding."
"Set up a custom signup Form that collects department information."
"Create a password reset Form with our logo." |
| `auth0_update_form` | Update an existing Auth0 Form. | "Update the colors on our login Form to match our new brand guidelines."
"Add a privacy policy link to our signup Form."
"Change the logo on our password reset Form." |
## Combining Operations
You can also ask [Claude](https://claude.ai/) to perform multiple related operations in sequence:
#### Set up a new API with client access
```bash wrap lines theme={null}
Create a new API called "Inventory API" with read and write scopes, then update my "Admin Dashboard" application to have access to it.
```
#### Create and deploy a security Action
```bash wrap lines theme={null}
Create an Action that requires MFA for users logging in from outside our corporate network, then deploy it to the login flow.
```
#### Analyze security events
```bash wrap lines theme={null}
Show me all failed login attempts from the past week, and identify any patterns or suspicious activity.
```
#### Updating branding across forms
```bash wrap lines theme={null}
Update all our Auth0 forms to use our new logo at and change the primary color to #0066CC.
```
## Best Practices
1. Be specific in your requests: Include names, IDs, or other identifying information when referring to specific resources.
2. Use natural language: You don't need to memorize tool names or parameters; simply describe what you want to accomplish.
3. Review before confirming: When Claude suggests changes, review them carefully before confirming.
4. Start simple: Begin with simple queries to get familiar with how Claude interprets your requests.
## Troubleshooting
If Claude is unable to perform an operation, consider the following:
1. Authentication: Ensure you're logged in with the Auth0 CLI (`auth0 login`).
2. Permissions: Verify your account has the necessary permissions in Auth0.
3. Specificity: Try to be more specific in your request.
# Getting Started with Auth0 Model Context Protocol (MCP) Server
Source: https://auth0.com/docs/get-started/auth0-mcp-server/getting-started-with-auth0-mcp-server
Integrate Auth0 Model Context Protocol (MCP) Server with your AI clients.
* Install [Node.js v18 or higher](https://nodejs.org/en/download) on your system.
* Create an active [Auth0 account](https://auth0.com/)with administrative permissions.
* Install at least one supported MCP client ([Claude Desktop](https://claude.ai/download), [Cursor](https://www.cursor.com/downloads), [Windsurf](https://www.windsurf.com/editor), [VS Code](https://code.visualstudio.com/download), [Claude Code](https://claude.ai/download), or [Gemini CLI](https://github.com/google-gemini/gemini-cli), for example).
Empower your team and your users by installing [Auth0 Model Context Protocol (MCP) Server](/docs/get-started/auth0-mcp-server) and integrating with several commonly-used [MCP clients](https://modelcontextprotocol.io/clients).
## Installation and configuration
Install Auth0 MCP Server by running one of these commands in your terminal:
### For Claude Desktop (default)
```bash lines theme={null}
npx @auth0/auth0-mcp-server init
```
### For Cursor
```bash lines theme={null}
npx @auth0/auth0-mcp-server init --client cursor
```
### For Windsurf
```bash lines theme={null}
npx @auth0/auth0-mcp-server init --client windsurf
```
### For VS Code
```bash lines theme={null}
npx @auth0/auth0-mcp-server init --client vscode
```
You will be prompted to choose a configuration scope:
* **Global**: Available in all VS Code instances.
* **Workspace**: Available only in a specific project or repository.
The command automatically configures the appropriate `mcp.json` file based on your selection.
### For Claude Code
```bash lines theme={null}
npx @auth0/auth0-mcp-server init --client claude-code
```
You will be prompted to choose a configuration scope:
* **User**: Written to `~/.claude.json` and available across all your projects.
* **Project**: Available only in the current project.
### For Gemini CLI
```bash lines theme={null}
npx @auth0/auth0-mcp-server init --client gemini
```
### Other MCP clients
To use Auth0 MCP Server with any other MCP Client, you can manually add this configuration to the client and restart for changes to take effect:
```json lines theme={null}
{
"mcpServers": {
"auth0": {
"command": "npx",
"args": ["-y", "@auth0/auth0-mcp-server", "run"],
"capabilities": ["tools"],
"env": {
"DEBUG": "auth0-mcp"
}
}
}
}
```
## Authenticate with Auth0
Your browser will automatically open to initiate the OAuth 2.0 device authorization flow. Log into your Auth0 account and grant the requested permissions.
Credentials are securely stored in your system's keychain. You can optionally verify storage through your keychain management tool.
## Verify your integration
### Claude Desktop
1. Restart Claude Desktop to ensure it recognizes the newly installed Auth0 MCP Server.
2. In Claude Desktop, click on the **Tools** icon and verify that Auth0 tools (for example, `auth0_create_action` or `auth0_delete_application`) show up in the **Available MCP Tools** list.
3. Begin a conversation with Claude Desktop and ask help managing your Auth0 tenant.
### Cursor
1. Restart Cursor to ensure it recognizes the newly installed Auth0 MCP Server.
2. In Cursor, open **Settings > MCP** and verify that **Auth0** appears in the **MCP Servers** list.
3. Begin a conversation with Cursor and ask for help managing your Auth0 tenant.
### Windsurf
1. Restart Windsurf to ensure it recognizes the newly installed Auth0 MCP Server.
2. In Windsurf, open **Windsurf Settings > Cascade** and verify that **Auth0** appears in the **Model Context Protocol (MCP) Servers** list.
3. Begin a conversation with Windsurf and ask for help managing your Auth0 tenant.
### VS Code
1. Restart VS Code to ensure it recognizes the newly installed Auth0 MCP Server.
2. In VS Code, open Copilot Chat in agent mode and verify that Auth0 tools are available.
3. Begin a conversation and ask for help managing your Auth0 tenant.
### Claude Code
1. Restart Claude Code to ensure it recognizes the newly installed Auth0 MCP Server.
2. Verify that Auth0 tools (for example, `auth0_create_action` or `auth0_list_applications`) are available in your session.
3. Begin a conversation with Claude Code and ask for help managing your Auth0 tenant.
### Gemini CLI
1. Restart Gemini CLI to ensure it recognizes the newly installed Auth0 MCP Server.
2. Begin a conversation with Gemini CLI and ask for help managing your Auth0 tenant.
## Common troubleshooting steps
Most connection issues can be resolved by configuring the Auth0 MCP server and restarting the MCP client.
#### Get command line help:
View a list of supported commands and usage examples with:
```bash lines theme={null}
npx @auth0/auth0-mcp-server help
```
#### Authentication issues
Ensure correct permissions in your Auth0 tenant and try re-initializing with:
```bash lines theme={null}
npx @auth0/auth0-mcp-server init
```
#### Connection failures:
1. Confirm the MCP server is actively running with:
```ps lines theme={null}
ps aux | grep auth0-mcp
```
2. Restart your AI client after verifying the server is running.
#### Claude Can't Connect to the Server error:
1. Restart Claude Desktop after installation.
2. Check that the server is running with:
```ps lines theme={null}
ps aux | grep auth0-mcp
```
#### API errors:
Check your Auth0 token permissions and expiration. Enable debug mode (see below) to view detailed logs.
## Debug configuration issues
#### Enable debug mode
Enable debug mode to view detailed logs:
```bash lines theme={null}
export DEBUG=auth0-mcp
```
#### Debug client logs
Get detailed MCP client logs from Claude Desktop:
```bash lines theme={null}
# Follow logs in real-time
tail -n 20 -F ~/Library/Logs/Claude/mcp*.log
```
Get detailed MCP server logs by running the Auth0 MCP Server in debug mode:
```bash lines theme={null}
DEBUG=auth0-mcp npx @auth0/auth0-mcp-server run
```
#### Advanced debugging using MCP Inspector
For advanced troubleshooting, use the MCP Inspector:
```bash wrap lines theme={null}
npx @modelcontextprotocol/inspector -e DEBUG='auth0-mcp' @auth0/auth0-mcp-server run__text in bold__
```
## Next steps
Explore the full capabilities of Auth0 MCP Server by visiting our [Auth0 Model Context Protocol (MCP) Server Tools Reference](/docs/get-started/auth0-mcp-server/auth0-mcp-tools-reference), or check out our Auth0 Model Context Protocol Server Guides for practical examples and use cases.
# Auth0 Overview
Source: https://auth0.com/docs/get-started/auth0-overview
Describes Auth0 services and helps you get started using them with your applications and APIs.
Auth0 is a flexible, drop-in solution to add authentication and authorization services to your applications. Your team and organization can avoid the cost, time, and risk that come with building your own solution to authenticate and authorize users.
Take a look at just a few of Auth0's use cases:
* You built an awesome app and you want to add user authentication and authorization. Your users should be able to log in either with an identifier (username, email, or phone number) and password or with their social accounts (such as Facebook or X). You want to retrieve the user's profile after the login so you can customize the UI and apply your authorization policies.
* You built an API and you want to secure it with [OAuth 2.0](/docs/authenticate/protocols/oauth).
* You have more than one app, and you want to implement [Single Sign-on (SSO)](/docs/authenticate/single-sign-on).
* You built a JavaScript front-end app and a mobile app, and you want them both to securely access your API.
* You have a web app that needs to authenticate users using [Security Assertion Markup Language (SAML)](/docs/authenticate/protocols/saml/saml-configuration).
* You believe passwords are broken and you want your users to log in with one-time codes delivered by email or SMS.
* If one of your user's email addresses is compromised in some site's public data breach, you want to be notified, and you want to notify the users and/or block them from logging in to your app until they reset their password.
* You want to act proactively to block suspicious IP addresses if they make consecutive failed login attempts, in order to avoid DDoS attacks.
* You are part of a large organization that wants to federate your existing enterprise directory service to allow employees to log in to the various internal and third-party applications using their existing enterprise credentials.
* You don't want (or you don't know how) to implement your own user management solution. Password resets, creating, provisioning, blocking, and deleting users, and the UI to manage all these. You just want to focus on your app.
* You want to enforce [multi-factor authentication (MFA)](/docs/secure/multi-factor-authentication) when your users want to access sensitive data.
* You are looking for an identity solution that will help you stay on top of the constantly growing compliance requirements of SOC2, GDPR, PCI DSS, HIPAA, and others.
* You want to monitor users on your site or application. You plan on using this data to create funnels, measure user retention, and improve your sign-up flow.
* You want robust authorization policy to allow your users access to resources based on [their relationship](https://docs.fga.dev/authorization-concepts) to the resource or [their role](/docs/manage-users/access-control/rbac) in your organization.
| Read... | To learn... |
| - | - |
| [Auth0 Dashboard](/docs/get-started/auth0-overview/dashboard) | About the Auth0 Dashboard and features you can access to implement authentication and authorization with your applications and APIs. |
| [Create Tenants](/docs/get-started/auth0-overview/create-tenants) | How to create tenants using the Auth0 Dashboard or the Management API, explore creating multiple tenants and child tenants, and learn about setting up multiple environments. |
| [Create Applications](/docs/get-started/auth0-overview/create-applications) | How to set up and configure applications in the Auth0 Dashboard. |
| [Register APIs](/docs/get-started/auth0-overview/set-up-apis) | How to set up and configure APIs in the Auth0 Dashboard. |
## Learn more
* [Create Tenants](/docs/get-started/auth0-overview/create-tenants)
* [Auth0 Dashboard](/docs/get-started/auth0-overview/dashboard)
* [Architecture Scenarios](/docs/get-started/architecture-scenarios)
* [Protocols](/docs/authenticate/protocols)
# Create Tenants
Source: https://auth0.com/docs/get-started/auth0-overview/create-tenants
Describes how to create a tenant and learn the basics of Auth0 and familiarize yourself with the terminology.
We will walk through the initial steps of getting started using Auth0 to familiarize you with the key concepts of the Auth0 service. We will use the company **Example-Co** to help describe some of the steps involved.
## Set up an Auth0 account
If you haven't already [signed up](https://auth0.com/signup) for an Auth0 **account**, do so (it's free). You can either use username/email/phone and password or log in with a social provider (such as LinkedIn, Microsoft, GitHub, or Google).
## Create a tenant and domain
Once you create your account you will be asked to create a **tenant**. Everything starts with an Auth0 tenant. This is where you configure your use of Auth0, and then where Auth0 assets - such as [applications](/docs/get-started/applications), [connections](/docs/authenticate/identity-providers), and [user profiles](/docs/get-started/architecture-scenarios/business-to-business/profile-management) - are defined, managed and stored. You access an Auth0 tenant via the Auth0 [Dashboard](/docs/get-started/auth0-overview/dashboard), where you can also create additional, associated tenants. You can create more than one Auth0 tenant so that you can structure your tenants in a way that will isolate different domains of users and also support your Software Development Life Cycle (SDLC).
**Tenant names cannot be changed or reused once deleted.** So, make sure you're happy with the name(s) before you create your Auth0 tenants.
Determining the level of isolation you require when it comes to your user domains is an important step, and together with your branding requirements helps you determine the number of Auth0 tenants needed in your environment. The number of Auth0 tenants you need to manage can quickly grow so consider carefully before creating multiple Auth0 tenants for production.
Tenant characteristics:
* The tenant name has to be unique. It will be used to create your personal domain.
* The tenant name can contain only lowercase alphanumeric characters and hyphens ("-"). It cannot begin or end with a hyphen.
* The tenant name must be a minimum of 3 characters and a maximum of 63 characters.
* The tenant name cannot be changed after creation.
* You can create more than one tenant; in fact, you are encouraged to do so for each environment you may have such as development, staging, or production. To learn more, read [Set Up Multiple Environments](/docs/get-started/auth0-overview/create-tenants/set-up-multiple-environments).
The name of your tenant is part of your Auth0 domain. You can customize this by using a custom domain. This domain is the base URL used to access the Auth0 API and the URL where your users authenticate.
### Region, locality, and sub-locality
The domain name is also made up of the locality value from a **region**. We support the following locality values for the [public cloud deployment option](/docs/deploy-monitor/deployment-options):
| Region | Locality | Sub-localities |
| - | - | - |
| Australia | AU | AU |
| Canada | CA | CA |
| Europe | EU | EU, EU-2 |
| Japan | JP | JP |
| United Kingdom | UK | UK |
| United States of America | US | US, US-3, US-4, US-5 |
Each of these localities is separated into a sub-locality (or **tenant environment**) with a digit after the locality, e.g. `EU-2`. Tenant environments cannot be chosen manually, but localities based on the selected region may be specified, which control the assigned tenant domain and the region where your data will be hosted.
In our example, **Example-Co** chose the name `example-co` and AU as their region. So their domain is `example-co.au.auth0.com`.
## Custom domains
We recommend the use of custom domains, such as `example-co.com`, in production environments to provide your users with the most secure and seamless experience.
Custom domain certificates can be managed by Auth0 or self-managed by you.
To learn more, read [Custom Domains](/docs/customize/custom-domains).
## What's next
* **Create and register applications**: Now that you have an account and a domain, you need to register each application that will use our services in the [Auth0 Dashboard](https://manage.auth0.com/#/applications). To learn more, read [Applications in Auth0](/docs/get-started/applications) and [Create Applications](/docs/get-started/auth0-overview/create-applications).
* **Set up connections**: Next, you need to set up how your users will authenticate during log in. Auth0 sits between your app and the identity provider that authenticates your users (such as Google or Facebook). The relationship between Auth0 and the identity provider is referred to as a **connection**. By using this connection layer, Auth0 keeps your app isolated from any changes that occur with the identity provider's implementation. To learn more, read [Authentication and Authorization](/docs/get-started/identity-fundamentals/authentication-and-authorization) and [Connections](/docs/authenticate/identity-providers).
## Extend Auth0's functionality
Auth0 offers several ways to extend the platform's functionality:
* [Actions](/docs/customize/actions): Actions are secure, tenant-specific, versioned functions written in Node.js that execute at certain points within the Auth0 platform. Use Actions to customize and extend Auth0's capabilities with custom login.
* [Rules](/docs/customize/rules): Rules are functions written in JavaScript or C#, that are executed in Auth0 just after successful authentication and before control returns to your app. Rules can be chained together for modular coding and can be turned on and off individually. You can use Rules for:
* Access control
* Webhooks
* Profile enrichment
* Multi-factor authentication (MFA)
* [Hooks](/docs/customize/hooks): Hooks allow you to customize the behavior of Auth0 using Node.js code that is executed against extensibility points (which are comparable to webhooks that come with a server). They are secure, self-contained functions associated with specific extensibility points of the Auth0 platform. Auth0 invokes the Hooks at runtime to execute your custom logic.
* [Extensions](/docs/customize/extensions): Auth0 Extensions enable you to install applications or run commands/scripts that extend the functionality of the Auth0 base product. You can either use one of the pre-defined extensions, provided by Auth0, or create your own. Some of the actions you can do with extensions include:
* Manage the authorizations for users (using groups, roles, and permissions)
* Import/export users
* Export logs to other services
* Deploy scripts from external repositories
## Learn more
* [Tenant Settings](/docs/get-started/tenant-settings)
* [Create Multiple Tenants](/docs/get-started/auth0-overview/create-tenants/create-multiple-tenants)
* [Link Multiple Tenants to a Single Subscription](/docs/get-started/auth0-overview/create-tenants/child-tenants)
* [Set Up Multiple Environments](/docs/get-started/auth0-overview/create-tenants/set-up-multiple-environments)
# Link Multiple Tenants to a Single Subscription
Source: https://auth0.com/docs/get-started/auth0-overview/create-tenants/child-tenants
Learn how to request linking of multiple tenants under a single Auth0 subscription.
Auth0 offers the ability for customers with an Enterprise subscription to link multiple tenants under a single Auth0 subscription (these linked tenants can also be referred to as child tenants).
This feature can be useful under the following situations:
* Separate development and production tenants while keeping the same feature access on development tenants as available in production tenants
* Own more than one production tenant under a single Enterprise subscription
## Linking tenants
An Enterprise subscription automatically allows users to link tenants under an existing Auth0 subscription by selecting the **Custom Agreement** option from the **Create Under** dropdown when creating new tenants.
If you need to link previously created tenants that are not currently part of your Enterprise subscription, contact your account team or open a ticket with [Auth0 Support](https://support.auth0.com).
If you have a self-service subscription (not Enterprise), you can still link tenants. To learn more, read [Tenant Management](/docs/get-started/auth0-teams/tenant-management).
## Usage consolidation
Usage from all linked tenants counts toward your Enterprise subscription limits. You can view aggregated usage across all linked tenants in your usage and quota reports.
## Learn more
* [Create Multiple Tenants](/docs/get-started/auth0-overview/create-tenants/create-multiple-tenants)
* [Delete or Reset Tenants](/docs/troubleshoot/customer-support/manage-subscriptions/delete-or-reset-tenant)
* [Set Up Multiple Environments](/docs/get-started/auth0-overview/create-tenants/set-up-multiple-environments)
# Create Multiple Tenants
Source: https://auth0.com/docs/get-started/auth0-overview/create-tenants/create-multiple-tenants
Describes how to create an additional tenant using the Auth0 Dashboard.
You can configure multiple tenants to create [different environments](/docs/get-started/auth0-overview/create-tenants/set-up-multiple-environments) in the Auth0 Dashboard to allow for complex configurations. For example, you could have two separate domains (one internal and one public-facing), or you may want users to log in differently for different applications. The way to accomplish this is to create more than one Auth0 tenant to allow you to have separate sets of applications, connections, and users for the applications and groups of users that you need to support.
1. Go to the [Auth0 Dashboard](https://manage.auth0.com/#/), select your tenant name, and select **Create Tenant**.
2. Enter your desired **Tenant Domain**, select a **Region**, and select **Create**.
## Learn more
* [Multiple Organization Architecture](/docs/get-started/architecture-scenarios/multiple-organization-architecture)
* [Set Up Multiple Environments](/docs/get-started/auth0-overview/create-tenants/set-up-multiple-environments)
* [Delete or Reset Tenants](/docs/troubleshoot/customer-support/manage-subscriptions/delete-or-reset-tenant)
* [Multi-Tenant Applications Best Practices](/docs/get-started/auth0-overview/create-tenants/multi-tenant-apps-best-practices)
* [Tenant Settings](/docs/get-started/tenant-settings)
# Multi-Tenant Applications Best Practices
Source: https://auth0.com/docs/get-started/auth0-overview/create-tenants/multi-tenant-apps-best-practices
Describes best practices for how to use Auth0 to secure your multi-tenant applications.
Multi-tenancy is an architectural approach featuring a single instance of software that runs on a server and is accessible by multiple groups of users. With multi-tenancy, you can segment users with shared characteristics into groups and grant them separate permissions and levels of access to your application. This allows you to create and maintain tailored experiences for different customers, business units, or other defined groups of users.
In Auth0, the best method for implementing multi-tenancy is [Auth0 Organizations](/docs/manage-users/organizations/organizations-overview). If necessary, other legacy solutions can be used to accommodate distinct business use cases. If you offer a [business-to-business (B2B)](/docs/get-started/architecture-scenarios/business-to-business) product or service, setting up multi-tenancy for your business users may be beneficial for your use case.
The sections below outline the options available for implementing multi-tenancy in Auth0.
This article uses the software architecture term "tenant" to refer to a group of users who can access your application. When referring to your Auth0 instance, the term "Auth0 tenant" is used.
## Auth0 Organizations
For most multi-tenant use cases, Auth0 Organizations is the ideal solution for you and your users. Auth0 Organizations supports business-to-business (B2B) implementations that have one or more applications that end-users can access.
Common features of B2B implementations include:
* A product that is licensed to another business for use by their employees.
* Multiple organizations that require their own federation and lightweight branding of the authentication experience.
* Separate levels of application access for different groups of users.
With Auth0 Organizations, you can create unique groups of users and tailor their experiences with [role-based access control](/docs/manage-users/access-control/rbac), [customized login pages and email templates](/docs/manage-users/organizations/create-first-organization#customize-prompts-and-email-templates), and more.
To learn more about using Auth0 Organizations to implement multi-tenancy, review [Multiple Organization Architecture](/docs/get-started/architecture-scenarios/multiple-organization-architecture).
## Legacy solutions
If Auth0 Organizations does not satisfy the requirements of your use case, you may consider the legacy solutions outlined below. For guidance on selecting the best approach for your specific requirements, please reach out to our [Professional Services](/docs/get-started/professional-services) team.
Legacy solutions include:
* Using an Auth0 connection to represent each tenant.
* Using an Auth0 application to represent each tenant.
* Using an Auth0 tenant to represent each tenant.
* Storing tenant details in the user's profile.
### Use Auth0 connections
Entity limits may apply. To learn more, read [Entity Limit Policy](/docs/troubleshoot/customer-support/operational-policies/entity-limit-policy). If you have an Enterprise subscription, you will not be constrained due to entity limits, but you may be constrained by a connection that already has thousands of enabled clients.
You can represent each of your tenants with a separate Auth0 connection.
This approach allows you to support scenarios where:
* You have different connection-level requirements, such as varying password policies, for each of your tenants.
* You have user pools from different connections. For example, one tenant could require users to provide username/password credentials, while another tenant could require users to log in through an enterprise IdP.
To prompt a user to log in through a specific connection, call the [Auth0 Authentication API Login endpoint](https://auth0.com/docs/api/authentication#login), and include the `connection` parameter.
If you use [Lock](/docs/libraries#lock) in your application, note that it supports a maximum of 50 database connections per application. Social and enterprise connections are not affected by this limit, but are still subject to the [Entity Limit Policy](/docs/troubleshoot/customer-support/operational-policies/entity-limit-policy).
### Use Auth0 applications
Entity limits may apply. To learn more, read [Entity Limit Policy](/docs/troubleshoot/customer-support/operational-policies/entity-limit-policy). If you have an Enterprise subscription, you will not be constrained due to entity limits, but you may be constrained by a connection that already has thousands of enabled clients.
You can represent each of your tenants with a separate Auth0 application.
This approach allows you to uniquely configure each Auth0 application based on varying tenant requirements, such as available connections.
You'll need to track the tenants to which your users belong within your application. When a user logs into your application, you'll need to read that information and direct the user to the appropriate Auth0 application to complete authentication.
To enable a connection for multiple applications with the Auth0 Management API, call the [Update enabled clients for a connection endpoint](https://auth0.com/docs/api/management/v2/connections/patch-clients), and pass the relevant connection ID.
### Use Auth0 tenants
You can represent each of your tenants with a separate Auth0 tenant.
This approach allows you to share access to the Auth0 Dashboard with users, restricted by tenant, but requires you to configure Auth0 individually for each tenant.
This means that, in addition to managing the features of each Auth0 tenant individually (such as Branding, Actions, and Attack Protection), your application will have to support multiple Auth0 configurations.
### Store tenant details in the user's profile
You can store tenant details in the user's profile and have your application read that information after the user logs in.
This approach allows all of your users, regardless of which tenant they belong to, to log in using a uniform configuration (such as available connections).
To implement this, you could store tenant details in the user's Auth0 profile in the [`app_metadata` object](/docs/manage-users/user-accounts/metadata), using an identifier of your choice (for example, `"tenant": "customer-group-12345"`). After the user logs in, your application retrieves the `tenant` variable, and then displays a version appropriate to the returned value.
# Set Up Multiple Environments
Source: https://auth0.com/docs/get-started/auth0-overview/create-tenants/set-up-multiple-environments
Describes how to use multiple Auth0 tenants to manage various environments.
Development, staging, and production environments are easy to set up in Auth0. Simply create a new tenant for each environment to guarantee isolation between them. You can easily switch between tenants using the tenant chooser from the top left menu on the Dashboard. You can also configure different administrators for each.
Production [rate limits](/docs/troubleshoot/customer-support/operational-policies/rate-limit-policy) only apply to tenants tagged as `Production`. Ensure your tenant's environment tag is set to `Production` before going live, and note the differences between rate limits for different tenants, environments, and fee structures.
You can name your multiple environments any way you prefer. For production environments, we strongly recommend using [custom domains](/docs/customize/custom-domains).
If you have an Enterprise subscription plan, you can create child tenants by [linking multiple tenants to a single subscription](/docs/get-started/auth0-overview/create-tenants/child-tenants); child tenants each gain access to the paid or upgraded features associated with the subscription. You can ensure your development, staging, or testing environments have access to the same features as your production environment by linking them all to the same Enterprise subscription.
## Tag the environment
For each new tenant created, you should specify its environment. You can assign Environment Tags to your tenants to differentiate between development, staging, and production environments.
If your tenant is mixed use, choose the higher environment. For example, a tenant used for both development and production should be set to **Production**.
1. To assign an Environment Tag to a tenant, go to the [Dashboard > Settings > General](https://manage.auth0.com/#/tenant/general).
2. Under **Assign Environment Tag**, identify your tenant's environment as **Development**, **Staging**, or **Production**.
3. After selecting the environment, click **Save**.
## Migration
Through the [Management API v2](https://auth0.com/docs/api/management/v2), you can automate the migration of assets ([rules](/docs/customize/rules), database [connections](/docs/authenticate/identity-providers), and so forth) between tenants.
For easier configuration management, save your configuration values in the [Dashboard](https://manage.auth0.com/#/rules), instead of hardcoding them into your **rules** or **db connections** scripts.
For example, let's say you want to set a URL for logs. One way to do it is to hardcode it in the rule:
```javascript lines theme={null}
function(user, context, callback){
var log_url = 'https://someurl/log';
...
}
```
This code, however, is not portable since this URL will likely change from development to production.
The recommended way of working with code that you need to use/move from development to product is via [Rules](https://manage.auth0.com/#/rules) section. If you have not yet created a rule, you'll need to do so. (Otherwise, jump to step 4.)
1. Click **Create Your First Rule**.
2. Choose the **empty rule** template.
3. Enter a name for your new rule, and click **Save**.
4. Go to [Dashboard > Rules](https://manage.auth0.com/#/rules), and scroll to the bottom of the page to set your configuration values (we will use `log_url` for the key name, and `https://someurl/log` for value), then click **Create**.
5. Now, you can write your rule. Edit the rule you created, enter the following code in the code area, and click **Save**.
```javascript lines theme={null}
function(user, context, callback){
var log_url = configuration.log_url;
...
}
```
This code is portable, and when you migrate to production, you only need to change this setting instead of searching your scripts.
## AD/LDAP Connectors
If you use multiple Auth0 tenants with AD/LDAP, you will need to create an AD/LDAP Connection and set up an AD/LDAP Connector for each tenant. This is because each AD/LDAP Connector is tied to a specific Connection within an Auth0 tenant.
Multiple AD/LDAP Connectors can point to the same AD or LDAP directory, but each AD/LDAP Connector can only be used by one Connection within one Auth0 tenant.
If you have multiple AD/LDAP directories against which users will authenticate (for example, to support different departments or customers, each with their own directory), you can set up multiple AD/LDAP Connectors within each Auth0 tenant.
## Learn more
* [Create Multiple Tenants](/docs/get-started/auth0-overview/create-tenants/create-multiple-tenants)
* [Delete or Reset Tenants](/docs/troubleshoot/customer-support/manage-subscriptions/delete-or-reset-tenant)
* [Link Multiple Tenants to a Single Subscription](/docs/get-started/auth0-overview/create-tenants/child-tenants)
# Auth0 Dashboard
Source: https://auth0.com/docs/get-started/auth0-overview/dashboard
Describes the Auth0 Dashboard and all the features you can access to implement authentication and authorization with your applications and APIs..
The [Auth0 Dashboard](https://manage.auth0.com/#) is where you manage all aspects of your Auth0 subscription and configuration.
It consists of several sections that you can navigate using the sidebar menu on your left.
We've redesigned the Dashboard navigation with an improved information architecture and more structured layout. [Learn more about the new navigation](/docs/get-started/auth0-overview/dashboard/use-dashboard-navigation.mdx).
## Configure implementation
The following table contains a brief overview of the different Dashboard sections and what you can do in each.
| Section | Description |
| - | - |
| **Applications** | Manage your applications, APIs, and single sign-on (SSO) integrations. **Applications**: For each of your apps for which you want to authenticate users with Auth0, register an application. **APIs**: For each of your APIs that you want to secure with Auth0, register an API. Create new APIs and manage existing ones. **SSO Integrations**: View and enable external services for SSO. Create new SSO integrations and configure, review, and manage integration settings. |
| **Authentication** | Manage the identity providers through which you allow users to authenticate to your apps. **Database**: Securely store and manage identifier/password credentials either in an Auth0 datastore or in your own database. Connect to existing databases using template-based JavaScript scripts that run on Auth0's server during every authentication. Gradually migrate an existing database of legacy credentials to Auth0 as users authenticate (no password reset required). **Social**: Configure social identity providers (such as Facebook, X, and Github) through which your users can log in. **Enterprise**: Configure enterprise identity providers (such as Active Directory, SAML, and Office 365) through which your users can log in using their enterprise credentials. **Passwordless**: Allow your users to sign up and log in using one-time passcodes (delivered by email or SMS) or one-click links, instead of passwords. |
| **Organizations** | Manage the organizations you do business with, and customize the experience their users have when accessing your applications. |
| **User Management** | Manage your users' identities and permissions. **Users**: View and create user profiles, perform password resets, block and delete users, and more. **Roles**: Create and manage roles for your apps. Roles contain collections of permissions and can be assigned to users. |
| **Branding** | **Universal Login**: Create and customize a login page to which you can direct users to authenticate. **Custom Domains**: Create a custom domain to maintain a consistent experience for your users. **Email Templates**: Use templates to create welcome, password reset, and account verification email-based workflows. **Email Provider**: Designate and configure your custom email provider information. |
| **Security** | Configure extra layers of security by enabling shields that protect your users against different types of attacks and user access anomalies. **Attack Protection**: Manage settings for bot, IP throttling, brute-force, and breached password attacks. **Multi-factor Auth**: Require additional factors during the login process to prevent unauthorized access. **Monitoring**: Monitor threat intelligence events with one of our data visualization and alerting integrations. |
| **Actions** | Configure flows such as login, machine-to-machine, user registration, and password resets. Create and manage customized actions used in flows. |
| **Auth Pipeline** | **Rules**: Configure custom JavaScript snippets that are executed in Auth0 as part of each user authentication transaction. You can call external APIs, filter which users can log in to your application, use an AllowList, configure geolocated access, and so on. **Hooks**: Customize the behavior of Auth0 when you use Database Connections by configuring Node.js code that is executed against extensibility points (which are comparable to webhooks that come with a server). |
| **Monitoring** | **Logs**: View log data of actions taken in the dashboard by administrators and user logins. **Streams**: Create and manage log event streaming to external data analysis services. |
| **Marketplace** | Explore integrations that help your business do more with Auth0. |
| **Extensions** | Extend the Auth0 platform with official and third-party add-ons. |
| **Settings** | Configure your tenants, manage your Auth0 subscription and payment options, control your tenant administrators and other user roles. Manage other tenant settings related to your custom domains, signing keys, and other advanced settings. |
| **Get Support** | Go to our [Support Center](https://support.auth0.com). If your plan does not have access to support services, see the [Auth0 Community](https://community.auth0.com/). |
## Manage account settings
On the top left, you can see your tenant's name and icon, and a little arrow. This arrow displays a dropdown menu that you can use to configure different aspects of your account:
* [**Settings**](/docs/get-started/tenant-settings): Configure several aspects of your tenant.
* [**Invite a member**](/docs/get-started/manage-dashboard-access): Add an additional user as an administrator or other role to your tenant configuration.
* [**Quota Utilization**](https://support.auth0.com/reports/quota): See quota utilization information about your subscription and tenants.
* [**Create tenant**](/docs/get-started/auth0-overview/create-tenants): Use this to create a new tenant.
* **Switch tenant**: If you have [multiple tenants](/docs/get-started/auth0-overview/create-tenants/create-multiple-tenants), use this option to switch between them. If you create an application for one tenant, you will not see it listed for another tenant.
On the top right, you see several clickable options:
* **Search**: Look for apps, marketplace entries, users, and other content related to your tenant.
* **Discuss your needs:** Contact an Auth0 expert to help you reach your goals with Auth0.
* **Docs:** A link to the documentation site you’re reading right now.
* **Notifications bell:** Informs you of new communication from Auth0 or your tenant settings.
* **Profile:** A link to your local tenant profile, as well as options to [change your theme](/docs/get-started/dashboard-profile/light-and-dark-themes) and log out.
## Learn more
* [Create Tenants](/docs/get-started/auth0-overview/create-tenants)
* [Tenant Settings](/docs/get-started/tenant-settings)
* [Application Settings](/docs/get-started/applications/application-settings)
* [Create Users](/docs/manage-users/user-accounts/create-users)
* [API Settings](/docs/get-started/apis/api-settings)
* [Logs](/docs/deploy-monitor/logs)
# About the Activity Page
Source: https://auth0.com/docs/get-started/auth0-overview/dashboard/activity
Learn about the metrics on the Activity page for your Auth0 tenant, including information on active users, failed logins, and more.
The Activity page provides a summary of key data about your Auth0 tenant, including information on active users, failed logins, and more.
## Things to know
* Viewing a tenant's Activity page requires an account with an administrator role (such as Administrator or Owner).
* The **Support Access** role has read-only access to view metrics on the tenant's Activity page but cannot modify settings.
* To ensure data is consistent, the current date cannot be selected in the date picker and data may take up to 24 hours to display.
## Metrics
Here’s what you will see on your tenant's Activity page.
### Totals
At the top of the page, you'll see your tenant's total number of users, applications, APIs, and connections.
### Daily active users
The number of daily unique users with successful authentication (successful login) or authorization activity (successful token exchange). This is calculated based on successful log events for each user. You can see the number of unique users for each day by hovering your mouse over a point in the graph.
### User retention
The percentage of users that were active during the given time frame, calculated from the number of active users out of the total number of users on the tenant.
### Signups
The number of successful user signups, which includes new user registrations through any configured connection (database, social, enterprise).
### Failed logins
The number of failed user logins (the `f` [log event type](/docs/deploy-monitor/logs/log-event-type-codes)) over the given time period.
## Compare to last period
When **Compare to last period** is enabled:
* The percentage difference is included in the graph. Increases are colored green while decreases are colored red.
* Dotted lines are the last time period and solid lines are the current time period.
## View data by time frame
You can view data for a given time frame by using the datepicker next to the **Compare to last period** checkbox. There are built-in date ranges for the last 7/14/30/60 days, or you can provide the **From** and **To** dates for a custom range.
# Search Capabilities in Auth0 Dashboard
Source: https://auth0.com/docs/get-started/auth0-overview/dashboard/search-and-filter-auth0-dashboard
Use Auth0 Dashboard search capabilities to filter Auth0 resources by name, ID, type, and metadata by field or explore the global search feature.
Auth0 Dashboard provides intuitive search capabilities to mitigate long search times if your tenant has complex integrations. If you have multiple configurations in one tenant, then finding a specific application, end user, or API could be difficult. Auth0 Dashboard Search allows you to search and filter throughout your Dashboard configurations.
Global Search is a command palette accessible from any Dashboard page. To access Global Search, press `Cmd+K` (macOS) or `Ctrl+K` (Windows/Linux), or select the search icon in the top navigation bar. Your options include:
* Search bar: Enter a name, display name, or ID to find a list of options or an exact match for an ID.
* Navigation: Select a section of Dashboard to explore.
* User: Find sections you can configure Dashboard user preferences or to manage end users.
* Tenant: Find sections you can use to configure your Auth0 tenant.
* Support: Find support options.
Once you access Global Search, you start under **Navigation** and can use directional keys to select an option to explore, such as Applications, Roles, or Get Started. You can also search by typing in a name or ID across Applications, Organizations, APIs, and Users. For example, if you have test applications, APIs, or users with `test` in the name or email, entering `test` in the search bar offers available options you can select to review or copy the application, API, or user ID.
For a more intuitive search, Auth0 provides tenant users a guided filter interface and Boolean search in specific sections of the Dashboard. You can build filter expressions for searchable fields. Rather than scroll through paginated lists with hundreds of resources, your tenant user queries for fields such as:
* The name of your application (Travel0-native)
* Application or user metadata (permissions)
* Application type (SPA)
* API by name
* API by ID
* Organization member by email
Auth0 Dashboard returns matching results in real time from all your registered resources.
## How it works
The search bar in the following sections uses a guided filter interface and Boolean search:
* [Applications](https://manage.auth0.com/#/applications)
* [APIs](https://manage.auth0.com/#/apis)
* [Roles](https://manage.auth0.com/#/roles)
* [Custom Domains](https://manage.auth0.com/#/custom-domains-v2)
* [Organizations](https://manage.auth0.com/#/organizations)
* [Organization members](https://manage.auth0.com/#/organizations)
* [Enterprise Connections](https://manage.auth0.com/#/connections/enterprise)
* [Database Connections](https://manage.auth0.com/#/connections/database)
The search bar functions as a dropdown menu that lists the filterable fields. When you select a field and enter a value, the filter applies the value as a removable tag above the results. You can combine up to five filters at a time.
Each filter you add narrows results further. To specify results, apply `AND/OR` logic between different fields. Filters reflect in the URL as query parameters. Copy the URL at any point to share with a teammate or bookmark it to return to the same filtered view later.
**Boolean example**
If you filter by **Application type** `Native` OR `SPA`, and **First-party client** `true`, the results show only first-party applications that are either Native or SPA. Applications that are Regular Web Apps or third-party apps are excluded.
### Search behavior by field type
Auth0 Dashboard search matches results based on the field type.
* **String fields** (name, identifier): Partial match is supported. Entering `payments` finds "Payments-application", "Corp Payments Service", and similar — word order does not matter. To exclude results that match a term, prefix it with `NOT`, for example, entering `NOT test` in the name field returns all resources whose name does not contain "test". Wildcard searches require at least three characters; entering fewer shows a "Minimum 3 characters" message and does not submit the query.
* **Exact match fields**
You must enter the full ID value. Partial IDs return no results. Use these fields when you have a specific Client ID from a log or support ticket.
* **Metadata fields**
You can search metadata by key and value or by key only:
* **Key and value**: Enter a key and a value to find resources where that exact key matches that value. For example, key `environment` and value `production` returns only resources where `app_metadata.environment` equals `production`. Prefix matching is supported for values — entering `prod` matches `production`, `prod-eu`, and `prod-us`.
* **Key only**: Enter a key and press **Enter** without a value. This returns all resources that have that metadata key set, regardless of its value. Useful for finding resources that use a specific key at all.
You can also search nested metadata keys up to two levels deep using dot notation. For example, key `tier.bronze` and value `true` matches resources where `app_metadata.tier.bronze` equals `true`.
To exclude results that match a specific key-value pair, prefix the value with `NOT`. For example, key `color` and value `NOT orange` returns all resources where `color` is set to anything other than `orange`. Keys must be an exact match. Contains and ends-with matching are not supported for metadata. Values are indexed up to 64 characters, longer values are not searchable.
* **Enum fields**
Select one or more Application types from a predefined list. Multiple selections within the same filter use OR logic. For example, select `Native` and `SPA` returns all Native and SPA applications.
* **Boolean fields**
Search for first-party clients by selecting `true` or `false`. Use this to distinguish first-party applications (those authorized to skip the consent screen) from third-party ones.
### Searchable fields
#### Applications
| **Field** | **Description** | **Match type** |
| - | - | - |
| **Name** | The name of the application | Partial match |
| **Client ID** (`client_id`) | The unique Client ID | Exact match |
| **External Client ID** (`external_client_id`) | An external identifier for the application | Exact match |
| **Metadata** | Custom key-value metadata stored on the application | Exact or prefix match |
| **Application type** | Native, SPA, Regular Web App, or Machine to Machine | Enum selection |
| **First-party client** | Whether the application is first-party or third-party | Boolean |
#### APIs
| **Field** | **Description** | **Match type** |
| - | - | - |
| **Name** | The name of the API | Partial match |
| **Identifier** | The unique audience identifier (for example, `https://api.example.com`) | Partial match |
| **Id** | The internal system ID | Exact match |
#### Roles
| **Field** | **Description** | **Match type** |
| - | - | - |
| **Name** | The name of the role | Partial match |
| **ID** | The unique role ID | Exact match |
#### Organizations
| **Field** | **Description** | **Match type** |
| - | - | - |
| **Name** | The unique name identifier of the [Organization](/docs/manage-users/organizations/configure-organizations) | Partial match |
| **Display name** | The human-readable display name shown in the Dashboard | Partial match |
| **Identifier** | The unique Organization identifier (`org_id`) | Exact match |
| **Metadata** | Custom key-value metadata stored on the Organization | Exact or prefix match |
| **Third-party client access** | Whether the Organization allows or blocks access from third-party applications (`allow` or `block`) | Enum selection |
| **Application entitlement active** | Whether the application entitlement is currently active for the Organization | Boolean |
#### Organization members
| **Field** | **Description** | **Match type** |
| - | - | - |
| **Name** | The name of the [Organization member](/docs/manage-users/organizations/configure-organizations/invite-members) | Partial match |
| **Email** | The email address of the Organization member | Partial match |
| **User ID** | The unique user identifier | Exact match |
| **Blocked Status** | Filter to show only blocked or active members | Boolean filter |
#### Custom Domains
| **Field** | **Description** | **Match type** |
| - | - | - |
| **Domain** | The [custom domain](/docs/customize/custom-domains) name | Partial match |
| **ID** | The unique custom domain identifier | Exact match |
| **Type** | The certificate type: [Auth0-managed certificates](/docs/customize/custom-domains/auth0-managed-certificates) or [Self-managed certificates](/docs/customize/custom-domains/self-managed-certificates) | Enum selection |
| **Status** | The domain status (Verified, Pending, or Failed) | Enum selection |
| **Default domain** | Whether this domain is marked as the default domain | Boolean |
| **Metadata** | Custom key-value pairs associated with the domain | Exact or prefix match |
#### Enterprise Connections
| **Field** | **Description** | **Match type** |
| - | - | - |
| **Name** | The name of the connection | Partial match |
| **Identifier** | The unique connection identifier | Exact match |
#### Database Connections
| **Field** | **Description** | **Match type** |
| - | - | - |
| **Name** | The name of the connection | Partial match |
| **Identifier** | The unique connection identifier | Exact match |
| **Domain connection** (`is_domain_connection`) | Whether the connection is configured as a domain-level connection | Boolean |
| **Metadata** | Custom key-value metadata stored on the connection | Exact or prefix match |
Canonical domains, for example: YOUR-TENANT.auth0.com, are not custom domains and will not appear in search results. If you are looking for your canonical domain, you can find it in your [tenant settings](https://manage.auth0.com/#/tenant/general).
### Limitations
* You can apply a maximum of five filters per search. The search bar prevents adding a sixth filter.
* Search results may not reflect changes made in the last few seconds, as the index is eventually consistent.
* Results return within two seconds under normal conditions. If a query times out, reduce the number of filters or use a more specific search term.
## Example queries
### Find an application by Client ID
Use this when you have a `client_id` from an error log or support ticket and need to locate the application quickly.
1. Navigate to **[Auth0 Dashboard > Applications > Applications](https://manage.auth0.com/#/applications)**.
2. Select the search bar and choose **Client ID**.
3. Paste the full `client_id` value. The matching application appears immediately.
### Find applications using metadata
If your applications store custom metadata — such as environment labels, plan tiers, or external IDs — you can search by those values.
1. Navigate to **[Auth0 Dashboard > Applications > Applications](https://manage.auth0.com/#/applications)**.
2. Select the search bar and choose **Metadata**.
3. Enter the metadata key, for example `environment`.
4. Enter the value, for example `production`. Applications where `metadata.environment` equals `production` appear in the results. To match by prefix, enter a partial value such as `prod`.
## Troubleshooting
**No results found**
Check that the filter values are spelled correctly. For string fields, try a shorter or more general term. For metadata fields, confirm the exact key name — keys are case-sensitive and must be an exact match. Contains-style matching is not supported for metadata; use a prefix instead. For exact match fields such as Application ID, make sure you are pasting the complete ID value.
**Results seem outdated**
Search results are eventually consistent and may not reflect changes made in the last few seconds. If you recently created or updated a resource, wait a few seconds and retry the search.
**Search timed out**
Reduce the number of active filters or use a more specific search term. If the problem persists, contact [Auth0 Support](https://support.auth0.com).
# Navigate Auth0 Dashboard
Source: https://auth0.com/docs/get-started/auth0-overview/dashboard/use-dashboard-navigation
Explore Auth0 Dashboard's redesigned navigation with an improved information architecture and more structured layout.
Auth0 Dashboard Navigation is is available as an Early Access feature on all Auth0 plans.
Feedback is collected throughout the Early Access period.
The navigation menu in Auth0 Dashboard helps you find what you need faster. The navigation features an improved sidebar with organized sections, a unified breadcrumb system, and improved visual hierarchy.
## Enable Auth0 Dashboard navigation
When the navigation feature is available for your tenant, an opt-in popup displays the first time you log in:
1. Select **Try now** to enable the new navigation immediately, or **Maybe later** to dismiss the popup.
* If you choose **Maybe later**, the popup will reappear in 14 days.
2. After opting in, you can disable the navigation feature from your user profile menu:
* Choose your profile icon in the top-right corner of the Dashboard.
* Click the new navigation toggle to switch back to the old navigation UI.
Your preference is saved and persists across sessions.
## How it works
The navigation in Auth0 Dashboard groups related items into logical sections with clear, workflow-focused naming for easier navigation. A sticky page action bar appears at the top of each page with breadcrumbs, tabs, actions, and the sidebar toggle button to keep important controls visible as you scroll.
Breadcrumb trails now appear in the action bar instead of scattered across page headers for consistent context navigation. The new navigation also includes a refreshed, modern layout and structure for improved usability.
The navigation features a redesigned left sidebar as you navigate between sections in Auth0 Dashboard. The sidebar is organized into the following sections:
| Section | Contains |
| - | - |
| Primary (non-labeled) | Home: Dashboard landing for getting started Agents: AI Agents configuration Users: User management Organizations: Organization management Settings: Tenant configuration and account management |
| Integration | Applications: Register and manage your applications APIs: Register and manage your APIs Authentication: Configure authentication (Database, Passwordless) Connections: Manage social connections Enterprise SSO: Manage enterprise connections and self-service profiles Authorization: Create and manage roles |
| Customization | Branding: Visual editor for Universal Login theming Pages: Universal Login and Forms page customization Portals: Visual editor for portal pages Domains: Manage custom domains |
| Messaging | Emails: Email templates and configuration Phone: Phone messaging settings |
| Automation & Extensibility | Actions: Create and manage Auth0 Actions Events: Stream authentication events to external services Extensions: Official and third-party add-ons Rules: Legacy rules (for existing configurations) Hooks: Legacy hooks (for existing configurations) |
| Security & Monitoring | Attack Protection: Bot, IP throttling, Brute-force, and Breached Password Protection Access Control: Access Control lists Security Dashboard: Security overview and threat metrics Logs: View activity logs Analytics: Usage analytics and reporting |
## Browser support
The new navigation requires modern browsers with `localStorage` support for sidebar state persistence. If you encounter any issues, you can always switch back to the classic navigation using the profile menu toggle.
## Learn more
* [Auth0 Dashboard Overview](/docs/get-started/auth0-overview/dashboard)
* [Dashboard Activity](/docs/get-started/auth0-overview/dashboard/activity)
* [Search and Filter by Fields in Auth0 Dashboard](/docs/get-started/auth0-overview/dashboard/search-and-filter-auth0-dashboard)
* [Tenant Settings](/docs/get-started/tenant-settings)
# Register APIs
Source: https://auth0.com/docs/get-started/auth0-overview/set-up-apis
Learn how to register APIs in the Auth0 Dashboard.
Before you register any APIs in the Auth0 Dashboard, one API will already exist: the **Auth0 Management API**. To learn more about the features of the Management API and its available endpoints, see [Management API](https://auth0.com/docs/api/management/v2).
1. Go to [Dashboard > Applications > APIs](https://manage.auth0.com/#/apis), and select **+ Create API**.
2. Provide the following information for your API, and click **Create**:
| Field | Description | Example |
| - | - | - |
| **Name** | A friendly name for the API. Does not affect any functionality. | `yourDomain` |
| **Identifier** | A unique identifier for the API. Auth0 recommends using a URL. Auth0 does differentiate between URLs that include the last forward slash. For example, `https://example.com` and `https://example.com/` are two different identifiers. The URL does not have to be a publicly available URL. Auth0 will not call your API. This value cannot be modified afterwards. | `https://{yourDomain}` |
| **JSON Web Token (JWT) Profile** | The profile determines the format of the access tokens issued for the API. The available values are `Auth0` and `RFC 9068`. To learn more, read [Access Token Profiles](/docs/secure/tokens/access-tokens/access-token-profiles). | `Auth0` |
| **JSON Web Token (JWT) Signing Algorithm** | The algorithm to sign the access tokens with. The available values are `HS256`, `PS256`, `RS256`. If you select `RS256`, the token will be signed with the tenant's private key. | `RS256` |
| **Access Policy for Applications within user flow** | Allow applications to access the API on the user’s behalf. To learn more read, [API Access Policies for Applications](/docs/get-started/apis/api-access-policies-for-applications). | `Allow via client-grant` |
| **Access Policy for Applications within client flows** | Allow Machine to Machine applications to access the API. To learn more read, [API Access Policies for Applications](/docs/get-started/apis/api-access-policies-for-applications). | `Allow via client-grant` |
3. Make the implementation changes to your API that are described in the QuickStart. These changes consist of choosing a JWT library from a predefined list and configuring this library to validate the access tokens in your API.
If you are creating a new custom API and also have Single-Page or Native applications in your tenant, you must enable Role-based Access Control (RBAC) to keep users logged in to these applications from generating an access token for your API that does not consider scopes. To learn how to enable RBAC for your API, read [Enable Role-Based Access Control for APIs](/docs/get-started/apis/enable-role-based-access-control-for-apis).
The other available Dashboard views for your API are:
* **Settings**: Lists the settings for your API. Some are editable. Here you can change the token expiration time and enable offline access (this way Auth0 will allow your applications to ask for refresh tokens for this API).
* **Scopes**: Define the scopes for this API by setting a name and a description.
* **Machine to Machine Applications**: Lists all applications for which the **Client Credentials** grant is enabled. By default, this grant is enabled for regular web applications and machine-to-machine applications. You can authorize any of these applications to request access tokens for your API. Optionally, you can select a subset of the defined scopes to limit your authorized application's access.
* **Test**: Execute a sample client credentials flow with any of your authorized applications to check that everything is working as expected.
## Learn more
* [API Settings](/docs/get-started/apis/api-settings)
* [Token Best Practices](/docs/secure/tokens/token-best-practices)
* [Which OAuth 2.0 Flow Should I Use?](/docs/get-started/authentication-and-authorization-flow/which-oauth-2-0-flow-should-i-use)
# Auth0 Teams
Source: https://auth0.com/docs/get-started/auth0-teams
Describes how Auth0 Teams allows you to manage tenants and tenant administrators.
Auth0 Teams provides a single point of visibility and control over your Auth0 resources by providing centralized governance, compliance, and secure collaboration at scale. Teams membership sits on top of the tenant membership account.
The main team member role is referred to as the Team Owner and has visibility into all tenants within their Auth0 Account. As an Auth0 Team Owner, you can manage a single tenant or multiple tenants.
The following features are currently available as part of Auth0 Teams:
* Visibility and control of Teams members
* Visibility into Tenants with relevant details
* Visibility and control of Tenant members
* Ability to enforce Single Sign-On with your own Identity provider
* Ability to restrict tenant creation
* Ability to manage subscription and billing details for self-service subscriptions
Auth0 Teams currently supports a single Teams instance for all tenants attached to either your subscription or Enterprise contract.
Team Owners manage and configure the tenants and tenant administrators within the Teams instance.
## Getting Started
Auth0 Teams is on by default for new self-service users since 1 November 2023.
Existing Public and Private Cloud Enterprise customers can request to be onboarded into Teams through their Technical Account Manager, Sales Executive, or open a ticket with [Auth0 Support](https://support.auth0.com).
For all other subscription types, if you joined Auth0 prior to 1 November 2023, you need to upgrade your plan to the latest version in your tenant's [subscription settings](https://manage.auth0.com/#/tenant/billing/subscription) to have Teams automatically provisioned for you.
## Feature Support Matrix
Features marked with an asterisk are currently in beta for Private Cloud customers.
| Teams Feature | Enterprise Private Cloud | Enterprise Public Cloud | Self-Service Subscription |
| - | - | - | - |
| Tenant Management | ✅ | ✅ | ✅ |
| Tenant Member Management | ✅ \* | ✅ | ✅ |
| SSO Enforcement | ✅ \* | ✅ | ❌ |
| Tenant Creation from Teams | ✅ | ❌ | ✅ |
# Team Member Management
Source: https://auth0.com/docs/get-started/auth0-teams/team-member-management
Invite members to an Auth0 Team and assign roles that define what each member can do across the tenants your team manages.
Use Team membership roles for access control across your Team and tenant. To follow the principal of least privilege, each role grants a specific set of permissions, from full administrative access to read-only reporting. Team Owners can manage and configure members as well as manage an Auth0 tenant. When we provision a new Team, Auth0 creates at least one Owner. We recommend at least two Team Owners, especially if you limit tenant creation to Team Owners.
**Self-Service Customers**
When Auth0 provisions a Team, we may automatically assign the **Team Owner** role to the administrator user account. However, this user must manually assign themselves the **Team Owner** role in order to verify their email and receive full account permissions. This user can then invite additional members as needed.
As a Team Owner, you can add, change, and remove team members. The supported roles apart from a Team Owner are Tenant Manager, Report Viewer, and Contributor.
## Team membership role comparison
Review permissions for both management of your Teams members and tenant.
**Team management**
| Function | Team Owner | Tenant Manager | Report Viewer | Contributor |
| :- | :-: | :-: | :-: | :-: |
| Invite members to team | ✓ | ✗ | ✗ | ✗ |
| Update team-level roles | ✓ | ✗ | ✗ | ✗ |
| Edit Security Policies / Team Settings | ✓ | ✗ | ✗ | ✗ |
| View Team Activity / Security / Settings | ✓ | ✗ | ✗ | ✗ |
| View Quota / Quarterly Reports | ✓ | ✗ | ✓ | ✗ |
**Tenant management**
| Function | Team Owner | Tenant Manager | Report Viewer | Contributor |
| :- | :-: | :-: | :-: | :-: |
| Create tenant | ✓ | ✓ | ✗ | ✗ |
| Delete tenant | ✓ | ✓ | ✗ | ✗ |
| View and access tenants | ✓ | ✓ (Assigned) | ✗ | ✓ (Assigned) |
| View Private Cloud environments | ✓ | ✓ | ✗ | ✗ |
| View tenant members | ✓ | ✓ | ✗ | ✗ |
| Add / update / remove tenant members **\*** | ✓ | ✓ | ✗ | ✗ |
In order to delete a tenant or view tenant memebers, Tenant Managers must also be assigned Tenant Admin role to delete a tenant.
## Team membership roles
### Team Owner
Members with this role have full access to the team dashboard (list of all tenants, tenant creation restriction, team members management) and can access specific tenants of which they are a member.
### Tenant Manager
Members with this team-level role can perform delegated tenant management tasks like create tenants, manage tenant members, and delete tenants without requiring full Team Owner access. For a full review of your Team's roles, review the [role comparison](#role-comparison) table for a detailed breakdown of permissions.
The Tenant Manager is a team-level role. To delete a tenant or manage tenant members, Tenant Managers must be assigned the [Tenant Admin](/docs/get-started/auth0-teams/tenant-member-management) role.
### Report Viewer
Members with this role can view Quarterly Snapshots. The Report Viewer role is available to select enterprise customers that are managed by the Digital Technical Account Manager (DTAM).
### Contributor
Members with this role can view and access specific tenants of which they are a member.
## View and add team members
### Invite a new team member
To invite a new team member, use Auth0 Dashboard to access the Teams Dashboard.
1. On the left side of the Teams Dashboard, select **Members**.
2. To invite a new team member, select **Invite a Member**.
3. Enter the email address of the member to invite and select the access level.
4. Select **Send Invite**.
### Update existing team member role
1. To update the role of an existing Team Member, search for the member in the **Members** list.
2. Select the three-dot menu option and click on the **Assign Role** option.
3. Pick the new role you want to assign the Team Member and select **Assign**.
### Delete an existing team member
If a team member no longer requires access to the team, they can simultaneously be removed from the Teams Dashboard and all team tenants in which they are a user.
This feature requires tenant member management. Public Cloud Enterprise customers must activate this feature manually on the Teams settings page.
To delete an existing Team Member:
1. Navigate to the **Members** section on the left side of the Teams Dashboard, then locate the team member.
2. Select the ellipsis to reveal more options and choose **Remove Member**.
3. After you confirm the removal, you will be presented with a toast notification confirming the successful deletion of the team member.
If you only want to remove the team member's access to one or more tenants, navigate to the **Members** section, then **Manage Tenant Access**. To learn more, read [Team Member's details page](/docs/get-started/auth0-teams/tenant-member-management).
## Update team name
Teams allow you to update the Team name visible on the tenant picker for dashboard users. To update the Team name:
1. Select **Settings** on the left side of the Teams Dashboard.
2. Make the necessary changes to the **Team Name** captured within the **Team Information** section.
3. Select **Save**. This change now displays in the tenant picker.
# Tenant Management
Source: https://auth0.com/docs/get-started/auth0-teams/tenant-management
Manage tenants in Auth0 Teams, including linking tenants, controlling tenant creation permissions, and reviewing subscription details.
Access and modify Team information from within your tenant. If you don't yet have a tenant associated with your account, see [Create Tenants.](/docs/get-started/auth0-overview/create-tenants)
## Access the Teams Dashboard
If you are a Team Owner, you can use the Teams Dashboard to:
* Choose who can create new tenants: Team Owners or all tenant administrators.
* View all tenants created under your Auth0 subscription or custom agreement.
* View and invite Team Owners.
To access the Teams Dashboard from any of your tenants:
1. Select your tenant name from the tenant drop-down menu in the [Auth0 Dashboard](https://manage.auth0.com/dashboard).
2. Find your Teams name at the bottom of the menu and select **Go to team**.
To access the Teams Dashboard using a URL:
1. Navigate to `https://accounts.auth0.com/`
2. If your user account is a member of only one Team, enter your credentials to be taken to your Teams dashboard. If your user account is a member of one or more Teams, select the Team from the list of Teams your user account is associated with to login.
If the option for Teams access isn't visible, try the following:
| Possible Cause | Action |
| - | - |
| The current tenant isn’t in Teams. | Try switching to a different tenant. |
| You’re not a Teams owner. | Ask a Teams owner to invite you to the team. |
## View tenants
In the Teams Dashboard, you can view all tenants within your Auth0 custom agreement or subscription present in either the Public or Private Cloud Environment. For each tenant, you can review:
* Tenant name
* Region
* Creation date
* Environment (Development, Staging, or Production)
* Tenant administrators
1. Select **Tenants** on the left side of the Teams Dashboard.
For Private Cloud Environments, select the **Overview** menu drop-down to reveal the **Tenants** menu option.
2. If you’re an administrator for a tenant, select the tenant name to access the tenant. If you are not a tenant administrator, you will not be able to select the tenant.
3. To review tenant members, select **View Members**.
## View private cloud environments
A list of private cloud environments can be viewed from the Teams Dashboard. You are able to view the following information
* Environment name
* Cloud provider type (AWS or Azure)
* Deployment region
* Failover region
* Current environment release version.
1. Select the **Overview** menu drop-down to reveal the **Private Cloud** menu option.
## Link tenants
This feature is currently available for the following Team Subscription types:
* B2C - Essentials
* B2B - Essentials
* B2C - Professional
* B2B - Professional
Linking tenants allows you to share features and quota limits available within your Team Subscription with the linked tenant. Once linked, that tenants subscriptions will be tied to your Team and you would no longer have to individually manage the subscription for that tenant.
You are able to link tenants to your team, if the following conditions are true:
* The tenant is not part of an existing Team.
* You are an administrator of the tenant you want to link.
* You have a Team Owner role on the team.
Linking a tenant cancels the subscription attached to the tenant.
If these conditions are met, the tenant will show up as a possible option to link to your team when you select **Link Existing Tenant** from the Tenants page.
## Create new tenant
This feature is currently available for the following Team Subscription types:
* B2C - Essentials
* B2B - Essentials
* B2C - Professional
* B2B - Professional
* Enterprise Private Cloud
By using this feature, you agree to the applicable Free Trial terms in Okta’s [Master Subscription Agreement](https://www.okta.com/legal/).
Team Owners can create a tenant from within the Teams Dashboard, automatically linking the created tenant with the team, including associating the Team Subscription details (available features and quota limits) with the newly created tenant.
You can do this by clicking on the **Create New Tenant** button on the Tenants page, which will open the Create Tenant form.
## Manage tenants
You can control who can create new tenants under your Auth0 custom agreement or subscription under **Team Settings**. When creating a new tenant, administrators can:
* Link the tenant to custom agreement. The new tenant exists under your custom agreement or subscription. It benefits from the same features, counts toward limits, and is visible to Team Owners.
or
* Create a tenant under their personal account. The new tenant is not a part of your Teams' custom agreement or subscription. The administrator who creates the tenant can access it with the same login credentials.
To allow administrators to link a tenant to a custom agreement, the Team Owner must:
1. Select **Settings** on the left side of the Teams Dashboard.
2. Select the option **Allow Tenant Admins to Create Tenants under the Teams Account**. If this option is unchecked, then tenant administrators can create personal accounts only.
The **Tenant Creation** option does not apply to Team Owners. Owners have permissions to create new tenants in the Teams instance under the custom agreement or subscription.
3. Select **Save**.
If a Tenant administrator without permission attempts to create tenants, they will be prompted to contact the Team Owner.
## View Team Subscription details
This feature is currently available for the following Team Subscription types:
* B2C - Essentials
* B2B - Essentials
* B2C - Professional
* B2B - Professional
Team Owners can view Team Subscription details by visiting Subscription tab within the Setting page.
# AI Doc Tools
Source: https://auth0.com/docs/get-started/build-with-ai-tools
Connect AI agents and LLMs directly to the Auth0 knowledge base using LLM context files and the hosted docs MCP server.
Accelerate your development workflow by connecting AI agents and LLMs directly to the Auth0 knowledge base. Get context-aware answers, code samples, and API references with links to official documentation.
To help your AI tools index and search for the information you need, Auth0 provides:
* LLM context files (`llms.txt`): Structured Markdown files for bulk ingestion.
* Auth0 Docs MCP Server: Hosted MCP Server for AI agents to dynamically query the knowledge base.
## LLM context files
Use LLM context files to help LLMs understand and efficiently ingest the entire Auth0 site directory.
| Name | URL | Description |
| - | - | - |
| `llms.txt` | `https://auth0.com/llms.txt` | Concise summaries of all articles; best for quick context. |
| `llms-full.txt` | `https://auth0.com/docs/llms-full.txt` | Full content of all articles; best for deep indexing. |
## Auth0 Docs MCP Server
Connect your AI tools to the Auth0 Docs Model Context Protocol (MCP) Server for real-time access to the most up-to-date documentation on Auth0. The Auth0 Docs MCP Server exposes the `SearchAuth0Docs` tool, which enables AI agents to search the Auth0 knowledge base and return contextual content with relevant links to product documentation.
The Auth0 Docs MCP Server has the following endpoint metadata:
```
Server Name: Auth0 Docs
Server URL: https://auth0.com/docs/mcp
Transport Type: HTTP
```
Learn how to connect your AI tools to the Auth0 Docs MCP Server by following our integration guides.
To connect ChatGPT to the Auth0 Docs MCP Server:
1. Navigate to [Settings > Connectors](https://chatgpt.com/#settings/Connectors).
2. Select **Create** and provide the metadata for your MCP server:
* Connector Name: Auth0 Docs MCP Server
* Description: Indexes and searches the Auth0 knowledge base
* Connector URL: `https://auth0.com/docs/mcp`
3. Select **Create**.
If successful, the Auth0 Docs MCP Server should appear as an installed MCP server. To learn more, read OpenAI's [Connect from ChatGPT](https://developers.openai.com/apps-sdk/deploy/connect-chatgpt/) documentation.
To connect Claude to the Auth0 Docs MCP Server:
1. Navigate to [Settings > Connectors](https://claude.ai/settings/connectors).
2. Select **Add custom connector**.
3. Enter the following to add the Auth0 Docs MCP Server:
* Name: Auth0 Docs MCP Server
* URL: `https://auth0.com/docs/mcp`
4. Select **Add**.
If successful, the Auth0 Docs MCP Server should appear as a custom connector. To learn more, read Model Context Protocol's [Connect to remote MCP Servers](https://modelcontextprotocol.io/docs/tutorials/use-remote-mcp-server#connecting-to-a-remote-mcp-server) documentation.
To connect Claude Code to the Auth0 Docs MCP Server:
In your terminal, run:
```bash lines theme={null}
claude mcp add --transport http auth0-docs-mcp-server https://auth0.com/docs/mcp
```
To verify, run:
```bash lines theme={null}
claude mcp list
```
If successful, the Auth0 Docs MCP Server should appear as an installed MCP server. To learn more, read Claude’s [Installing MCP servers](https://docs.anthropic.com/en/docs/claude-code/mcp#installing-mcp-servers) documentation.
To connect Codex to the Auth0 Docs MCP Server:
In your terminal, run:
```bash lines theme={null}
codex mcp add auth0-docs-mcp-server --url https://auth0.com/docs/mcp
```
To verify, run:
```bash lines theme={null}
codex mcp list
```
If successful, the Auth0 Docs MCP Server should appear as an installed MCP server. To learn more, read Codex’s [Model Context Protocol](https://developers.openai.com/codex/mcp) documentation.
To connect Cursor to the Auth0 Docs MCP Server:
1. Use Command + Shift + P (Ctrl + Shift + P on Windows) to open the command palette and search for **Open MCP settings**.
2. Select **New MCP Server** to edit your `mcp.json`.
3. Add the Auth0 Docs MCP Server:
```json lines theme={null}
{
"mcpServers": {
"auth0-docs-mcp-server": {
"url": "https://auth0.com/docs/mcp"
}
}
}
```
If successful, the Auth0 Docs MCP Server should appear as an installed MCP server. To learn more, read Cursor’s [Installing MCP servers](https://cursor.com/docs/context/mcp#installing-mcp-servers) documentation.
To connect VS Code to the Auth0 Docs MCP Server:
1. Use Command + Shift + P (Ctrl + Shift + P on Windows) to open the command palette and search for **MCP: Add Server**.
2. Select **HTTP** as the type of MCP server.
3. Enter the MCP Server URL (`https://auth0.com/docs/mcp`) and set the Server ID to `auth0-docs-mcp-server`.
4. Select **Global** or **Workspace** to make the MCP server available across all your workspaces or for your current workspace.
5. Press **Enter** to complete setup. Verify the Auth0 Docs MCP Server appears under **Installed MCP Servers** in your **Extensions**.
To learn more, read [Add and manage MCP servers in VS Code](https://code.visualstudio.com/docs/copilot/chat/mcp-servers).
To connect Windsurf to the Auth0 Docs MCP Server:
1. Use Command + Shift + P (Ctrl + Shift + P on Windows) to open Windsurf settings and search for **MCP**.
2. Select **View Raw Config** to edit your `mcp_config.json`.
3. Add the Auth0 Docs MCP Server:
```json lines theme={null}
{
"mcpServers": {
"auth0-docs-mcp-server": {
"serverUrl": "https://auth0.com/docs/mcp"
}
}
}
```
4. Save and select **Refresh** to load the new MCP configuration.
To verify, ask `What MCP servers do you have installed?` in Cascade’s chat. Cascade should list the Auth0 Docs MCP Server as an installed MCP server. To learn more, read Windsurf’s [Model Context Protocol](https://docs.windsurf.com/plugins/cascade/mcp#model-context-protocol-mcp) documentation.
## Sample prompts
AI tools can make mistakes. Always review responses by referencing the provided documentation links and AI-generated code for accuracy before deploying.
Use the following sample prompts with your AI tools to leverage Auth0 to secure your identity workflow.
### Setup
* How do I customize the consent prompt to render rich authorization requests in a web browser?
* Fetch me instructions on how to set up asynchronous authorization with the Auth0 Guardian app in my mobile application.
* How do I implement refresh token rotation in a Next.js app? Show me the configuration steps and a code example.
### Connections and integrations
* I want to restrict access to this app to users who are members of a specific GitHub Organization. Use the Auth0 Docs MCP Server to find how to configure the GitHub Enterprise Connection and write an Auth0 Action that checks the user's GitHub org membership during login, denying access if they aren't a member.
* Configure a Slack Social Connection. Use the Auth0 Docs MCP Server to find the correct way to map Slack's `team_id` onto the user's ID token. Then, update my local user interface to include this `slack_team_id` field.
* How do I integrate Auth0 into an existing Vercel project?
### AI agents and MCP servers
* Add a tool call to my AI agent that can access the user’s Google calendar and answer questions about their schedule and meetings. Use the Auth0 Docs MCP Server for instructions on using Auth0 to secure login and implementing the tool call to the user’s Google calendar.
* Act as a security engineer. Use the Auth0 Docs MCP Server to find the guide on Authorization for Your MCP Server. Update my current server configuration to require OAuth 2.1 for all incoming connections and verify that it uses the Resource Parameter Compatibility Profile for access tokens.
* Examine my current tool definitions in `server.py`. Use the Auth0 Docs MCP Server to verify whether my implementation of Custom Token Exchange complies with RFC 8693. If you find any discrepancies where user context might be leaked, suggest a fix and provide the updated code.
### Troubleshooting
* Help me troubleshoot a `refresh token doesn’t exist` error when using the refresh token exchange. Use the Token Vault setup instructions as context.
* The logout button isn't clearing the session on the Auth0 side. Search the documentation for the correct Federated Logout URL structure and update my logout handler to use it.
* My login flow is failing with a `401 Unauthorized error`. Use the Auth0 Docs MCP Server to look up common causes for this error with the `auth0-node` SDK and check my `.env` and client initialization for mismatches.
# Agent Skills for Auth0
Source: https://auth0.com/docs/quickstart/agent-skills
Use Auth0 agent skills to integrate authentication into your applications with AI coding assistants like Claude Code, Cursor, and GitHub Copilot
Agent skills are structured instructions that help AI coding assistants implement Auth0 authentication correctly. Install once, then ask your assistant to add login, protect routes, secure APIs, set up MFA, migrate from another provider, or customize your login page — it handles the rest.
Works with Claude Code, Cursor, GitHub Copilot, and [40+ other agents](https://agentskills.io/clients) that support the [Agent Skills](https://agentskills.io) format.
## Prerequisites
* An [Auth0 account](https://auth0.com/signup) (free tier available)
* Your Auth0 **domain** and **client ID** from the [Auth0 Dashboard](https://manage.auth0.com)
* An AI coding assistant (Claude Code, Cursor, or GitHub Copilot)
## Install
Auth0 is on the official Claude Code plugins marketplace (`claude-plugins-official`). First, make sure the marketplace is up to date, then install:
```bash theme={null}
/plugin marketplace update claude-plugins-official
/plugin install auth0@claude-plugins-official
```
Or type `/plugin` in a session, go to the **Discover** tab, and search "Auth0".
You can also install from your terminal without starting a session:
```bash theme={null}
claude plugin marketplace update claude-plugins-official
claude plugin install auth0@claude-plugins-official
```
If you get a "not found" error, add the marketplace first and then retry the install:
```bash theme={null}
/plugin marketplace add anthropics/claude-plugins-official
/plugin install auth0@claude-plugins-official
```
Auth0 is on the [Cursor marketplace](https://cursor.com/marketplace/auth0). Open the listing and click **Add** to install.
You can also install via **Cursor Settings > Rules > Add Rule > Remote Rule (GitHub)** and enter the [Auth0 Agent Skills repository URL](https://github.com/auth0/agent-skills).
Install using the [Skills CLI](https://github.com/vercel-labs/skills) targeting GitHub Copilot:
```bash theme={null}
npx skills add auth0/agent-skills --agent github-copilot
```
The [Skills CLI](https://github.com/vercel-labs/skills) works with Claude Code, Cursor, Copilot, Codex, and [40+ other agents](https://agentskills.io/clients):
```bash theme={null}
npx skills add auth0/agent-skills --all
```
Target specific agents with `--agent`:
```bash theme={null}
npx skills add auth0/agent-skills --agent claude-code cursor
```
## Try it now
After installing, paste any of these into your AI coding assistant:
```
Add Auth0 login to my app
```
```
Secure my Express API with Auth0 JWT validation
```
```
Migrate from Firebase Auth to Auth0
```
Provide context when prompting — mention your framework, router type, and whether you need login, API protection, or both. The more specific the prompt, the better the output.
## How it works
Tell your assistant what you want — add login to your React app, secure a Spring Boot API, migrate from Cognito, add MFA, or customize your login page. You don't need to know which skill or SDK to use.
The `auth0` skill's router reads your project files (`package.json`, `requirements.txt`, `build.gradle`, etc.), identifies your framework, and loads the matching reference files for your stack.
The skill guides your assistant through the full implementation — installing the right SDK, creating auth routes, configuring environment variables, adding route protection, and following Auth0 best practices.
With a single `auth0` skill, you don't need to pick anything manually. It detects your framework automatically and handles features, like [Multi-factor authentication (MFA)](/docs/secure/multi-factor-authentication), when you describe what you need. If your assistant doesn't pick it up automatically, then invoke it explicitly with `/auth0`.
## Skill capabilities
The `auth0` skill handles authentication setup, API protection, migration, CLI tooling, and advanced features across the frameworks below. Each example prompt can be pasted directly into your AI coding assistant.
### Get started
| Capability | What it does | Try it |
| - | - | - |
| **Framework detection** | Detects your framework and sets up Auth0 with the right SDK | `Add Auth0 authentication to my app` |
| **Migration** | Migrate users and code from Firebase, Cognito, Supabase, Clerk, or custom auth | `Help me migrate from Firebase Auth to Auth0` |
| **CLI** | Auth0 CLI command reference — manage apps, APIs, users, roles, orgs, actions, logs, custom domains, and Universal Login | `Create an Auth0 application using the CLI` |
### Frontend
| Capability | What it does | Try it |
| - | - | - |
| **React** | Login, logout, user sessions, and protected routes for React SPAs | `Add Auth0 login to my React app` |
| **Vue** | Authentication for Vue 3 applications with composables and route guards | `Set up Auth0 in my Vue 3 app` |
| **Angular** | Auth with route guards and HTTP interceptors for Angular 13+ | `Add Auth0 authentication to my Angular app` |
| **Vanilla JS** | Auth for any JavaScript SPA — also works with Svelte and SolidJS | `Add Auth0 login to my Svelte app` |
### Backend & Fullstack
| Capability | What it does | Try it |
| - | - | - |
| **Next.js** | Auth for Next.js 13+ with App Router, Pages Router, middleware, and server components | `Set up Auth0 in my Next.js app with protected routes` |
| **Nuxt** | Server-side sessions and route protection for Nuxt 3/4 | `Add Auth0 authentication to my Nuxt app` |
| **Express** | Session-based login, logout, and protected routes for Express.js | `Add Auth0 login to my Express app` |
| **Flask** | Login, logout, and user profiles for Flask web applications | `Set up Auth0 in my Flask app` |
| **Fastify** | Session-based auth for Fastify web applications | `Add Auth0 authentication to my Fastify app` |
| **Java Servlet** | Login and callback handling for Java Servlet applications | `Add Auth0 login to my Java Servlet app` |
### API
| Capability | What it does | Try it |
| - | - | - |
| **Express API** | JWT Bearer validation, scope-based access control for Node.js/Express APIs | `Secure my Express API with Auth0 JWT validation` |
| **Fastify API** | JWT Bearer validation and scope checks for Fastify API endpoints | `Add Auth0 JWT validation to my Fastify API` |
| **FastAPI** | Token validation and scope-based auth for Python FastAPI backends | `Secure my FastAPI endpoints with Auth0` |
| **Spring Boot API** | JWT validation and scope-based authorization for Spring Boot APIs | `Add Auth0 authentication to my Spring Boot API` |
| **ASP.NET Core API** | JWT Bearer auth and DPoP support for .NET API endpoints | `Secure my ASP.NET Core API with Auth0` |
| **Go API** | JWT validation and scope-based authorization for Go HTTP APIs using go-jwt-middleware | `Add Auth0 JWT validation to my Go API` |
### Mobile
| Capability | What it does | Try it |
| - | - | - |
| **React Native** | Auth with biometric support and deep linking for React Native CLI apps | `Add Auth0 login to my React Native app` |
| **Expo** | Auth with Expo Config Plugin for managed workflow mobile apps | `Set up Auth0 in my Expo app` |
| **Android** | Web Auth, biometrics, and credential management for native Android | `Add Auth0 authentication to my Android app` |
| **iOS / macOS** | Native Auth0.swift integration for iOS, macOS, tvOS, watchOS, and visionOS | `Add Auth0 login to my iOS app` |
### Advanced
| Capability | What it does | Try it |
| - | - | - |
| **MFA** | Multi-factor authentication — TOTP, SMS, email, push, WebAuthn | `Add TOTP-based multi-factor authentication to my app` |
| **ACUL Screen Generator** | Generate custom-branded Universal Login screens with React or vanilla JS | `Create a branded login screen matching our design system` |
## Learn more
Source code, the `auth0` skill definition, and issue tracker.
Step-by-step guides for manual (non-AI) Auth0 integration.
SDK documentation and API references.
The open standard behind agent skills, supported by 40+ AI coding tools.
## Get help
* **Ask your AI assistant** — rephrase your request or provide more context about your project setup
* **[Open an issue](https://github.com/auth0/agent-skills/issues)** — report bugs or request skills for new frameworks
* **[Auth0 Community](https://community.auth0.com)** — get help from other Auth0 developers
* **Security issues** — use the [Responsible Disclosure Program](https://bugcrowd.com/engagements/auth0-okta)
# ASP.NET Core Web API
Source: https://auth0.com/docs/quickstart/backend/aspnet-core-webapi
Add Auth0 JWT authentication to an ASP.NET Core Web API with protected endpoints
This Quickstart is currently in **Beta**. We'd love to hear your feedback!
If you use an AI coding assistant like Claude Code, Cursor, or GitHub Copilot, you can add Auth0 authentication automatically in minutes using [agent skills](https://agentskills.io/home).
**Install:**
```bash theme={null}
npx skills add auth0/agent-skills --skill auth0
```
**Then ask your AI assistant:**
```text theme={null}
Add Auth0 JWT authentication to my ASP.NET Core Web API
```
Your AI assistant will automatically create your Auth0 API, fetch credentials, install the Auth0 ASP.NET Core Authentication API SDK, configure JWT bearer authentication, and implement protected API endpoints. [Full agent skills documentation →](/docs/quickstart/agent-skills)
**Prerequisites:** Before you begin, ensure you have the following installed:
* **[.NET 8.0 SDK](https://dotnet.microsoft.com/download/dotnet/8.0)** or higher
* Your preferred IDE (Visual Studio 2022, VS Code, or Rider)
**.NET Version Compatibility:** This quickstart works with **.NET 8.0** and newer.
## Get Started
This quickstart demonstrates how to add Auth0 JWT authentication to an ASP.NET Core Web API. You'll build a secure API with protected endpoints using the Auth0 ASP.NET Core API SDK.
Create a new ASP.NET Core Web API project for this Quickstart
```bash theme={null}
dotnet new webapi -n Auth0Api
```
Open the project
```bash theme={null}
cd Auth0Api
```
```bash theme={null}
dotnet add package Auth0.AspNetCore.Authentication.Api
```
Next up, you need to create a new API on your Auth0 tenant and add the configuration to your project.
You can choose to do this automatically by running a CLI command or do it manually via the Dashboard:
Run the following shell command on your project's root directory to create an Auth0 API and update your `appsettings.json` file:
```bash theme={null}
AUTH0_API_NAME="My ASP.NET Core API" && \
AUTH0_API_IDENTIFIER="https://my-api" && \
brew tap auth0/auth0-cli && \
brew install auth0 && \
auth0 login --no-input && \
auth0 apis create -n "${AUTH0_API_NAME}" -i "${AUTH0_API_IDENTIFIER}" --offline-access --token-lifetime 86400 --signing-alg RS256 --json > auth0-api-details.json && \
DOMAIN=$(auth0 tenants list --json | jq -r '.[] | select(.active == true) | .name') && \
AUDIENCE=$(jq -r '.identifier' auth0-api-details.json) && \
jq --arg domain "$DOMAIN" --arg audience "$AUDIENCE" \
'.Auth0.Domain = $domain | .Auth0.Audience = $audience' \
appsettings.json > appsettings.tmp.json && \
mv appsettings.tmp.json appsettings.json && \
rm auth0-api-details.json && \
echo "✅ appsettings.json updated with your Auth0 API details:" && \
cat appsettings.json
```
```powershell theme={null}
$ApiName = "My ASP.NET Core API"
$ApiIdentifier = "https://my-api"
$latestRelease = Invoke-RestMethod -Uri "https://api.github.com/repos/auth0/auth0-cli/releases/latest"
$latestVersion = $latestRelease.tag_name
$version = $latestVersion -replace "^v"
Invoke-WebRequest -Uri "https://github.com/auth0/auth0-cli/releases/download/${latestVersion}/auth0-cli_${version}_Windows_x86_64.zip" -OutFile ".\auth0.zip"
Expand-Archive ".\auth0.zip" .\
[System.Environment]::SetEnvironmentVariable('PATH', $Env:PATH + ";${pwd}")
auth0 login --no-input
auth0 apis create -n "$ApiName" -i "$ApiIdentifier" --offline-access --token-lifetime 86400 --signing-alg RS256 --json | Set-Content -Path auth0-api-details.json
$Domain = (auth0 tenants list --json | ConvertFrom-Json | Where-Object { $_.active -eq $true }).name
$Audience = (Get-Content -Raw auth0-api-details.json | ConvertFrom-Json).identifier
$Config = Get-Content -Raw appsettings.json | ConvertFrom-Json
if (-not $Config.Auth0) { $Config | Add-Member -MemberType NoteProperty -Name Auth0 -Value @{} }
$Config.Auth0.Domain = $Domain
$Config.Auth0.Audience = $Audience
$Config | ConvertTo-Json -Depth 10 | Set-Content appsettings.json
Remove-Item auth0-api-details.json
Write-Output "✅ appsettings.json updated with your Auth0 API details:"
Get-Content appsettings.json
```
Before you start, add Auth0 configuration to your `appsettings.json` file
```json appsettings.json theme={null}
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"Auth0": {
"Domain": "YOUR_AUTH0_DOMAIN",
"Audience": "YOUR_AUTH0_API_IDENTIFIER"
}
}
```
1. Go to [Auth0 Dashboard](https://manage.auth0.com) → **Applications** → **APIs**
2. Click **Create API**
3. Enter your API details:
* **Name**: My ASP.NET Core API
* **Identifier**: `https://my-api` (this becomes your Audience)
* **Signing Algorithm**: RS256
4. Click **Create**
5. Replace `YOUR_AUTH0_DOMAIN` in `appsettings.json` with your **Domain** from the Test tab (e.g., `your-tenant.auth0.com`)
6. Replace `YOUR_AUTH0_API_IDENTIFIER` in `appsettings.json` with your **Identifier** (e.g., `https://my-api`)
Your **Domain** should not include `https://` - use only the domain name (e.g., `your-tenant.auth0.com`).
The **Audience** (API Identifier) is a unique identifier for your API and can be any valid URI. It doesn't need to be a publicly accessible URL.
Replace the entire contents of `Program.cs` with the following code:
```csharp Program.cs lines theme={null}
using Auth0.AspNetCore.Authentication.Api;
using Microsoft.AspNetCore.Authentication.JwtBearer;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAuth0ApiAuthentication(options =>
{
options.Domain = builder.Configuration["Auth0:Domain"];
options.JwtBearerOptions = new JwtBearerOptions
{
Audience = builder.Configuration["Auth0:Audience"]
};
});
builder.Services.AddAuthorization();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseHttpsRedirection();
}
app.UseAuthentication();
app.UseAuthorization();
app.Run();
```
Add endpoints to test authentication. Add the following code in `Program.cs` before `app.Run()`:
```csharp Program.cs theme={null}
// Public endpoint - no authentication required
app.MapGet("/api/public", () =>
Results.Ok(new { Message = "This endpoint is public" }))
.WithName("GetPublic");
// Protected endpoint - requires authentication
app.MapGet("/api/private", () =>
Results.Ok(new { Message = "This endpoint requires authentication" }))
.RequireAuthorization()
.WithName("GetPrivate");
```
```bash theme={null}
dotnet run
```
Your API is now running on `https://localhost:7190` (or similar - check your console output for the exact URL).
**Checkpoint**
You should now have a fully functional Auth0-protected API running on your [localhost](https://localhost:7190/)
***
## Advanced Usage
Test your protected endpoints with an access token.
**1. Get an access token** from Auth0 using the Client Credentials flow:
```bash theme={null}
curl --request POST \
--url https://YOUR_DOMAIN/oauth/token \
--header 'content-type: application/json' \
--data '{"client_id":"YOUR_CLIENT_ID","client_secret":"YOUR_CLIENT_SECRET","audience":"YOUR_AUDIENCE","grant_type":"client_credentials"}'
```
To get `YOUR_CLIENT_ID` and `YOUR_CLIENT_SECRET`, create a Machine to Machine Application in the [Auth0 Dashboard](https://manage.auth0.com/#/applications) and authorize it for your API.
**2. Test the public endpoint** (should return 200 OK):
```bash theme={null}
curl https://localhost:7190/api/public
```
**3. Test the protected endpoint without authentication** (should return 401 Unauthorized):
```bash theme={null}
curl https://localhost:7190/api/private
```
**4. Call the protected endpoint with the token:**
```bash theme={null}
curl https://localhost:7190/api/private \
--header 'Authorization: Bearer YOUR_ACCESS_TOKEN'
```
For larger APIs, use controllers instead of minimal API endpoints.
**1. Add controllers support:**
```csharp Program.cs theme={null}
builder.Services.AddControllers();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseHttpsRedirection();
}
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
```
**2. Create a controller:**
Create `Controllers/MessagesController.cs`:
```csharp Controllers/MessagesController.cs theme={null}
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace Auth0Api.Controllers;
[ApiController]
[Route("api/[controller]")]
public class MessagesController : ControllerBase
{
[HttpGet]
public IActionResult GetPublic()
{
return Ok(new { Message = "This endpoint is public" });
}
[Authorize]
[HttpGet("private")]
public IActionResult GetPrivate()
{
var userId = User.FindFirst("sub")?.Value;
return Ok(new { Message = "This endpoint is protected", UserId = userId });
}
[Authorize(Policy = "read:messages")]
[HttpGet("messages")]
public IActionResult GetMessages()
{
return Ok(new { Messages = new[] { "Message 1", "Message 2" } });
}
}
```
Protect endpoints based on specific scopes in the access token.
**1. Define scopes in your Auth0 API:**
In the [Auth0 Dashboard](https://manage.auth0.com) → APIs → Your API → Permissions, add scopes:
* `read:messages` - Read messages
* `write:messages` - Write messages
**2. Configure authorization policies:**
```csharp Program.cs theme={null}
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("read:messages", policy =>
policy.RequireClaim("scope", "read:messages"));
options.AddPolicy("write:messages", policy =>
policy.RequireClaim("scope", "write:messages"));
});
```
**3. Apply policies to endpoints:**
```csharp theme={null}
app.MapGet("/api/messages", () =>
Results.Ok(new { Messages = new[] { "Message 1", "Message 2" } }))
.RequireAuthorization("read:messages");
app.MapPost("/api/messages", () =>
Results.Created("/api/messages/1", new { Id = 1, Text = "New message" }))
.RequireAuthorization("write:messages");
```
When requesting an access token, include the required scope:
```bash theme={null}
curl --request POST \
--url https://YOUR_DOMAIN/oauth/token \
--header 'content-type: application/json' \
--data '{"client_id":"YOUR_CLIENT_ID","client_secret":"YOUR_CLIENT_SECRET","audience":"YOUR_AUDIENCE","grant_type":"client_credentials","scope":"read:messages write:messages"}'
```
DPoP (Demonstration of Proof-of-Possession) binds access tokens to cryptographic keys, preventing token theft and replay attacks.
**Enable DPoP support:**
```csharp Program.cs theme={null}
builder.Services.AddAuth0ApiAuthentication(options =>
{
options.Domain = builder.Configuration["Auth0:Domain"];
options.JwtBearerOptions = new JwtBearerOptions
{
Audience = builder.Configuration["Auth0:Audience"]
};
}).WithDPoP(); // Enable DPoP with default settings
```
**DPoP Modes:**
Accept both DPoP and Bearer tokens (default):
```csharp theme={null}
using Auth0.AspNetCore.Authentication.Api.DPoP;
.WithDPoP(dpopOptions =>
{
dpopOptions.Mode = DPoPModes.Allowed;
});
```
Only accept DPoP tokens, reject Bearer tokens:
```csharp theme={null}
using Auth0.AspNetCore.Authentication.Api.DPoP;
.WithDPoP(dpopOptions =>
{
dpopOptions.Mode = DPoPModes.Required;
});
```
Configure time validation parameters:
```csharp theme={null}
.WithDPoP(dpopOptions =>
{
dpopOptions.Mode = DPoPModes.Allowed;
dpopOptions.IatOffset = 300; // Allow DPoP proof up to 5 minutes old
dpopOptions.Leeway = 30; // 30 seconds clock skew tolerance
});
```
Learn more about DPoP in the [Auth0 DPoP Documentation](https://auth0.com/docs/secure/sender-constraining/demonstrating-proof-of-possession-dpop).
Create reusable authorization policies for complex requirements.
**1. Create a custom requirement:**
```csharp Authorization/HasScopeRequirement.cs theme={null}
using Microsoft.AspNetCore.Authorization;
namespace Auth0Api.Authorization;
public class HasScopeRequirement : IAuthorizationRequirement
{
public string Scope { get; }
public string Issuer { get; }
public HasScopeRequirement(string scope, string issuer)
{
Scope = scope;
Issuer = issuer;
}
}
```
**2. Create a handler:**
```csharp Authorization/HasScopeHandler.cs theme={null}
using Microsoft.AspNetCore.Authorization;
namespace Auth0Api.Authorization;
public class HasScopeHandler : AuthorizationHandler
{
protected override Task HandleRequirementAsync(
AuthorizationHandlerContext context,
HasScopeRequirement requirement)
{
if (!context.User.HasClaim(c => c.Type == "scope" && c.Issuer == requirement.Issuer))
{
return Task.CompletedTask;
}
var scopes = context.User
.FindFirst(c => c.Type == "scope" && c.Issuer == requirement.Issuer)?
.Value.Split(' ');
if (scopes?.Any(s => s == requirement.Scope) == true)
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
```
**3. Register and use the policy:**
```csharp Program.cs theme={null}
using Auth0Api.Authorization;
var builder = WebApplication.CreateBuilder(args);
var domain = $"https://{builder.Configuration["Auth0:Domain"]}";
builder.Services.AddAuth0ApiAuthentication(options =>
{
options.Domain = builder.Configuration["Auth0:Domain"];
options.JwtBearerOptions = new JwtBearerOptions
{
Audience = builder.Configuration["Auth0:Audience"]
};
});
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("read:messages", policy =>
policy.Requirements.Add(new HasScopeRequirement("read:messages", domain)));
});
builder.Services.AddSingleton();
var app = builder.Build();
// ... rest of configuration
```
Extract user information from the authenticated token.
```csharp theme={null}
app.MapGet("/api/user-info", (HttpContext context) =>
{
var userId = context.User.FindFirst("sub")?.Value;
var email = context.User.FindFirst("email")?.Value;
var name = context.User.FindFirst("name")?.Value;
var scopes = context.User.FindAll("scope")
.SelectMany(c => c.Value.Split(' '))
.Distinct();
return Results.Ok(new
{
UserId = userId,
Email = email,
Name = name,
Scopes = scopes
});
})
.RequireAuthorization();
```
Customize JWT token validation parameters for specific requirements.
```csharp Program.cs theme={null}
using Microsoft.IdentityModel.Tokens;
using System.Security.Claims;
builder.Services.AddAuth0ApiAuthentication(options =>
{
options.Domain = builder.Configuration["Auth0:Domain"];
options.JwtBearerOptions = new JwtBearerOptions
{
Audience = builder.Configuration["Auth0:Audience"],
TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ClockSkew = TimeSpan.FromMinutes(5),
NameClaimType = ClaimTypes.NameIdentifier,
RoleClaimType = "https://my-app.com/roles"
},
Events = new JwtBearerEvents
{
OnAuthenticationFailed = context =>
{
Console.WriteLine($"Authentication failed: {context.Exception.Message}");
return Task.CompletedTask;
},
OnTokenValidated = context =>
{
var userId = context.Principal?.FindFirst("sub")?.Value;
Console.WriteLine($"Token validated for user: {userId}");
return Task.CompletedTask;
}
}
};
});
```
***
## Additional Resources
Complete SDK documentation and API reference
Migrate from JWT Bearer authentication
Comprehensive code examples and patterns
Learn about proof-of-possession security
Security best practices for tokens
Get help from the Auth0 community
***
## Common Issues
**Problem:** Token validation fails with audience mismatch error.
**Solution:** Ensure the `Audience` in `appsettings.json` exactly matches the Identifier of your Auth0 API. The audience claim in the token must match this value.
```json theme={null}
{
"Auth0": {
"Audience": "https://my-api" // Must match Auth0 API Identifier
}
}
```
**Problem:** Token validation fails with issuer error.
**Solution:** Verify your Domain is correct and does not include `https://`. The library automatically constructs the authority as `https://{Domain}`.
```json theme={null}
{
"Auth0": {
"Domain": "your-tenant.auth0.com" // No https://
}
}
```
**Problem:** `ArgumentNullException: Value cannot be null. (Parameter 'Domain')` or similar.
**Solution:** Ensure `appsettings.json` contains the Auth0 section with Domain and Audience values. Check that configuration is being read correctly:
```csharp theme={null}
builder.Services.AddAuth0ApiAuthentication(options =>
{
options.Domain = builder.Configuration["Auth0:Domain"]
?? throw new InvalidOperationException("Auth0:Domain is required");
options.JwtBearerOptions = new JwtBearerOptions
{
Audience = builder.Configuration["Auth0:Audience"]
?? throw new InvalidOperationException("Auth0:Audience is required")
};
});
```
**Problem:** SSL/TLS certificate errors when running locally.
**Solution:** Trust the development certificate:
```bash theme={null}
dotnet dev-certs https --trust
```
Or generate a new certificate:
```bash theme={null}
dotnet dev-certs https --clean
dotnet dev-certs https --trust
```
**Problem:** Authentication not working despite correct configuration.
**Solution:** Ensure middleware is in the correct order. `UseAuthentication()` must come before `UseAuthorization()`:
```csharp theme={null}
app.UseAuthentication(); // Must be before UseAuthorization
app.UseAuthorization();
app.MapControllers();
```
**Problem:** Scope-based authorization policies always fail.
**Solution:** Ensure your access token includes the required scopes. When requesting a token, specify the scopes:
```bash theme={null}
curl --request POST \
--url https://YOUR_DOMAIN/oauth/token \
--data '{"client_id":"...","client_secret":"...","audience":"...","grant_type":"client_credentials","scope":"read:messages write:messages"}'
```
Also verify scopes are defined in your Auth0 API settings (Dashboard → APIs → Your API → Permissions).
***
## Sample Application
A complete sample application demonstrating all features is available in the SDK repository.
Includes public and protected endpoints, DPoP support, Swagger UI integration, and Postman collection
Clone and run:
```bash theme={null}
git clone https://github.com/auth0/aspnetcore-api.git
cd aspnetcore-api/Auth0.AspNetCore.Authentication.Api.Playground
# Update appsettings.json with your Auth0 configuration
dotnet run
```
# Add Authorization to Your Django API Application
Source: https://auth0.com/docs/quickstart/backend/django/interactive
This tutorial demonstrates how to add authorization to a Python API built with Django.
This guide demonstrates how to integrate Auth0 with any new or existing Python API built with [Django](https://www.djangoproject.com/).
If you haven't created an API in your Auth0 Dashboard yet, you can use the interactive selector to create a new
Auth0 API or select an existing API that represents the project you want to integrate with.
Alternatively, you can read our getting started guide,
which will help you set up your first API through the Auth0 Dashboard.
Every API in Auth0 is configured using an API Identifier that your application code will use as the Audience to
validate the Access Token.
**New to Auth0?** Learn how Auth0 works and
read about implementing API authentication and
authorization using the OAuth 2.0 framework.
Permissions let you define how resources can be accessed on behalf of the user with a given access token. For
example, you might choose to grant read access to the `messages` resource if users have the manager
access level, and grant write access to that resource if they have the administrator access level.
You can define allowed permissions in the **Permissions** view of the Auth0 Dashboard's [APIs](https://manage.auth0.com/#/apis) section. The following
example uses the `read:messages` scope.
### Install dependencies
1. Add the following dependencies to your `requirements.txt`:
2. Run `pip install -r requirements.txt`
### Create a Django application
You will use a library called [Authlib](https://github.com/lepture/authlib) to create a [ResourceProtector](https://docs.authlib.org/en/latest/flask/1/resource-server.html), which is a type of [Django view decorator](https://docs.djangoproject.com/en/4.0/topics/http/decorators/) that protects your resources (API views) with a given
validator.
The validator will verify the Access Token that you pass to the resource by checking that it has a valid
signature and claims.
You can use AuthLib's `JWTBearerTokenValidator` validator with a few tweaks to make sure it conforms
to our requirements for [validating Access Tokens](https://auth0.com/docs/secure/tokens/access-tokens/validate-access-tokens).
To create your `Auth0JWTBearerTokenValidator`, you need to pass it to your `domain` and
`audience` (API Identifier). It will then get the public key required to verify the token's signature
and pass it to the `JWTBearerTokenValidator` class.
You'll then override the class's `claims_options` to make sure the token's `expiry`,
`audience`, and `issue` claims are validated according to our requirements.
Create the file `apiexample/validator.py` using the code from the interactive panel.
Next, you'll create three API views in `apiexample/views.py`:
* `/api/public`: A public endpoint that requires no authentication.
* `/api/private`: A private endpoint that requires a valid Access Token JWT.
* `/api/private-scoped`: A private endpoint that requires a valid Access Token JWT containing the
given `scope`.
The protected routes will have a `require_auth` decorator, which is a `ResourceProtector`
that uses the `Auth0JWTBearerTokenValidator` you created earlier.
To create the `Auth0JWTBearerTokenValidator`, you'll pass it to your tenant's domain and the API
Identifier of the API you created earlier.
The `require_auth` decorator on the `private_scoped` route accepts an additional argument
`"read:messages"`, which checks the Access Token for the Permission (Scope) you created earlier.
In previous steps, you added methods to the `views.py` file. Next, map those methods to URLs using
Django's [URL dispatcher](https://docs.djangoproject.com/en/4.0/topics/http/urls/), which lets you map URL patterns to views.
Add the URL patterns to your `apiexample/urls.py` file.
### Make a Call to Your API
To make calls to your API, you will need an access token. You can retrieve an access token for testing purposes
from the **Test** view in your [API settings](https://manage.auth0.com/#/apis).
Provide the access token as an `Authorization` header in your requests.
```bash cURL lines theme={null}
curl --request get \
--url 'http:///%7ByourDomain%7D.com/api_path' \
--header 'authorization: Bearer YOUR_ACCESS_TOKEN_HERE'
```
```csharp C# lines theme={null}
var client = new RestClient("http:///%7ByourDomain%7D.com/api_path");
var request = new RestRequest(Method.GET);
request.AddHeader("authorization", "Bearer YOUR_ACCESS_TOKEN_HERE");
IRestResponse response = client.Execute(request);
```
```go Go lines theme={null}
package main
import (
"fmt"
"net/http"
"io/ioutil"
)
func main() {
url := "http:///%7ByourDomain%7D.com/api_path"
req, _ := http.NewRequest("get", url, nil)
req.Header.Add("authorization", "Bearer YOUR_ACCESS_TOKEN_HERE")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := ioutil.ReadAll(res.Body)
fmt.Println(res)
fmt.Println(string(body))
}
```
```java Java lines theme={null}
HttpResponse response = Unirest.get("http:///%7ByourDomain%7D.com/api_path")
.header("authorization", "Bearer YOUR_ACCESS_TOKEN_HERE")
.asString();
```
```javascript Node.JS lines theme={null}
var axios = require("axios").default;
var options = {
method: 'get',
url: 'http:///%7ByourDomain%7D.com/api_path',
headers: {authorization: 'Bearer YOUR_ACCESS_TOKEN_HERE'}
};
axios.request(options).then(function (response) {
console.log(response.data);
}).catch(function (error) {
console.error(error);
});
```
```objc Obj-C lines theme={null}
#import
NSDictionary *headers = @{ @"authorization": @"Bearer YOUR_ACCESS_TOKEN_HERE" };
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http:///%7ByourDomain%7D.com/api_path"]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:10.0];
[request setHTTPMethod:@"get"];
[request setAllHTTPHeaderFields:headers];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
NSLog(@"%@", error);
} else {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
NSLog(@"%@", httpResponse);
}
}];
[dataTask resume];
```
```php PHP lines theme={null}
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "http:///%7ByourDomain%7D.com/api_path",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "get",
CURLOPT_HTTPHEADER => [
"authorization: Bearer YOUR_ACCESS_TOKEN_HERE"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
```
```python Python lines theme={null}
import http.client
conn = http.client.HTTPConnection("")
headers = { 'authorization': "Bearer YOUR_ACCESS_TOKEN_HERE" }
conn.request("get", "/{yourDomain}.com/api_path", headers=headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
```
```ruby Ruby lines theme={null}
require 'uri'
require 'net/http'
url = URI("http:///%7ByourDomain%7D.com/api_path")
http = Net::HTTP.new(url.host, url.port)
request = Net::HTTP::Get.new(url)
request["authorization"] = 'Bearer YOUR_ACCESS_TOKEN_HERE'
response = http.request(request)
puts response.read_body
```
```swift Swift lines theme={null}
import Foundation
let headers = ["authorization": "Bearer YOUR_ACCESS_TOKEN_HERE"]
let request = NSMutableURLRequest(url: NSURL(string: "http:///%7ByourDomain%7D.com/api_path")! as URL,
cachePolicy: .useProtocolCachePolicy,
timeoutInterval: 10.0)
request.httpMethod = "get"
request.allHTTPHeaderFields = headers
let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
if (error != nil) {
print(error)
} else {
let httpResponse = response as? HTTPURLResponse
print(httpResponse)
}
})
dataTask.resume()
```
## Next Steps
Excellent work! If you made it this far, you should now have login, logout, and user profile information running in your application.
This concludes our quickstart tutorial, but there is so much more to explore. To learn more about what you can do with Auth0, check out:
* [Auth0 Dashboard](https://manage.auth0.com/dashboard/us/dev-gja8kxz4ndtex3rq) - Learn how to configure and manage your Auth0 tenant and applications
* [Auth0 Marketplace](https://marketplace.auth0.com/) - Discover integrations you can enable to extend Auth0’s functionality
```py apiexample/views.py lines highlight={} theme={null}
from authlib.integrations.django_oauth2 import ResourceProtector
from django.http import JsonResponse
from . import validator
require_auth = ResourceProtector()
validator = validator.Auth0JWTBearerTokenValidator(
"{yourDomain}",
"{yourApiIdentifier}"
)
require_auth.register_token_validator(validator)
def public(request):
"""No access token required to access this route
"""
response = "Hello from a public endpoint! You don't need to be authenticated to see this."
return JsonResponse(dict(message=response))
@require_auth(None)
def private(request):
"""A valid access token is required to access this route
"""
response = "Hello from a private endpoint! You need to be authenticated to see this."
return JsonResponse(dict(message=response))
@require_auth("read:messages")
def private_scoped(request):
"""A valid access token and an appropriate scope are required to access this route
"""
response = "Hello from a private endpoint! You need to be authenticated and have a scope of read:messages to see this."
return JsonResponse(dict(message=response))
```
```py apiexample/validator.py lines highlight={} theme={null}
import json
from urllib.request import urlopen
from authlib.oauth2.rfc7523 import JWTBearerTokenValidator
from authlib.jose.rfc7517.jwk import JsonWebKey
class Auth0JWTBearerTokenValidator(JWTBearerTokenValidator):
def __init__(self, domain, audience):
issuer = f"https://{domain}/"
jsonurl = urlopen(f"{issuer}.well-known/jwks.json")
public_key = JsonWebKey.import_key_set(
json.loads(jsonurl.read())
)
super(Auth0JWTBearerTokenValidator, self).__init__(
public_key
)
self.claims_options = {
"exp": {"essential": True},
"aud": {"essential": True, "value": audience},
"iss": {"essential": True, "value": issuer},
}
```
```py apiexample/urls.py lines highlight={8-10} theme={null}
from django.contrib import admin
from django.urls import path
from . import views
urlpatterns = [
path('admin/', admin.site.urls),
path('api/public', views.public),
path('api/private', views.private),
path('api/private-scoped', views.private_scoped)
]
```
```py apiexample/validator.py lines highlight={} theme={null}
import json
from urllib.request import urlopen
from authlib.oauth2.rfc7523 import JWTBearerTokenValidator
from authlib.jose.rfc7517.jwk import JsonWebKey
class Auth0JWTBearerTokenValidator(JWTBearerTokenValidator):
def __init__(self, domain, audience):
issuer = f"https://{domain}/"
jsonurl = urlopen(f"{issuer}.well-known/jwks.json")
public_key = JsonWebKey.import_key_set(
json.loads(jsonurl.read())
)
super(Auth0JWTBearerTokenValidator, self).__init__(
public_key
)
self.claims_options = {
"exp": {"essential": True},
"aud": {"essential": True, "value": audience},
"iss": {"essential": True, "value": issuer},
}
```
```py apiexample/views.py lines highlight={} theme={null}
from authlib.integrations.django_oauth2 import ResourceProtector
from django.http import JsonResponse
from . import validator
require_auth = ResourceProtector()
validator = validator.Auth0JWTBearerTokenValidator(
"{yourDomain}",
"{yourApiIdentifier}"
)
require_auth.register_token_validator(validator)
def public(request):
"""No access token required to access this route
"""
response = "Hello from a public endpoint! You don't need to be authenticated to see this."
return JsonResponse(dict(message=response))
@require_auth(None)
def private(request):
"""A valid access token is required to access this route
"""
response = "Hello from a private endpoint! You need to be authenticated to see this."
return JsonResponse(dict(message=response))
@require_auth("read:messages")
def private_scoped(request):
"""A valid access token and an appropriate scope are required to access this route
"""
response = "Hello from a private endpoint! You need to be authenticated and have a scope of read:messages to see this."
return JsonResponse(dict(message=response))
```
```py apiexample/urls.py lines highlight={8-10} theme={null}
from django.contrib import admin
from django.urls import path
from . import views
urlpatterns = [
path('admin/', admin.site.urls),
path('api/public', views.public),
path('api/private', views.private),
path('api/private-scoped', views.private_scoped)
]
```
```py apiexample/urls.py lines highlight={8-10} theme={null}
from django.contrib import admin
from django.urls import path
from . import views
urlpatterns = [
path('admin/', admin.site.urls),
path('api/public', views.public),
path('api/private', views.private),
path('api/private-scoped', views.private_scoped)
]
```
```py apiexample/validator.py lines highlight={} theme={null}
import json
from urllib.request import urlopen
from authlib.oauth2.rfc7523 import JWTBearerTokenValidator
from authlib.jose.rfc7517.jwk import JsonWebKey
class Auth0JWTBearerTokenValidator(JWTBearerTokenValidator):
def __init__(self, domain, audience):
issuer = f"https://{domain}/"
jsonurl = urlopen(f"{issuer}.well-known/jwks.json")
public_key = JsonWebKey.import_key_set(
json.loads(jsonurl.read())
)
super(Auth0JWTBearerTokenValidator, self).__init__(
public_key
)
self.claims_options = {
"exp": {"essential": True},
"aud": {"essential": True, "value": audience},
"iss": {"essential": True, "value": issuer},
}
```
```py apiexample/views.py lines highlight={} theme={null}
from authlib.integrations.django_oauth2 import ResourceProtector
from django.http import JsonResponse
from . import validator
require_auth = ResourceProtector()
validator = validator.Auth0JWTBearerTokenValidator(
"{yourDomain}",
"{yourApiIdentifier}"
)
require_auth.register_token_validator(validator)
def public(request):
"""No access token required to access this route
"""
response = "Hello from a public endpoint! You don't need to be authenticated to see this."
return JsonResponse(dict(message=response))
@require_auth(None)
def private(request):
"""A valid access token is required to access this route
"""
response = "Hello from a private endpoint! You need to be authenticated to see this."
return JsonResponse(dict(message=response))
@require_auth("read:messages")
def private_scoped(request):
"""A valid access token and an appropriate scope are required to access this route
"""
response = "Hello from a private endpoint! You need to be authenticated and have a scope of read:messages to see this."
return JsonResponse(dict(message=response))
```
# Protect Your Express.js API
Source: https://auth0.com/docs/quickstart/backend/express-api-beta
This guide demonstrates how to protect Express.js API endpoints using JWT access tokens with the @auth0/auth0-express-api SDK (Beta).
This Quickstart is currently in **Beta**. We'd love to hear your feedback!
**Prerequisites:** Before you begin, ensure you have the following installed:
* [Node.js](https://nodejs.org/) 22 LTS or newer
* [npm](https://www.npmjs.com/) 10+ or [yarn](https://yarnpkg.com/) 1.22+
## Get Started
This quickstart demonstrates how to protect Express.js API endpoints using JWT access tokens. You'll build a secure API that validates Auth0 access tokens, protects routes, and implements scope- and claim-based authorization.
Create a new directory for your Express API and initialize a Node.js project.
```shellscript Mac theme={null}
mkdir auth0-express-api && cd auth0-express-api
npm init -y
touch server.js .env
```
```shellscript Windows theme={null}
mkdir auth0-express-api; cd auth0-express-api
npm init -y
New-Item server.js, .env
```
Update your `package.json` to use ES modules and add start scripts:
```json theme={null}
{
"name": "auth0-express-api",
"version": "1.0.0",
"type": "module",
"main": "server.js",
"scripts": {
"start": "node server.js",
"dev": "node --watch server.js"
}
}
```
Install `@auth0/auth0-express-api` along with `express` and `dotenv`:
```shell theme={null}
npm install @auth0/auth0-express-api@beta express dotenv
```
You need to create a new API on your Auth0 tenant and configure your environment variables.
Run the following command in your project root to create an Auth0 API:
```shellscript Mac theme={null}
# Install Auth0 CLI (if not already installed)
brew tap auth0/auth0-cli && brew install auth0
# Create Auth0 API
auth0 apis create \
--name "My Express API" \
--identifier https://my-express-api.example.com
```
```powershell Windows theme={null}
# Install Auth0 CLI (if not already installed)
scoop bucket add auth0 https://github.com/auth0/scoop-auth0-cli.git
scoop install auth0
# Create Auth0 API
auth0 apis create `
--name "My Express API" `
--identifier https://my-express-api.example.com
```
After creation, copy the **Identifier** and your **Domain** values, then create your `.env` file:
Replace `YOUR_API_IDENTIFIER` with the identifier you used above (e.g., `https://my-express-api.example.com`).
1. Go to [Auth0 Dashboard](https://manage.auth0.com/) → **Applications > APIs** → **Create API**
2. Enter a name (e.g., "My Express API")
3. Set the **Identifier** — this is your API audience (e.g., `https://my-express-api.example.com`). It doesn't need to be a real URL.
4. Keep **Signing Algorithm** as **RS256**
5. Click **Create**
6. Copy the **Domain** from your tenant and the **Identifier** from **API Settings**
Create your `.env` file:
Replace `YOUR_AUTH0_DOMAIN` with your Auth0 tenant domain (e.g., `dev-abc123.us.auth0.com`) and `YOUR_API_IDENTIFIER` with the API identifier you set above.
Register `createAuth0Api()` on your Express application to configure JWT validation. Then add public and protected routes.
```javascript server.js theme={null}
import 'dotenv/config';
import express from 'express';
import { createAuth0Api, requiresAuth } from '@auth0/auth0-express-api';
const app = express();
const port = process.env.PORT || 3001;
app.use(express.json());
app.use(createAuth0Api());
// Public route — no token required
app.get('/api/public', (req, res) => {
res.json({
message: 'Hello from a public endpoint! No authentication required.',
timestamp: new Date().toISOString(),
});
});
// Protected route — requires a valid access token
app.get('/api/private', requiresAuth(), (req, res) => {
res.json({
message: 'Hello from a protected endpoint! You are authenticated.',
sub: req.auth0.user?.sub,
timestamp: new Date().toISOString(),
});
});
app.listen(port, () => {
console.log(`API server running at http://localhost:${port}`);
});
```
**What this does:**
* `createAuth0Api()` reads `AUTH0_DOMAIN` and `AUTH0_AUDIENCE` from environment variables automatically
* `requiresAuth()` validates the `Authorization: Bearer ` header on each request
* `req.auth0.user` contains the decoded JWT claims for authenticated requests — `sub` is the user's unique identifier
Beyond requiring a valid token, you can require a specific scope. Pass a `scopes` option to `requiresAuth()` — the SDK returns `403 insufficient_scope` if the token is missing the scope.
```javascript server.js theme={null}
// Requires the "read:messages" scope
app.get('/api/messages', requiresAuth({ scopes: ['read:messages'] }), (req, res) => {
res.json({ messages: ['Hello!', 'World!'] });
});
```
Define the scope in your API's **Permissions** tab (see [Advanced Usage](#advanced-usage)) and request it when obtaining the access token. For matching multiple scopes or authorizing on custom claims, the SDK also provides `scopesInclude`, `claimEquals`, `claimIncludes`, and `claimCheck` — covered in [Advanced Usage](#advanced-usage).
Start the development server:
```shell theme={null}
npm run dev
```
Your API is now running at [http://localhost:3001](http://localhost:3001).
Test the public endpoint (no token required):
```shell theme={null}
curl http://localhost:3001/api/public
```
Expected response:
```json theme={null}
{
"message": "Hello from a public endpoint! No authentication required.",
"timestamp": "2026-06-22T12:00:00.000Z"
}
```
To call the protected endpoint, you need an access token:
1. Go to [Auth0 Dashboard](https://manage.auth0.com/) → **Applications > APIs**
2. Select your API → **Test** tab
3. Copy the generated access token
Test the protected endpoint:
```shell theme={null}
curl http://localhost:3001/api/private \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
```
Expected response:
```json theme={null}
{
"message": "Hello from a protected endpoint! You are authenticated.",
"sub": "auth0|abc123...",
"timestamp": "2026-06-22T12:00:00.000Z"
}
```
**Checkpoint**
You should now have a protected API. Your API:
1. Accepts requests to public endpoints without a token
2. Returns the protected response when a valid access token is provided
3. Validates JWTs against your Auth0 domain and audience
4. Exposes decoded token claims via `req.auth0.user`
***
## Advanced Usage
Use `scopesInclude` when a route should accept any one of several scopes, or require several at once. By default it matches **any** of the listed scopes; pass `{ match: 'all' }` to require all of them. Scopes can be passed as an array or a space-separated string — these examples use arrays.
```javascript server.js theme={null}
import { scopesInclude } from '@auth0/auth0-express-api';
// Requires ANY of these scopes
app.get('/api/feed', requiresAuth(), scopesInclude(['read:feed', 'read:admin']), (req, res) => {
res.json({ feed: [] });
});
// Requires ALL of these scopes
app.get('/api/admin/edit', requiresAuth(), scopesInclude(['read:admin', 'write:admin'], { match: 'all' }), (req, res) => {
res.json({ message: 'Admin editor access granted.' });
});
```
When authorization depends on claims other than `scope`, use `claimEquals`, `claimIncludes`, or `claimCheck`. Each runs after `requiresAuth()` and returns `401 invalid_token` if the claim requirement isn't met.
```javascript server.js theme={null}
import { claimEquals, claimIncludes, claimCheck } from '@auth0/auth0-express-api';
// claimEquals — claim must equal an exact value
app.get('/api/admin', requiresAuth(), claimEquals('isAdmin', true), (req, res) => {
res.json({ message: 'Admin access granted.' });
});
// claimIncludes — array claim must contain all listed values
app.get('/api/editor', requiresAuth(), claimIncludes('roles', ['admin', 'editor']), (req, res) => {
res.json({ message: 'Editor access granted.' });
});
// claimCheck — custom logic over the decoded token
app.get('/api/premium', requiresAuth(), claimCheck(
(req, token) => token.tier === 'premium' || token.roles?.includes('admin'),
{ errorMessage: 'Premium tier or admin role required' }
), (req, res) => {
res.json({ message: 'Premium content access granted.' });
});
```
If you're using TypeScript, augment the `Token` interface to get type-safe access to custom claims:
```typescript server.ts theme={null}
import '@auth0/auth0-express-api';
declare module '@auth0/auth0-express-api' {
interface Token {
tier: 'free' | 'premium';
roles: string[];
'https://myapp.com/org_id': string;
}
}
```
Install type support:
```shell theme={null}
npm install -D typescript @types/express @types/node
```
Enable CORS to allow your web application to call the API:
```shell theme={null}
npm install cors
```
```javascript server.js theme={null}
import cors from 'cors';
app.use(cors({
origin: ['http://localhost:3000', 'http://localhost:5173'],
allowedHeaders: ['Authorization', 'Content-Type'],
exposedHeaders: ['WWW-Authenticate'],
}));
app.use(createAuth0Api());
```
For production, specify exact allowed origins instead of wildcards.
To use scope-based authorization, first define the permissions on your API:
1. Go to [Auth0 Dashboard](https://manage.auth0.com/) → **Applications > APIs** → your API
2. Navigate to the **Permissions** tab
3. Add permissions like `read:messages`, `write:messages`, `read:admin`
4. Click **Save**
Your client application must then request these scopes when obtaining an access token. If a token lacks the required scope, the API returns `403 Forbidden`.
***
## Troubleshooting
**Cause:** The `Authorization` header is missing or malformed, so no bearer token could be extracted. Per [RFC 6750](https://datatracker.ietf.org/doc/html/rfc6750#section-3), the SDK returns `401` with a bare `WWW-Authenticate: Bearer` header and no error body in this case. This is distinct from a token that is *present but invalid or expired*, which returns `401` with an `invalid_token` error and a JSON body (see below).
**Fix:**
1. Ensure the header is present: `Authorization: Bearer YOUR_TOKEN`
2. Verify "Bearer" (with a capital B and a space) precedes the token
**Cause:** The token was not issued for this API, or the domain/audience values don't match.
**Fix:**
1. Decode your token at [jwt.io](https://jwt.io)
2. Check `iss` matches `https://{yourDomain}/` (note the trailing slash)
3. Check `aud` matches your `AUTH0_AUDIENCE` exactly
4. Make sure you're using an **access token**, not an ID token — access tokens are obtained with the `audience` parameter
**Cause:** The token does not include the required scope.
**Fix:**
1. Verify the scope is defined in your API's Permissions tab in the Auth0 Dashboard
2. Ensure the client is requesting the scope when obtaining the access token
3. Decode the token at [jwt.io](https://jwt.io) and check the `scope` claim
**Cause:** `dotenv` is not configured, or variable names are wrong.
**Fix:**
1. Ensure `import 'dotenv/config'` is the first import in your entry file
2. Verify `.env` contains `AUTH0_DOMAIN` and `AUTH0_AUDIENCE`
3. Debug:
```javascript theme={null}
console.log({
domain: !!process.env.AUTH0_DOMAIN,
audience: !!process.env.AUTH0_AUDIENCE,
});
```
**Cause:** The `@auth0/auth0-express-api` SDK uses ES modules.
**Fix:** Add `"type": "module"` to your `package.json`:
📁 **package.json**
```json theme={null}
{
"type": "module"
}
```
Or rename your server file to `server.mjs`.
***
## Next Steps
* **[Add Login to an Express Web App](/docs/quickstart/webapp/express-beta)** — Use `@auth0/auth0-express` for session-based auth in web apps
* **[Role-Based Access Control](https://auth0.com/docs/manage-users/access-control/rbac)** — Implement fine-grained permissions
* **[Access Token Best Practices](https://auth0.com/docs/secure/tokens/access-tokens)** — Learn about access token handling
* **[Monitor Your API](https://auth0.com/docs/deploy-monitor/logs)** — Set up logging and monitoring
***
## Resources
* **[auth0/auth0-express-api GitHub](https://github.com/auth0/auth0-express/tree/main/packages/auth0-express-api)** — Source code and examples
* **[Auth0 Community](https://community.auth0.com/)** — Get help from the community
* **[JWT.io](https://jwt.io/)** — Debug and decode JWTs
# FastAPI API
Source: https://auth0.com/docs/quickstart/backend/fastapi
Learn how to add Auth0 JWT authentication to a FastAPI backend in Python, validating access tokens and gating endpoints by audience and scope.
**Using AI to integrate Auth0?** Add this prompt to Cursor, Windsurf, Copilot, Claude Code or your favourite AI-powered IDE to speed up development.
```markdown expandable theme={null}
Integrate the Auth0 FastAPI SDK into a Python API
AI PERSONA & PRIMARY OBJECTIVE
You are a helpful Auth0 SDK Integration Assistant for FastAPI APIs. Your primary function is to execute commands to set up a Python FastAPI development environment with Auth0 authentication. Your secondary function is to modify the files created during setup.
CRITICAL BEHAVIORAL INSTRUCTIONS
1. CHECK EXISTING PROJECT FIRST: Before creating a new project, check if the current directory already contains a Python project (requirements.txt, pyproject.toml, or .py files). If it does, skip project creation and work with the existing project.
2. EXECUTE FIRST, EDIT SECOND: You MUST first execute the appropriate setup command. Do not show, suggest, or create any files until the setup is complete.
3. NO PLANNING: DO NOT propose a directory structure. DO NOT show a file tree. Your first action must be to run the appropriate command.
4. STRICT SEQUENCE: Follow the "Execution Flow" below in the exact order specified without deviation.
5. SECURITY FIRST: NEVER hardcode Auth0 Domain or Audience values. ALWAYS use environment variables via python-dotenv.
6. 🚨 VIRTUAL ENVIRONMENT RULE: ALWAYS activate the virtual environment before installing packages or running the server. Never skip venv activation.
EXECUTION FLOW
⚠️ CRITICAL: Before ANY command execution, run `pwd` to check current directory and verify you're in the correct location.
Step 1: Check for Existing FastAPI Project and Prerequisites
FIRST, verify prerequisites and check for existing Python project:
# Check if Python 3.9+ and pip are available
python3 --version && pip --version
Then examine the current directory:
# Check for existing Python project
if [ -f "requirements.txt" ] || [ -f "pyproject.toml" ] || [ -f "app.py" ]; then
echo "Found existing Python project"
ls -la
else
echo "No Python project found, will create new project"
fi
Based on the results:
- If an existing FastAPI project exists, proceed to Step 1b (create venv and install dependencies only)
- If no project exists, proceed to Step 1a (create new project structure)
Step 1a: Create New FastAPI Project
If no existing project, create project structure:
mkdir my-fastapi-api && cd my-fastapi-api && python3 -m venv venv && source venv/bin/activate
⚠️ WINDOWS USERS: Use `venv\Scripts\activate` instead of `source venv/bin/activate`
Step 1b: Work with Existing Project
If project exists, create and activate virtual environment:
python3 -m venv venv && source venv/bin/activate
Step 2: Install Dependencies
Create requirements.txt with the following content:
cat > requirements.txt << 'EOF'
fastapi>=0.115.0
uvicorn[standard]>=0.34.0
auth0-fastapi-api>=1.0.0b5
python-dotenv>=1.0.0
EOF
Then install dependencies (MUST be in activated venv):
pip install -r requirements.txt
Step 3: Setup Auth0 API
⚠️ CRITICAL: Verify you're in the project directory with `pwd` before running Auth0 CLI commands.
Step 3a: Execute Auth0 CLI Setup
If MacOS, execute:
AUTH0_API_NAME="My FastAPI API" && AUTH0_API_IDENTIFIER="https://my-fastapi-api" && brew tap auth0/auth0-cli && brew install auth0 && auth0 login --no-input && auth0 apis create --name "${AUTH0_API_NAME}" --identifier "${AUTH0_API_IDENTIFIER}" --signing-alg RS256 --no-input && echo "AUTH0_DOMAIN=$(auth0 tenants list --json | jq -r '.[] | select(.active == true) | .name')\nAUTH0_AUDIENCE=${AUTH0_API_IDENTIFIER}" > .env
If Windows, execute:
$ApiName = "My FastAPI API"; $ApiIdentifier = "https://my-fastapi-api"; auth0 login --no-input; auth0 apis create -n $ApiName -i $ApiIdentifier --signing-alg RS256 --no-input; $ActiveTenant = (auth0 tenants list --json | ConvertFrom-Json | Where-Object { $_.active -eq $true }).name; "AUTH0_DOMAIN=$ActiveTenant`nAUTH0_AUDIENCE=$ApiIdentifier" | Out-File -FilePath .env -Encoding utf8
Step 3b: Verify .env file was created correctly
cat .env
Expected output:
AUTH0_DOMAIN=your-domain.auth0.com
AUTH0_AUDIENCE=https://my-fastapi-api
⚠️ If AUTH0_DOMAIN is null or missing, manually add your Auth0 domain to the .env file.
Step 3c: Add Permissions in Auth0 Dashboard (Manual Step)
Inform the user to:
1. Navigate to Applications > APIs in Auth0 Dashboard
2. Select "My FastAPI API"
3. Go to Permissions tab
4. Add permissions:
- Permission: `read:messages`, Description: "Read messages"
- Permission: `write:messages`, Description: "Write messages"
Step 4: Create FastAPI Application with Auth0
Create app.py with the following content:
cat > app.py << 'EOF'
from fastapi import FastAPI, Depends
from fastapi_plugin.fast_api_client import Auth0FastAPI
import os
from dotenv import load_dotenv
# Load environment variables
load_dotenv()
app = FastAPI()
# Initialize Auth0
auth0 = Auth0FastAPI(
domain=os.environ.get("AUTH0_DOMAIN"),
audience=os.environ.get("AUTH0_AUDIENCE")
)
# Public route - no authentication required
@app.get("/api/public")
async def public():
return {
"message": "Hello from a public endpoint! You don't need to be authenticated to see this."
}
# Protected route - requires authentication
@app.get("/api/private")
async def private(claims: dict = Depends(auth0.require_auth())):
return {
"message": "Hello from a private endpoint! You need to be authenticated to see this.",
"user_id": claims.get("sub")
}
# Scoped route - requires specific permission
@app.get("/api/private-scoped")
async def private_scoped(claims: dict = Depends(auth0.require_auth(scopes="read:messages"))):
return {
"message": "Hello from a private endpoint! You need to be authenticated and have a scope of read:messages to see this.",
"user_id": claims.get("sub")
}
EOF
Step 5: Run the FastAPI Application
⚠️ CRITICAL: Verify virtual environment is activated before running uvicorn.
# Verify venv is activated (you should see (venv) in your prompt)
which python
# Start the server
uvicorn app:app --reload
Expected output: Server starts on http://127.0.0.1:8000
Step 6: Test the API
6a: Test public endpoint (no authentication required):
curl http://localhost:8000/api/public
6b: Test protected endpoints (authentication required):
Inform the user to:
1. Get access token from Auth0 Dashboard:
- Navigate to Applications > APIs
- Select "My FastAPI API"
- Click "Test" tab
- Click "Copy Token"
2. Test private endpoint:
curl -X GET http://localhost:8000/api/private -H 'authorization: Bearer YOUR_ACCESS_TOKEN'
3. Test scoped endpoint:
curl -X GET http://localhost:8000/api/private-scoped -H 'authorization: Bearer YOUR_ACCESS_TOKEN'
ANTI-PATTERNS - NEVER DO THESE
1. ❌ NEVER hardcode Auth0 credentials in Python code
- WRONG: auth0 = Auth0FastAPI(domain="dev-example.us.auth0.com", audience="https://my-api")
- ✓ CORRECT: Always use environment variables via dotenv
2. ❌ NEVER skip virtual environment activation
- WRONG: Installing packages without activating venv first
- ✓ CORRECT: Always activate venv first with `source venv/bin/activate`
3. ❌ NEVER use multi-line curl commands with backslashes (they often fail)
- ✓ CORRECT: Use single-line format: `curl -X GET -H 'authorization: Bearer TOKEN'`
4. ❌ NEVER proceed if .env file has null values
- WRONG: AUTH0_DOMAIN=null in .env file
- ✓ CORRECT: Verify .env contains valid Auth0 domain before proceeding
ABSOLUTE REQUIREMENTS
1. ✓ Virtual environment MUST be activated before pip install
2. ✓ .env file MUST contain valid AUTH0_DOMAIN (not null)
3. ✓ .env file MUST be added to .gitignore to prevent credential exposure
4. ✓ Auth0FastAPI MUST use os.environ.get() for credentials
5. ✓ All endpoints requiring authentication MUST use Depends(auth0.require_auth())
COMMON ISSUES & SOLUTIONS
1. **ModuleNotFoundError: No module named 'fastapi_plugin'**
- Cause: Wrong virtual environment activated or venv not activated
- Solution: Deactivate all venvs, then activate the correct one in project directory
2. **AUTH0_DOMAIN is null in .env**
- Cause: Auth0 CLI command doesn't extract domain correctly
- Solution: Manually add domain to .env file from Auth0 Dashboard
3. **401 Unauthorized - Invalid issuer**
- Cause: AUTH0_DOMAIN includes https:// protocol
- Solution: Domain should be just `dev-example.us.auth0.com` without protocol
4. **401 Unauthorized - Invalid audience**
- Cause: AUTH0_AUDIENCE doesn't match API identifier
- Solution: Verify AUTH0_AUDIENCE exactly matches identifier in Auth0 Dashboard
5. **403 Forbidden - Insufficient scope**
- Cause: Access token doesn't include required scope
- Solution: Verify permissions exist in Auth0 Dashboard and token includes them
VALIDATION CHECKLIST
Before considering the integration complete, verify:
- [ ] Virtual environment is activated (check with `which python`)
- [ ] .env file exists and contains valid AUTH0_DOMAIN (not null)
- [ ] .env is added to .gitignore
- [ ] app.py imports and initializes Auth0FastAPI correctly
- [ ] Public endpoint returns 200 OK without authentication
- [ ] Private endpoint returns 401 without token
- [ ] Private endpoint returns 200 with valid token
- [ ] Scoped endpoint returns 403 without required scope
- [ ] Scoped endpoint returns 200 with token containing read:messages scope
```
This quickstart requires:
* **Python 3.9** or higher
* **pip** package manager
* **jq** - Required for Auth0 CLI setup
* Familiarity with FastAPI
If you haven't already, [sign up for a free Auth0 account](https://auth0.com/signup) to follow along.
This guide demonstrates how to integrate Auth0 with a FastAPI API to add authentication and protect your endpoints.
Create a new directory for your FastAPI project and set up a virtual environment.
```bash theme={null}
mkdir my-fastapi-api
cd my-fastapi-api
python3 -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
```
Create a `requirements.txt` file with the following dependencies:
```txt requirements.txt theme={null}
fastapi>=0.115.0
uvicorn[standard]>=0.34.0
auth0-fastapi-api>=1.0.0b5
python-dotenv>=1.0.0
```
Install the dependencies:
```bash theme={null}
pip install -r requirements.txt
```
You'll need to create an Auth0 API to represent your FastAPI application.
1. Navigate to [Applications > APIs](https://manage.auth0.com/#/apis) in the Auth0 Dashboard
2. Click **Create API**
3. Provide a **Name** for your API (e.g., "My FastAPI API")
4. Set the **Identifier** to your API identifier (e.g., `https://my-fastapi-api`)
5. Leave the **Signing Algorithm** as RS256
6. Click **Create**
If you have the [Auth0 CLI](https://github.com/auth0/auth0-cli) installed, you can create an API and configure your environment from your terminal:
```shellscript Mac theme={null}
AUTH0_API_NAME="My FastAPI API" && AUTH0_API_IDENTIFIER="https://my-fastapi-api" && brew tap auth0/auth0-cli && brew install auth0 && auth0 login --no-input && auth0 apis create --name "${AUTH0_API_NAME}" --identifier "${AUTH0_API_IDENTIFIER}" --signing-alg RS256 --no-input && echo "AUTH0_DOMAIN=$(auth0 tenants list --json | jq -r '.[] | select(.active == true) | .name')\nAUTH0_AUDIENCE=${AUTH0_API_IDENTIFIER}" > .env
```
```powershell Windows theme={null}
$ApiName = "My FastAPI API"; $ApiIdentifier = "https://my-fastapi-api"; auth0 login --no-input; auth0 apis create -n $ApiName -i $ApiIdentifier --signing-alg RS256 --no-input; $ActiveTenant = (auth0 tenants list --json | ConvertFrom-Json | Where-Object { $_.active -eq $true }).name; "AUTH0_DOMAIN=$ActiveTenant`nAUTH0_AUDIENCE=$ApiIdentifier" | Out-File -FilePath .env -Encoding utf8
```
This will create your API and automatically generate a `.env` file with your Auth0 configuration.
The **Identifier** is a unique identifier for your API. It's recommended to use a URL, but it doesn't have to be a publicly accessible URL—Auth0 won't call it. This value cannot be modified afterwards.
Make note of the **Domain** and **Identifier** (Audience) values. You'll need these in the next step.
Permissions (also known as scopes) allow you to define how your API can be accessed. You can create permissions for your API in the Auth0 Dashboard.
1. In the Auth0 Dashboard, navigate to your API's **Permissions** tab
2. Add the following permissions:
* `read:messages` with description "Read messages"
* `write:messages` with description "Write messages"
These permissions will be used to control access to specific endpoints in your API.
Create a `.env` file in your project root to store your Auth0 configuration:
```txt .env theme={null}
AUTH0_DOMAIN=YOUR_AUTH0_DOMAIN
AUTH0_AUDIENCE=YOUR_API_IDENTIFIER
```
Replace `YOUR_AUTH0_DOMAIN` with your Auth0 domain (e.g., `dev-abc123.us.auth0.com`) and `YOUR_API_IDENTIFIER` with the identifier you set when creating your API.
Never commit your `.env` file to version control. Add it to your `.gitignore` file to keep your credentials secure.
Now create an `app.py` file and initialize your FastAPI application with Auth0:
```python app.py theme={null}
from fastapi import FastAPI, Depends
from fastapi_plugin.fast_api_client import Auth0FastAPI
import os
from dotenv import load_dotenv
# Load environment variables
load_dotenv()
app = FastAPI()
# Initialize Auth0
auth0 = Auth0FastAPI(
domain=os.environ.get("AUTH0_DOMAIN"),
audience=os.environ.get("AUTH0_AUDIENCE")
)
```
Add the following routes to your `app.py` file. These routes demonstrate different levels of access control:
```python app.py theme={null}
from fastapi import FastAPI, Depends
from fastapi_plugin.fast_api_client import Auth0FastAPI
import os
from dotenv import load_dotenv
load_dotenv()
app = FastAPI()
auth0 = Auth0FastAPI(
domain=os.environ.get("AUTH0_DOMAIN"),
audience=os.environ.get("AUTH0_AUDIENCE")
)
# Public route - no authentication required
@app.get("/api/public")
async def public():
return {
"message": "Hello from a public endpoint! You don't need to be authenticated to see this."
}
# Protected route - requires authentication
@app.get("/api/private")
async def private(claims: dict = Depends(auth0.require_auth())):
return {
"message": "Hello from a private endpoint! You need to be authenticated to see this.",
"user_id": claims.get("sub")
}
# Scoped route - requires specific permission
@app.get("/api/private-scoped")
async def private_scoped(claims: dict = Depends(auth0.require_auth(scopes="read:messages"))):
return {
"message": "Hello from a private endpoint! You need to be authenticated and have a scope of read:messages to see this.",
"user_id": claims.get("sub")
}
```
The `require_auth()` method validates the access token sent in the Authorization header. When called with a `scopes` parameter, it also verifies that the token contains the specified permission.
Start your FastAPI application:
```bash theme={null}
uvicorn app:app --reload
```
Your API is now running on `http://localhost:8000`.
Visit `http://localhost:8000/api/public` in your browser. You should see the public message without needing authentication.
***
## Test your API
To test the protected endpoints, you'll need to obtain an access token from Auth0.
### Get an access token
The easiest way to get an access token for testing is through the Auth0 Dashboard:
1. Navigate to [Applications > APIs](https://manage.auth0.com/#/apis) in the Auth0 Dashboard
2. Select your API
3. Click the **Test** tab
4. Click **Copy Token** in the **Asking Auth0 for tokens from my application** section
### Call your API
Use the access token to call your protected endpoint:
```bash theme={null}
curl -X GET http://localhost:8000/api/private -H 'authorization: Bearer YOUR_ACCESS_TOKEN'
```
You should receive a response with the private message and your user ID.
To test the scoped endpoint, make sure your token includes the `read:messages` scope:
```bash theme={null}
curl -X GET http://localhost:8000/api/private-scoped -H 'authorization: Bearer YOUR_ACCESS_TOKEN'
```
If your token doesn't have the required scope, you'll receive a 403 Forbidden response.
***
## Advanced Usage
You can access custom claims that have been added to the access token through [Auth0 Actions](https://auth0.com/docs/customize/actions).
Access custom claims in your route handler:
```python theme={null}
@app.get("/api/profile")
async def profile(claims: dict = Depends(auth0.require_auth())):
return {
"user_id": claims.get("sub"),
"email": claims.get("email"),
"permissions": claims.get("permissions", []),
"custom_claim": claims.get("https://myapp.example.com/custom_claim")
}
```
To add custom claims to your access tokens, create an Auth0 Action:
1. Navigate to **Actions > Library** in the Auth0 Dashboard
2. Click **Create Action**
3. Select **Build from scratch**
4. Name your action and select the **Login / Post Login** trigger
5. Add your custom claims:
```javascript theme={null}
exports.onExecutePostLogin = async (event, api) => {
const namespace = 'https://myapp.example.com';
if (event.authorization) {
// Add custom claim to access token
api.accessToken.setCustomClaim(`${namespace}/roles`, event.user.app_metadata.roles || []);
}
};
```
6. Click **Deploy** and add the action to your Login flow
Custom claims must use a namespaced format (e.g., `https://myapp.example.com/claim_name`) to avoid conflicts with standard claims.
If you need to protect an endpoint but don't need to access the claims, you can use the `dependencies` parameter:
```python theme={null}
@app.get("/api/protected", dependencies=[Depends(auth0.require_auth())])
async def protected():
return {"message": "This endpoint is protected"}
```
This validates the access token but doesn't inject the claims into your function.
DPoP (Demonstrating Proof-of-Possession) is currently in [Early Access](https://auth0.com/docs/troubleshoot/product-lifecycle/product-release-stages). Contact [Auth0 support](https://support.auth0.com/) to enable it for your tenant.
DPoP provides enhanced security by cryptographically binding access tokens to the client that requested them. This prevents token theft and replay attacks.
The SDK enables DPoP support by default. You can configure DPoP behavior:
```python theme={null}
auth0 = Auth0FastAPI(
domain=os.environ.get("AUTH0_DOMAIN"),
audience=os.environ.get("AUTH0_AUDIENCE"),
dpop_enabled=True, # Enable DPoP (default: True)
dpop_required=False # Require DPoP (default: False)
)
```
**Mixed mode** (default) accepts both Bearer and DPoP tokens:
```python theme={null}
auth0 = Auth0FastAPI(
domain=os.environ.get("AUTH0_DOMAIN"),
audience=os.environ.get("AUTH0_AUDIENCE"),
dpop_enabled=True,
dpop_required=False
)
```
**DPoP-only mode** rejects Bearer tokens:
```python theme={null}
auth0 = Auth0FastAPI(
domain=os.environ.get("AUTH0_DOMAIN"),
audience=os.environ.get("AUTH0_AUDIENCE"),
dpop_required=True
)
```
When using DPoP, clients must include both the `Authorization: DPoP ` and `DPoP: ` headers. The SDK automatically validates the DPoP proof and binds it to the access token.
Only enable `trust_proxy` when your application is behind a trusted reverse proxy. Never enable this for applications directly exposed to the internet.
If your application runs behind a reverse proxy (nginx, AWS ALB, etc.), you need to enable proxy trust for DPoP validation to work correctly:
```python theme={null}
from fastapi import FastAPI
app = FastAPI()
# Enable proxy trust
app.state.trust_proxy = True
auth0 = Auth0FastAPI(
domain=os.environ.get("AUTH0_DOMAIN"),
audience=os.environ.get("AUTH0_AUDIENCE")
)
```
Configure your reverse proxy to forward the necessary headers:
```nginx theme={null}
location /api {
proxy_pass http://localhost:8000;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Prefix /api;
}
```
This is essential for DPoP validation because the SDK needs to match the exact URL the client used. Without proxy trust, your application sees internal URLs while DPoP proofs reference external URLs, causing validation failures.
The SDK raises `HTTPException` for authentication errors. FastAPI handles these automatically, returning appropriate HTTP responses to the client.
You can implement custom error handling if needed:
```python theme={null}
from fastapi import Request
from fastapi.responses import JSONResponse
from fastapi.exceptions import HTTPException
@app.exception_handler(HTTPException)
async def custom_http_exception_handler(request: Request, exc: HTTPException):
if exc.status_code in [401, 403]:
return JSONResponse(
status_code=exc.status_code,
content={
"error": "authentication_failed",
"message": "You must be authenticated to access this resource",
"details": exc.detail
}
)
return JSONResponse(
status_code=exc.status_code,
content={"detail": exc.detail}
)
```
Authentication errors include:
* **401 Unauthorized**: Missing, invalid, or expired access token
* **403 Forbidden**: Valid token but insufficient permissions (scopes)
***
## Common Issues
**Problem**: Token validation fails with "Invalid audience" error.
**Solution**: Verify that the `AUTH0_AUDIENCE` in your `.env` file exactly matches the **Identifier** you configured for your API in the Auth0 Dashboard.
1. Open the Auth0 Dashboard and navigate to **Applications > APIs**
2. Select your API
3. Check the **Identifier** value in the Settings tab
4. Update your `.env` file:
```txt theme={null}
AUTH0_AUDIENCE=https://your-exact-api-identifier
```
5. Restart your application
**Problem**: Token validation fails with "Invalid issuer" error.
**Solution**: Verify that your `AUTH0_DOMAIN` is correct and does not include the `https://` protocol.
Your domain should look like `dev-abc123.us.auth0.com`, not `https://dev-abc123.us.auth0.com`.
Update your `.env` file:
```txt theme={null}
AUTH0_DOMAIN=dev-abc123.us.auth0.com
```
**Problem**: Protected endpoint returns 403 even with a valid access token.
**Solution**: The access token doesn't include the required scope.
1. Check what scopes your endpoint requires
2. When requesting a token, ensure you include the required scopes
3. Verify the scope exists in your API's Permissions tab in the Auth0 Dashboard
4. Decode your token at [jwt.io](https://jwt.io) to verify it contains the `scope` claim with the required values
**Problem**: Python cannot find the Auth0 FastAPI SDK.
**Solution**: Ensure the SDK is installed in your active virtual environment.
```bash theme={null}
# Activate your virtual environment
source venv/bin/activate # Windows: venv\Scripts\activate
# Install the SDK
pip install auth0-fastapi-api
# Verify installation
pip show auth0-fastapi-api
```
**Problem**: Application cannot fetch signing keys from Auth0.
**Solution**: Check your network connectivity and domain configuration.
1. Verify your domain is accessible:
```bash theme={null}
curl https://YOUR_DOMAIN/.well-known/openid-configuration
```
2. Check that your firewall allows outbound HTTPS (port 443) connections to `*.auth0.com`
3. If behind a corporate proxy, configure the `HTTP_PROXY` and `HTTPS_PROXY` environment variables
**Problem**: DPoP authentication returns errors about URL or proof validation.
**Solution**:
1. If behind a reverse proxy, enable proxy trust:
```python theme={null}
app.state.trust_proxy = True
```
2. Verify your proxy forwards these headers:
* `X-Forwarded-Proto`
* `X-Forwarded-Host`
* `X-Forwarded-Prefix`
3. Ensure DPoP is enabled for your tenant (contact Auth0 support)
4. Verify the DPoP proof `htu` claim matches your request URL exactly
***
## Next Steps
Explore the Auth0 FastAPI SDK on GitHub for advanced configuration and examples
Learn how to define and use scopes for fine-grained access control
Customize your authentication flow and add custom claims to tokens
Learn more about FastAPI features, async patterns, and best practices
Implement role-based access control (RBAC) for your API
Best practices for deploying FastAPI applications with Auth0
# Protect Your Fastify API
Source: https://auth0.com/docs/quickstart/backend/fastify/index
This guide demonstrates how to protect Fastify API endpoints using JWT access tokens with the Auth0 Fastify API SDK.
If you use an AI coding assistant like Claude Code, Cursor, or GitHub Copilot, you can add Auth0 API authentication automatically in minutes using [agent skills](https://agentskills.io/home).
**Install:**
```bash theme={null}
npx skills add auth0/agent-skills --skill auth0
```
**Then ask your AI assistant:**
```text theme={null}
Add Auth0 JWT authentication to my Fastify API
```
Your AI assistant will automatically create your Auth0 API, fetch credentials, install `@auth0/auth0-fastify-api`, configure the plugin, and protect your API endpoints with JWT validation. [Full agent skills documentation →](/docs/quickstart/agent-skills)
**Prerequisites:** Before you begin, ensure you have the following installed:
* **[Node.js](https://nodejs.org/en/download)** 20 LTS or newer
* **[npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm)** 10+ or **[yarn](https://classic.yarnpkg.com/lang/en/docs/install/)** 1.22+ or **[pnpm](https://pnpm.io/installation)** 8+
Verify installation: `node --version && npm --version`
**Fastify Version Compatibility:** This quickstart works with **Fastify 5.x** and newer.
## Get Started
This quickstart demonstrates how to protect Fastify API endpoints using JWT access tokens. You'll build a secure API that validates Auth0 access tokens and grants access to protected resources.
Create a new directory for your Fastify API and initialize a Node.js project.
```shellscript theme={null}
mkdir auth0-fastify-api && cd auth0-fastify-api
```
Initialize the project
```shellscript theme={null}
npm init -y
```
Create the project structure
```shellscript theme={null}
touch server.js .env
```
Install the required dependencies
```shellscript theme={null}
npm install @auth0/auth0-fastify-api fastify dotenv
```
Update your `package.json` to add start scripts:
```json package.json theme={null}
{
"name": "auth0-fastify-api",
"version": "1.0.0",
"type": "module",
"main": "server.js",
"scripts": {
"start": "node server.js",
"dev": "node --watch server.js"
},
"dependencies": {
"@auth0/auth0-fastify-api": "^1.2.0",
"dotenv": "^16.3.1",
"fastify": "^5.0.0"
}
}
```
Next, you need to create a new API on your Auth0 tenant and add the environment variables to your project.
You have two options to set up your Auth0 API: use a CLI command or configure manually via the Dashboard:
Run the following command in your project's root directory to create an Auth0 API:
```shellscript Mac theme={null}
# Install Auth0 CLI (if not already installed)
brew tap auth0/auth0-cli && brew install auth0
# Create Auth0 API
auth0 apis create \
--name "My Fastify API" \
--identifier https://my-fastify-api.example.com
```
```powershell Windows theme={null}
# Install Auth0 CLI (if not already installed)
scoop bucket add auth0 https://github.com/auth0/scoop-auth0-cli.git
scoop install auth0
# Create Auth0 API
auth0 apis create `
--name "My Fastify API" `
--identifier https://my-fastify-api.example.com
```
After creation, copy the **Identifier** and your **Domain** values, then create your `.env` file:
```bash .env theme={null}
AUTH0_DOMAIN=YOUR_AUTH0_DOMAIN
AUTH0_AUDIENCE=YOUR_API_IDENTIFIER
```
This command will:
1. Check if you're authenticated (and prompt for login if needed)
2. Create an Auth0 API with the specified identifier
3. Display the API details including the domain and identifier
1. Go to the [Auth0 Dashboard](https://manage.auth0.com/dashboard/)
2. Navigate to **Applications** → **APIs** → **Create API**
3. Enter a name for your API (e.g., "My Fastify API")
4. Set the **Identifier** (e.g., `https://my-fastify-api.example.com`)
* This is your API audience and must be a valid URL format
* It doesn't need to be a real URL - it's just an identifier
5. Keep **Signing Algorithm** as **RS256**
6. Click **Create**
7. Copy the **Identifier** value from the **Settings** tab
Create your `.env` file with the following values:
```bash .env theme={null}
AUTH0_DOMAIN=YOUR_AUTH0_DOMAIN
AUTH0_AUDIENCE=YOUR_API_IDENTIFIER
```
Replace `YOUR_AUTH0_DOMAIN` with your Auth0 tenant domain (e.g., `dev-abc123.us.auth0.com`) and `YOUR_API_IDENTIFIER` with your API identifier from the dashboard (e.g., `https://my-fastify-api.example.com`).
Verify your `.env` file exists: `cat .env` (Mac/Linux) or `type .env` (Windows)
Create your Fastify server and register the Auth0 API plugin:
```javascript server.js {1-3,6-7,10-13,16-17} lines theme={null}
import 'dotenv/config';
import Fastify from 'fastify';
import fastifyAuth0Api from '@auth0/auth0-fastify-api';
const fastify = Fastify({ logger: true });
const port = process.env.PORT || 3001;
// Register Auth0 API plugin
await fastify.register(fastifyAuth0Api, {
domain: process.env.AUTH0_DOMAIN,
audience: process.env.AUTH0_AUDIENCE,
});
// Start server
fastify.listen({ port }, (err) => {
if (err) {
fastify.log.error(err);
process.exit(1);
}
fastify.log.info(`API server running at http://localhost:${port}`);
});
```
**What this does:**
* Registers the Auth0 API plugin with your Auth0 domain and API audience
* Configures JWT validation for incoming requests
* Makes the `requireAuth()` preHandler available for protecting routes
Add public and protected routes to your `server.js`:
```javascript server.js expandable lines theme={null}
import 'dotenv/config';
import Fastify from 'fastify';
import fastifyAuth0Api from '@auth0/auth0-fastify-api';
const fastify = Fastify({ logger: true });
const port = process.env.PORT || 3001;
// Register Auth0 API plugin
await fastify.register(fastifyAuth0Api, {
domain: process.env.AUTH0_DOMAIN,
audience: process.env.AUTH0_AUDIENCE,
});
// Public route - no authentication required
fastify.get('/api/public', async (request, reply) => {
return {
message: 'Hello from a public endpoint! You don\'t need to be authenticated to see this.',
timestamp: new Date().toISOString(),
};
});
// Protected route - requires valid access token
fastify.get('/api/private', {
preHandler: fastify.requireAuth()
}, async (request, reply) => {
return {
message: 'Hello from a protected endpoint! You successfully authenticated.',
user: request.user.sub,
timestamp: new Date().toISOString(),
};
});
// Protected route - returns user information from token
fastify.get('/api/profile', {
preHandler: fastify.requireAuth()
}, async (request, reply) => {
return {
message: 'Your user profile from the access token',
profile: request.user,
};
});
// Start server
fastify.listen({ port }, (err) => {
if (err) {
fastify.log.error(err);
process.exit(1);
}
fastify.log.info(`API server running at http://localhost:${port}`);
});
```
**Key points:**
* Public routes don't require authentication
* Protected routes use `preHandler: fastify.requireAuth()` to require a valid JWT
* `request.user` contains the decoded JWT claims for authenticated requests
* The `sub` claim contains the user's unique identifier
Start the development server:
```shellscript theme={null}
npm run dev
```
Your API is now running at [http://localhost:3001](http://localhost:3001).
The `--watch` flag in Node.js 20+ automatically restarts the server when files change.
Test the public endpoint (no authentication required):
```bash theme={null}
curl http://localhost:3001/api/public
```
You should see:
```json theme={null}
{
"message": "Hello from a public endpoint! You don't need to be authenticated to see this.",
"timestamp": "2024-01-15T10:30:00.000Z"
}
```
Test the protected endpoint without a token (should fail):
```bash theme={null}
curl http://localhost:3001/api/private
```
You should see a 401 Unauthorized error:
```json theme={null}
{
"error": "Unauthorized",
"message": "No authorization token was found"
}
```
To test with a valid token, you need to:
1. Create a client application (web or mobile app) that authenticates users
2. Configure the client to request an access token for your API (using the audience parameter)
3. Use that access token in the Authorization header
Example with a token:
```bash theme={null}
curl http://localhost:3001/api/private \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
```
**Checkpoint**
You should now have a protected API. Your API:
1. Accepts requests to public endpoints without authentication
2. Rejects requests to protected endpoints without a valid token
3. Validates JWT tokens against your Auth0 domain and audience
4. Provides user information from the token claims via `request.user`
***
## Advanced Usage
Extend the Token interface to add type safety for custom claims in your access tokens:
```typescript server.ts theme={null}
import '@auth0/auth0-fastify-api';
// Extend the Token interface with your custom claims
declare module '@auth0/auth0-fastify-api' {
interface Token {
sub: string;
permissions?: string[];
'https://myapp.com/roles'?: string[];
email?: string;
email_verified?: boolean;
}
}
```
Now TypeScript will recognize your custom claims:
```typescript server.ts theme={null}
fastify.get('/api/profile', {
preHandler: fastify.requireAuth()
}, async (request, reply) => {
// TypeScript knows about these properties
const userRoles = request.user['https://myapp.com/roles']; // string[] | undefined
const permissions = request.user.permissions; // string[] | undefined
const email = request.user.email; // string | undefined
return {
userId: request.user.sub,
roles: userRoles || [],
permissions: permissions || [],
email: email,
};
});
```
Custom claims must use namespaced URLs (e.g., `https://myapp.com/roles`) unless they're standard OIDC claims. [Learn more about custom claims](/docs/secure/tokens/json-web-tokens/create-custom-claims).
Check for specific permissions in the access token:
```javascript server.js theme={null}
// Middleware to check for specific permission
function requirePermission(permission) {
return async (request, reply) => {
const permissions = request.user.permissions || [];
if (!permissions.includes(permission)) {
return reply.status(403).send({
error: 'Forbidden',
message: `Missing required permission: ${permission}`
});
}
};
}
// Route requiring 'read:messages' permission
fastify.get('/api/messages', {
preHandler: [
fastify.requireAuth(),
requirePermission('read:messages')
]
}, async (request, reply) => {
return {
messages: ['Message 1', 'Message 2', 'Message 3']
};
});
// Route requiring 'write:messages' permission
fastify.post('/api/messages', {
preHandler: [
fastify.requireAuth(),
requirePermission('write:messages')
]
}, async (request, reply) => {
return {
message: 'Message created successfully',
id: 'msg_123'
};
});
```
Permissions must be configured in your Auth0 API settings and granted to clients. [Learn more about API permissions](/docs/manage-users/access-control/configure-core-rbac/rbac-users/assign-permissions-to-users).
Implement role-based access control using custom claims:
```javascript server.js theme={null}
// Middleware to check for specific role
function requireRole(role) {
return async (request, reply) => {
const roles = request.user['https://myapp.com/roles'] || [];
if (!roles.includes(role)) {
return reply.status(403).send({
error: 'Forbidden',
message: `Missing required role: ${role}`
});
}
};
}
// Admin-only route
fastify.get('/api/admin/users', {
preHandler: [
fastify.requireAuth(),
requireRole('admin')
]
}, async (request, reply) => {
return {
users: [
{ id: 1, name: 'User 1' },
{ id: 2, name: 'User 2' }
]
};
});
// Manager or admin route
function requireAnyRole(...roles) {
return async (request, reply) => {
const userRoles = request.user['https://myapp.com/roles'] || [];
const hasRole = roles.some(role => userRoles.includes(role));
if (!hasRole) {
return reply.status(403).send({
error: 'Forbidden',
message: `Missing required role. Need one of: ${roles.join(', ')}`
});
}
};
}
fastify.get('/api/reports', {
preHandler: [
fastify.requireAuth(),
requireAnyRole('admin', 'manager')
]
}, async (request, reply) => {
return { reports: [] };
});
```
Roles must be added to tokens using Auth0 Actions. [Learn how to add roles to tokens](/docs/manage-users/access-control/sample-use-cases-actions-with-authorization#add-user-roles-to-tokens).
Enable CORS to allow requests from web applications:
```bash theme={null}
npm install @fastify/cors
```
```javascript server.js theme={null}
import cors from '@fastify/cors';
await fastify.register(cors, {
origin: ['http://localhost:3000', 'http://localhost:5173'], // Your web app URLs
credentials: true,
});
```
For production, specify exact origins:
```javascript server.js theme={null}
await fastify.register(cors, {
origin: [
'https://myapp.com',
'https://www.myapp.com'
],
credentials: true,
methods: ['GET', 'POST', 'PUT', 'DELETE'],
});
```
Add comprehensive error handling for authentication errors:
```javascript server.js theme={null}
// Custom error handler
fastify.setErrorHandler((error, request, reply) => {
fastify.log.error(error);
// Handle JWT validation errors
if (error.statusCode === 401) {
return reply.status(401).send({
error: 'Unauthorized',
message: error.message || 'Invalid or missing access token',
code: 'UNAUTHORIZED'
});
}
// Handle permission/role errors
if (error.statusCode === 403) {
return reply.status(403).send({
error: 'Forbidden',
message: error.message || 'Insufficient permissions',
code: 'FORBIDDEN'
});
}
// Handle other errors
return reply.status(error.statusCode || 500).send({
error: 'Internal Server Error',
message: 'An unexpected error occurred',
code: 'INTERNAL_ERROR'
});
});
// Not found handler
fastify.setNotFoundHandler((request, reply) => {
return reply.status(404).send({
error: 'Not Found',
message: `Route ${request.method} ${request.url} not found`,
code: 'NOT_FOUND'
});
});
```
Protect your API from abuse with rate limiting:
```bash theme={null}
npm install @fastify/rate-limit
```
```javascript server.js theme={null}
import rateLimit from '@fastify/rate-limit';
await fastify.register(rateLimit, {
max: 100, // Maximum requests
timeWindow: '1 minute', // Time window
errorResponseBuilder: (request, context) => {
return {
error: 'Too Many Requests',
message: `Rate limit exceeded. Try again in ${context.after}`,
retryAfter: context.after
};
}
});
// Apply stricter limits to specific routes
fastify.get('/api/expensive-operation', {
preHandler: fastify.requireAuth(),
config: {
rateLimit: {
max: 10,
timeWindow: '1 minute'
}
}
}, async (request, reply) => {
return { result: 'expensive operation result' };
});
```
***
## Troubleshooting
### "No authorization token was found"
**Problem:** The API cannot find the access token in the request.
**Solutions:**
1. Ensure the `Authorization` header is present: `Authorization: Bearer YOUR_TOKEN`
2. Check that "Bearer" is included before the token
3. Verify the token is not expired
### "Invalid token" or "jwt malformed"
**Problem:** The token format is invalid.
**Solutions:**
1. Ensure you're using an **access token**, not an ID token
2. The token should be obtained with your API's `audience` parameter
3. Check that the token is a valid JWT (should have three parts separated by dots)
### "Invalid signature"
**Problem:** The token signature doesn't match.
**Solutions:**
1. Verify `AUTH0_DOMAIN` matches the domain that issued the token
2. Ensure you're using RS256 signing algorithm (default)
3. Check that the token hasn't been modified
### "Invalid audience"
**Problem:** The token's audience doesn't match your API.
**Solution:** The client application must request a token with the correct audience:
```javascript theme={null}
// In your client app
const token = await getAccessTokenSilently({
authorizationParams: {
audience: 'https://my-fastify-api.example.com' // Must match your API identifier
}
});
```
### CORS errors in browser
**Problem:** Browser blocks API requests due to CORS policy.
**Solution:** Install and configure `@fastify/cors`:
```bash theme={null}
npm install @fastify/cors
```
```javascript theme={null}
import cors from '@fastify/cors';
await fastify.register(cors, {
origin: 'http://localhost:3000', // Your frontend URL
credentials: true
});
```
***
## Next Steps
Now that you have a protected API, consider exploring:
* **[Fastify Web App Quickstart](/docs/quickstart/webapp/fastify)** - Build a web application that calls your API
* **[Role-Based Access Control](/docs/manage-users/access-control/rbac)** - Implement fine-grained permissions
* **[API Authorization Best Practices](/docs/secure/tokens/access-tokens)** - Learn about access token best practices
* **[Monitor Your API](/docs/deploy-monitor/logs)** - Set up logging and monitoring
***
## Resources
* **[auth0-fastify-api GitHub](https://github.com/auth0/auth0-fastify/tree/main/packages/auth0-fastify-api)** - Source code and examples
* **[Fastify Documentation](https://fastify.dev/)** - Learn more about Fastify
* **[Auth0 API Authentication](/docs/secure/tokens/access-tokens)** - Understanding access tokens
* **[Auth0 Community](https://community.auth0.com/)** - Get help from the community
# Protect Your Go API
Source: https://auth0.com/docs/quickstart/backend/golang
This guide demonstrates how to protect Go API endpoints using JWT access tokens with the go-jwt-middleware v3 SDK.
If you use an AI coding assistant like Claude Code, Cursor, or GitHub Copilot, you can add Auth0 API authentication automatically in minutes using [agent skills](https://agentskills.io/home).
**Install:**
```bash theme={null}
npx skills add auth0/agent-skills --skill auth0
```
**Then ask your AI assistant:**
```text theme={null}
Add Auth0 JWT authentication to my Go API
```
Your AI assistant will automatically create your Auth0 API, fetch credentials, install `go-jwt-middleware`, configure the validator, and protect your API endpoints with JWT validation. [Full agent skills documentation →](/docs/quickstart/agent-skills)
**Prerequisites:** Before you begin, ensure you have the following installed:
* **[Go](https://go.dev/doc/install)** 1.24 or newer (required for generics support in go-jwt-middleware v3)
* **[Git](https://git-scm.com/downloads)** for version control
Verify installation: `go version`
## Get Started
You'll build a Go API with three endpoints demonstrating different protection levels: public access, JWT-authenticated, and permission-scoped. The complete implementation uses [go-jwt-middleware v3](https://github.com/auth0/go-jwt-middleware) with Go's standard `net/http` library.
Complete working example with tests
Create a new directory for your Go API and initialize a module.
```shellscript theme={null}
mkdir myapi && cd myapi
go mod init github.com/yourorg/myapi
```
Install the required dependencies:
```shellscript theme={null}
go get github.com/auth0/go-jwt-middleware/v3
go get github.com/joho/godotenv
go mod download
```
Create the project structure:
```shellscript theme={null}
mkdir -p cmd/server internal/auth internal/config internal/handlers
touch .env cmd/server/main.go internal/config/auth.go internal/auth/claims.go internal/auth/validator.go internal/auth/middleware.go internal/handlers/api.go
```
```go go.mod theme={null}
module github.com/yourorg/myapi
go 1.24
require (
github.com/auth0/go-jwt-middleware/v3 v3.1.0
github.com/joho/godotenv v1.5.1
)
```
Next, you need to create a new API on your Auth0 tenant and add the environment variables to your project.
You have two options to set up your Auth0 API: use a CLI command or configure manually via the Dashboard:
Run the following command in your project's root directory to create an Auth0 API:
```shellscript Mac theme={null}
# Install Auth0 CLI (if not already installed)
brew tap auth0/auth0-cli && brew install auth0
# Create Auth0 API
auth0 apis create \
--name "My Go API" \
--identifier https://my-go-api.example.com
```
```powershell Windows theme={null}
# Install Auth0 CLI (if not already installed)
scoop bucket add auth0 https://github.com/auth0/scoop-auth0-cli.git
scoop install auth0
# Create Auth0 API
auth0 apis create `
--name "My Go API" `
--identifier https://my-go-api.example.com
```
After creation, copy the **Identifier** and your **Domain** values, then create your `.env` file:
This command will:
1. Check if you're authenticated (and prompt for login if needed)
2. Create an Auth0 API with the specified identifier
3. Display the API details including the domain and identifier
1. Go to the [Auth0 Dashboard](https://manage.auth0.com/dashboard/)
2. Navigate to **Applications** → **APIs** → **Create API**
3. Enter a name for your API (e.g., "My Go API")
4. Set the **Identifier** (e.g., `https://my-go-api.example.com`)
* This is your API audience and must be a valid URL format
* It doesn't need to be a real URL, it's just an identifier
5. Keep **Signing Algorithm** as **RS256**
6. Click **Create**
7. Copy the **Identifier** value from the **Settings** tab
Create your `.env` file with the following values:
```bash .env theme={null}
AUTH0_DOMAIN=YOUR_AUTH0_DOMAIN
AUTH0_AUDIENCE=YOUR_API_IDENTIFIER
```
Replace `YOUR_AUTH0_DOMAIN` with your Auth0 tenant domain (e.g., `dev-abc123.us.auth0.com`) and `YOUR_API_IDENTIFIER` with your API identifier from the dashboard (e.g., `https://my-go-api.example.com`).
**Security**: Never commit `.env` files to version control. Add `.env` to your `.gitignore` file.
Permissions (scopes) let you define how resources can be accessed. For example, grant `read` access to managers and `write` access to administrators.
1. In your API settings, click the **Permissions** tab
2. Create the following permission:
| Permission | Description |
| - | - |
| `read:messages` | Read messages from the API |
This tutorial uses the `read:messages` scope to protect the scoped endpoint. You can define additional permissions based on your application's needs.
Create a config package to load and validate environment variables.
```go internal/config/auth.go lines theme={null}
package config
import (
"fmt"
"os"
)
type AuthConfig struct {
Domain string
Audience string
}
func LoadAuthConfig() (*AuthConfig, error) {
domain := os.Getenv("AUTH0_DOMAIN")
if domain == "" {
return nil, fmt.Errorf("AUTH0_DOMAIN environment variable required")
}
audience := os.Getenv("AUTH0_AUDIENCE")
if audience == "" {
return nil, fmt.Errorf("AUTH0_AUDIENCE environment variable required")
}
return &AuthConfig{
Domain: domain,
Audience: audience,
}, nil
}
```
**What this does:**
* Loads Auth0 domain and audience from environment variables
* Validates that required configuration is present at startup
* Returns a type-safe config struct for use across the application
Custom claims allow you to extract and validate application-specific data from JWTs. The validator is the core component that verifies tokens against Auth0.
```go internal/auth/claims.go lines theme={null}
package auth
import (
"context"
"fmt"
"strings"
)
// CustomClaims contains custom data we want to parse from the JWT.
type CustomClaims struct {
Scope string `json:"scope"`
}
// Validate ensures the custom claims are properly formatted.
func (c *CustomClaims) Validate(ctx context.Context) error {
if c.Scope == "" {
return nil
}
if strings.TrimSpace(c.Scope) != c.Scope {
return fmt.Errorf("scope claim has invalid whitespace")
}
if strings.Contains(c.Scope, " ") {
return fmt.Errorf("scope claim contains double spaces")
}
return nil
}
// HasScope checks whether our claims have a specific scope.
func (c *CustomClaims) HasScope(expectedScope string) bool {
if c.Scope == "" {
return false
}
scopes := strings.Split(c.Scope, " ")
for _, scope := range scopes {
if scope == expectedScope {
return true
}
}
return false
}
```
```go internal/auth/validator.go lines theme={null}
package auth
import (
"fmt"
"net/url"
"time"
"github.com/auth0/go-jwt-middleware/v3/jwks"
"github.com/auth0/go-jwt-middleware/v3/validator"
)
func NewValidator(domain, audience string) (*validator.Validator, error) {
// Construct issuer URL (must include trailing slash)
issuerURL, err := url.Parse("https://" + domain + "/")
if err != nil {
return nil, fmt.Errorf("failed to parse issuer URL: %w", err)
}
// Initialize JWKS provider using v3 options pattern
provider, err := jwks.NewCachingProvider(
jwks.WithIssuerURL(issuerURL),
jwks.WithCacheTTL(5*time.Minute),
)
if err != nil {
return nil, fmt.Errorf("failed to create JWKS provider: %w", err)
}
// Create validator using v3 options pattern
jwtValidator, err := validator.New(
validator.WithKeyFunc(provider.KeyFunc),
validator.WithAlgorithm(validator.RS256),
validator.WithIssuer(issuerURL.String()),
validator.WithAudience(audience),
validator.WithCustomClaims(func() validator.CustomClaims {
return &CustomClaims{}
}),
validator.WithAllowedClockSkew(30*time.Second),
)
if err != nil {
return nil, fmt.Errorf("failed to create validator: %w", err)
}
return jwtValidator, nil
}
```
**Key points:**
* The `Validate` method is called automatically by the middleware after parsing the JWT
* `HasScope` parses space-separated scopes for permission-based access control
* The validator uses JWKS caching (5 min TTL) and allows 30s clock skew
* RS256 algorithm is explicitly set to prevent [algorithm confusion attacks](https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/)
The middleware wraps the validator for HTTP requests. The handlers demonstrate three protection levels: public, private, and permission-scoped.
```go internal/auth/middleware.go lines theme={null}
package auth
import (
"log/slog"
"net/http"
jwtmiddleware "github.com/auth0/go-jwt-middleware/v3"
"github.com/auth0/go-jwt-middleware/v3/validator"
)
func NewMiddleware(jwtValidator *validator.Validator) (*jwtmiddleware.JWTMiddleware, error) {
return jwtmiddleware.New(
jwtmiddleware.WithValidator(jwtValidator),
jwtmiddleware.WithValidateOnOptions(false),
jwtmiddleware.WithErrorHandler(func(w http.ResponseWriter, r *http.Request, err error) {
slog.Error("JWT validation failed", "error", err, "path", r.URL.Path)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusUnauthorized)
w.Write([]byte(`{"message":"Failed to validate JWT."}`))
}),
)
}
```
```go internal/handlers/api.go expandable lines theme={null}
package handlers
import (
"encoding/json"
"net/http"
"github.com/yourorg/myapi/internal/auth"
jwtmiddleware "github.com/auth0/go-jwt-middleware/v3"
"github.com/auth0/go-jwt-middleware/v3/validator"
)
// PublicHandler - no authentication required
func PublicHandler(w http.ResponseWriter, r *http.Request) {
response := map[string]string{
"message": "Hello from a public endpoint! You don't need to be authenticated to see this.",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
}
// PrivateHandler - requires valid JWT
func PrivateHandler(w http.ResponseWriter, r *http.Request) {
response := map[string]string{
"message": "Hello from a private endpoint! You need to be authenticated to see this.",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
}
// ScopedHandler - requires 'read:messages' permission
func ScopedHandler(w http.ResponseWriter, r *http.Request) {
claims, err := jwtmiddleware.GetClaims[*validator.ValidatedClaims](r.Context())
if err != nil {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusUnauthorized)
w.Write([]byte(`{"message":"Unauthorized."}`))
return
}
customClaims, ok := claims.CustomClaims.(*auth.CustomClaims)
if !ok || !customClaims.HasScope("read:messages") {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusForbidden)
w.Write([]byte(`{"message":"Insufficient scope."}`))
return
}
response := map[string]string{
"message": "Hello from a private endpoint! You need to be authenticated and have a scope of read:messages to see this.",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
}
```
**Protection levels:**
* **Public** (`/api/public`) — No authentication required
* **Private** (`/api/private`) — Valid JWT required
* **Scoped** (`/api/private-scoped`) — Valid JWT + `read:messages` permission required
Wire everything together in the main entry point with production-ready timeouts and graceful shutdown:
```go cmd/server/main.go expandable lines theme={null}
package main
import (
"context"
"log"
"net/http"
"os"
"os/signal"
"time"
"github.com/yourorg/myapi/internal/auth"
"github.com/yourorg/myapi/internal/config"
"github.com/yourorg/myapi/internal/handlers"
"github.com/joho/godotenv"
)
func main() {
// Load environment variables from .env file
if err := godotenv.Load(); err != nil {
log.Println("No .env file found, using environment variables")
}
// Load Auth0 configuration
cfg, err := config.LoadAuthConfig()
if err != nil {
log.Fatalf("Failed to load config: %v", err)
}
// Create JWT validator
jwtValidator, err := auth.NewValidator(cfg.Domain, cfg.Audience)
if err != nil {
log.Fatalf("Failed to create validator: %v", err)
}
// Create HTTP middleware
middleware, err := auth.NewMiddleware(jwtValidator)
if err != nil {
log.Fatalf("Failed to create middleware: %v", err)
}
// Setup routes
mux := http.NewServeMux()
mux.HandleFunc("/api/public", handlers.PublicHandler)
mux.Handle("/api/private", middleware.CheckJWT(http.HandlerFunc(handlers.PrivateHandler)))
mux.Handle("/api/private-scoped", middleware.CheckJWT(http.HandlerFunc(handlers.ScopedHandler)))
// Configure server with production timeouts
srv := &http.Server{
Addr: ":8080",
Handler: mux,
ReadTimeout: 15 * time.Second,
WriteTimeout: 15 * time.Second,
IdleTimeout: 60 * time.Second,
}
// Start server in goroutine
go func() {
log.Println("Server starting on :8080")
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Fatalf("Server failed: %v", err)
}
}()
// Graceful shutdown
quit := make(chan os.Signal, 1)
signal.Notify(quit, os.Interrupt)
<-quit
log.Println("Shutting down server...")
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := srv.Shutdown(ctx); err != nil {
log.Fatalf("Server forced to shutdown: %v", err)
}
log.Println("Server exited")
}
```
```
myapi/
├── cmd/
│ └── server/
│ └── main.go # Application entry point
├── internal/
│ ├── auth/
│ │ ├── claims.go # Custom JWT claims
│ │ ├── middleware.go # JWT middleware
│ │ └── validator.go # JWT validator
│ ├── config/
│ │ └── auth.go # Configuration loader
│ └── handlers/
│ └── api.go # HTTP handlers (public, private, scoped)
├── .env # Environment variables (not committed)
├── .gitignore
├── go.mod
└── go.sum
```
Start the development server:
```shellscript theme={null}
go run cmd/server/main.go
```
You should see: `Server starting on :8080`
Test the public endpoint (no authentication required):
```bash theme={null}
curl http://localhost:8080/api/public
```
You should see:
```json theme={null}
{
"message": "Hello from a public endpoint! You don't need to be authenticated to see this."
}
```
Test the private endpoint without a token (should fail):
```bash theme={null}
curl http://localhost:8080/api/private
```
You should see a 401 Unauthorized error:
```json theme={null}
{
"message": "Failed to validate JWT."
}
```
To test with a valid token, navigate to your API in the [Auth0 Dashboard](https://manage.auth0.com/#/apis), click the **Test** tab, and copy the access token. Then run:
```bash theme={null}
curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
http://localhost:8080/api/private
```
Test the scoped endpoint (requires `read:messages` permission):
```bash theme={null}
curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
http://localhost:8080/api/private-scoped
```
**Checkpoint**
You should now have a protected Go API. Your API:
1. Accepts requests to public endpoints without authentication
2. Rejects requests to protected endpoints without a valid token
3. Validates JWT tokens against your Auth0 domain and audience
4. Enforces permission-based access control using scopes
***
## Calling Your API
You can call your protected API from any application by passing an access token in the `Authorization` header as a Bearer token.
```bash cURL theme={null}
curl --request GET \
--url http://localhost:8080/api/private \
--header 'authorization: Bearer YOUR_ACCESS_TOKEN'
```
```go Go theme={null}
package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "http://localhost:8080/api/private"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("authorization", "Bearer YOUR_ACCESS_TOKEN")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(res)
fmt.Println(string(body))
}
```
```javascript Node.js theme={null}
const axios = require("axios").default;
const options = {
method: 'GET',
url: 'http://localhost:8080/api/private',
headers: {authorization: 'Bearer YOUR_ACCESS_TOKEN'}
};
axios.request(options).then(function (response) {
console.log(response.data);
}).catch(function (error) {
console.error(error);
});
```
```python Python theme={null}
import http.client
conn = http.client.HTTPConnection("localhost", 8080)
headers = { 'authorization': "Bearer YOUR_ACCESS_TOKEN" }
conn.request("GET", "/api/private", headers=headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
```
If you are calling the API from a Single-Page Application or a Mobile/Native application, after the authorization flow is completed, you will get an access token. How you get the token and how you make the call to the API will depend on the type of application you are developing and the framework you are using.
React, Vue, Angular quickstarts with examples
iOS, Android, React Native quickstarts
If you are calling the API from a command-line tool or another service where there isn't a user entering their credentials, you need to use the [OAuth Client Credentials flow](https://auth0.com/docs/api/authentication#client-credentials).
Register a [Machine to Machine Application](https://manage.auth0.com/#/applications) in your Auth0 Dashboard.
Copy your **Client ID** and **Client Secret** from [Application Settings](https://auth0.com/docs/get-started/dashboard/application-settings).
Use the Client Credentials flow to obtain an access token:
```bash theme={null}
curl --request POST \
--url 'https://YOUR_AUTH0_DOMAIN/oauth/token' \
--header 'content-type: application/x-www-form-urlencoded' \
--data grant_type=client_credentials \
--data 'client_id=YOUR_CLIENT_ID' \
--data client_secret=YOUR_CLIENT_SECRET \
--data audience=YOUR_API_IDENTIFIER
```
**Token Reuse**: Auth0 customers are billed based on the number of Machine to Machine access tokens issued. Once your application gets an access token, it should keep using it until it expires to minimize the number of tokens requested.
***
## Advanced Usage
**DPoP (Demonstrating Proof-of-Possession)** per RFC 9449 provides enhanced security by preventing token theft through cryptographic key binding.
```go internal/auth/middleware.go theme={null}
func NewMiddleware(jwtValidator *validator.Validator) *jwtmiddleware.JWTMiddleware {
return jwtmiddleware.New(
jwtmiddleware.WithValidator(jwtValidator),
jwtmiddleware.WithDPoPMode(jwtmiddleware.DPoPRequired),
jwtmiddleware.WithLogger(slog.Default()),
)
}
```
**DPoP Modes:**
* `DPoPAllowed` (default) — Accept both Bearer and DPoP tokens
* `DPoPRequired` — Only accept DPoP tokens, reject Bearer
* `DPoPDisabled` — Only accept Bearer tokens, reject DPoP
DPoP is recommended for financial APIs, healthcare APIs, and high-security enterprise applications. Learn more in the [DPoP documentation](https://github.com/auth0/go-jwt-middleware#dpop-support).
Enable CORS to allow requests from web applications. You can use a simple middleware or a library like [rs/cors](https://github.com/rs/cors):
```bash theme={null}
go get github.com/rs/cors
```
```go cmd/server/main.go theme={null}
import "github.com/rs/cors"
// Wrap the mux with CORS middleware
handler := cors.New(cors.Options{
AllowedOrigins: []string{"http://localhost:3000"},
AllowedMethods: []string{"GET", "POST", "PUT", "DELETE"},
AllowedHeaders: []string{"Authorization", "Content-Type"},
AllowCredentials: true,
}).Handler(mux)
srv := &http.Server{
Addr: ":8080",
Handler: handler,
}
```
For production, specify exact origins instead of wildcards.
Enable detailed logging for debugging token validation:
```go internal/auth/middleware.go theme={null}
middleware := jwtmiddleware.New(
jwtmiddleware.WithValidator(jwtValidator),
jwtmiddleware.WithLogger(slog.Default()),
)
```
Add startup verification:
```go cmd/server/main.go theme={null}
log.Printf("Validator configured:")
log.Printf(" Issuer: https://%s/", cfg.Domain)
log.Printf(" Audience: %s", cfg.Audience)
log.Printf(" Algorithm: RS256")
```
***
## Troubleshooting
### "Failed to validate JWT" or 401 Unauthorized
**Problem:** The API cannot find or validate the access token.
**Solutions:**
1. Ensure the `Authorization` header is present: `Authorization: Bearer YOUR_TOKEN`
2. Check that "Bearer" is included before the token
3. Verify the token is not expired
4. Ensure you're using an **access token**, not an ID token
### "aud claim mismatch"
**Problem:** The token's audience doesn't match your API.
**Solution:** Verify `AUTH0_AUDIENCE` exactly matches your API Identifier from the Auth0 Dashboard. The audience should NOT have a trailing slash:
```bash theme={null}
# Correct
AUTH0_AUDIENCE=https://my-go-api.example.com
# Wrong (no trailing slash)
AUTH0_AUDIENCE=https://my-go-api.example.com/
```
The client application must also request a token with the correct audience parameter.
### "unexpected signing method"
**Problem:** Token algorithm doesn't match validator configuration.
**Solutions:**
1. Auth0 uses RS256 by default (asymmetric)
2. Ensure your validator specifies `validator.RS256`
3. Never use `validator.HS256` for Auth0 tokens unless specifically configured
### JWKS endpoint unreachable
**Problem:** The JWKS caching provider cannot reach Auth0's public key endpoint.
**Solutions:**
1. Check network connectivity to Auth0 (firewall/proxy settings)
2. Test JWKS endpoint manually: `curl https://YOUR_AUTH0_DOMAIN/.well-known/jwks.json`
3. Verify correct Auth0 region (us/eu/au)
### Wrong import path
**Problem:** `cannot find package "github.com/auth0/go-jwt-middleware/v3/..."`
**Solution:** Ensure all imports use the `/v3` suffix:
```go theme={null}
// Correct
import "github.com/auth0/go-jwt-middleware/v3/validator"
// Wrong
import "github.com/auth0/go-jwt-middleware/validator"
```
### Clock skew / token expired errors
**Problem:** Server clock is out of sync, causing valid tokens to appear expired.
**Solution:** The validator already includes 30s clock skew tolerance. If you need more, adjust:
```go theme={null}
validator.WithAllowedClockSkew(60*time.Second)
```
### Claims extraction fails
**Problem:** `Failed to retrieve claims` when using generics.
**Solution:** Ensure you're using the correct type parameter:
```go theme={null}
claims, err := jwtmiddleware.GetClaims[*validator.ValidatedClaims](r.Context())
```
***
## Next Steps
Now that you have a protected API, consider exploring:
* **[Role-Based Access Control](https://auth0.com/docs/manage-users/access-control/rbac)** — Implement fine-grained permissions
* **[Access Token Best Practices](https://auth0.com/docs/secure/tokens/access-tokens)** — Learn about token security
* **[Monitor Your API](https://auth0.com/docs/deploy-monitor/logs)** — Set up logging and monitoring
* **[Production Readiness Checks](https://auth0.com/docs/deploy-monitor/pre-deployment-checks/production-checks-best-practices)** — Pre-launch security review
***
## Resources
* **[go-jwt-middleware GitHub](https://github.com/auth0/go-jwt-middleware)** — Source code, examples, and DPoP support
* **[Go API Sample](https://github.com/auth0-samples/auth0-golang-api-samples)** — Complete working example
* **[Auth0 Community](https://community.auth0.com/)** — Get help from the community
# Java Springboot API
Source: https://auth0.com/docs/quickstart/backend/java-spring-security5/index
Add Auth0 JWT authentication to a Spring Boot API with protected endpoints
This Quickstart is currently in **Beta**. We'd love to hear your feedback!
If you use an AI coding assistant like Claude Code, Cursor, or GitHub Copilot, you can add Auth0 authentication automatically in minutes using [agent skills](https://agentskills.io/home).
**Install:**
```bash theme={null}
npx skills add auth0/agent-skills --skill auth0
```
**Then ask your AI assistant:**
```text theme={null}
Add Auth0 JWT authentication to my Spring Boot API
```
Your AI assistant will automatically create your Auth0 API, fetch credentials, add the Auth0 Spring Boot API SDK dependency, configure `application.yml`, and implement a `SecurityFilterChain` with JWT validation and protected endpoints. [Full agent skills documentation →](/docs/quickstart/agent-skills)
**Prerequisites:** Before you begin, ensure you have the following installed:
* **[JDK 17+](https://openjdk.org/projects/jdk/17/)** for Spring Boot 3.2+ compatibility
* **[Maven 3.6+](https://maven.apache.org/download.cgi)** or **[Gradle 7+](https://gradle.org/install/)** for dependency management
* Your preferred IDE (IntelliJ IDEA, Eclipse, or VS Code with Java support)
**Java Version Compatibility:** This quickstart works with **Java 17+** and **Spring Boot 3.2+**.
## Get Started
This quickstart demonstrates how to add Auth0 JWT authentication to a Spring Boot API. You'll build a secure API with protected endpoints using the Auth0 Spring Boot API SDK.
Create a new Spring Boot API project for this quickstart:
**Using Spring Initializr:**
```bash theme={null}
curl -L https://start.spring.io/starter.zip \
-d dependencies=web,security \
-d javaVersion=17 \
-d name=auth0-api \
-d artifactId=auth0-api \
-d packageName=com.example.auth0api \
-o auth0-api.zip
mkdir auth0-api && unzip auth0-api.zip -d auth0-api && cd auth0-api
```
**Or manually create with Maven:**
```bash theme={null}
mvn archetype:generate \
-DgroupId=com.example \
-DartifactId=auth0-api \
-DarchetypeArtifactId=maven-archetype-quickstart \
-DinteractiveMode=false
cd auth0-api
```
Add the Auth0 Spring Boot API SDK to your project dependencies:
**Maven (`pom.xml`):**
```xml theme={null}
com.auth0auth0-springboot-api1.0.0-beta.0
```
**Gradle (`build.gradle`):**
```gradle theme={null}
dependencies {
implementation 'com.auth0:auth0-springboot-api:1.0.0-beta.0'
}
```
Next up, you need to create a new API on your Auth0 tenant and add the configuration to your project.
You can choose to do this automatically by running a CLI command or do it manually via the Dashboard:
Run the following shell command on your project's root directory to create an Auth0 API and update your `application.yml` file:
```bash expandable theme={null}
AUTH0_API_NAME="My Spring Boot API" && \
AUTH0_API_IDENTIFIER="https://my-springboot-api" && \
brew tap auth0/auth0-cli && \
brew install auth0 && \
auth0 login --no-input && \
auth0 apis create -n "${AUTH0_API_NAME}" -i "${AUTH0_API_IDENTIFIER}" --offline-access --token-lifetime 86400 --signing-alg RS256 --json > auth0-api-details.json && \
DOMAIN=$(auth0 tenants list --json | jq -r '.[] | select(.active == true) | .name') && \
AUDIENCE=$(jq -r '.identifier' auth0-api-details.json) && \
mkdir -p src/main/resources && \
printf 'auth0:\n domain: %s\n audience: %s\n\nspring:\n application:\n name: auth0-api\n' "$DOMAIN" "$AUDIENCE" > src/main/resources/application.yml && \
rm auth0-api-details.json && \
echo "✅ application.yml created with your Auth0 API details:" && \
cat src/main/resources/application.yml
```
```powershell expandable theme={null}
$ApiName = "My Spring Boot API"
$ApiIdentifier = "https://my-springboot-api"
$latestRelease = Invoke-RestMethod -Uri "https://api.github.com/repos/auth0/auth0-cli/releases/latest"
$latestVersion = $latestRelease.tag_name
$version = $latestVersion -replace "^v"
Invoke-WebRequest -Uri "https://github.com/auth0/auth0-cli/releases/download/${latestVersion}/auth0-cli_${version}_Windows_x86_64.zip" -OutFile ".\auth0.zip"
Expand-Archive ".\auth0.zip" .\
[System.Environment]::SetEnvironmentVariable('PATH', $Env:PATH + ";${pwd}")
auth0 login --no-input
auth0 apis create -n "$ApiName" -i "$ApiIdentifier" --offline-access --token-lifetime 86400 --signing-alg RS256 --json | Set-Content -Path auth0-api-details.json
$Domain = (auth0 tenants list --json | ConvertFrom-Json | Where-Object { $_.active -eq $true }).name
$Audience = (Get-Content -Raw auth0-api-details.json | ConvertFrom-Json).identifier
New-Item -ItemType Directory -Force -Path "src\main\resources"
@"
auth0:
domain: "$Domain"
audience: "$Audience"
spring:
application:
name: auth0-api
"@ | Set-Content "src\main\resources\application.yml"
Remove-Item auth0-api-details.json
Write-Output "✅ application.yml created with your Auth0 API details:"
Get-Content "src\main\resources\application.yml"
```
Before you start, add Auth0 configuration to your `src/main/resources/application.yml` file
```yaml src/main/resources/application.yml expandable theme={null}
auth0:
domain: "YOUR_AUTH0_DOMAIN"
audience: "YOUR_AUTH0_API_IDENTIFIER"
spring:
application:
name: auth0-api
```
1. Go to [Auth0 Dashboard](https://manage.auth0.com) → **Applications** → **APIs**
2. Choose **Create API**
3. Enter your API details:
* **Name**: My Spring Boot API
* **Identifier**: `https://my-springboot-api` (this becomes your Audience)
* **Signing Algorithm**: RS256
4. Choose **Create**
5. Replace `YOUR_AUTH0_DOMAIN` in `application.yml` with your **Domain** from the Test tab (e.g., `your-tenant.auth0.com`)
6. Replace `YOUR_AUTH0_API_IDENTIFIER` in `application.yml` with your **Identifier**. For example `https://my-springboot-api`.
Your **Domain** should not include `https://`. Use only the domain and region. For example: `your-tenant.auth0.com`.
The **Audience** (API Identifier) is a unique identifier for your API and can be any valid URI. It doesn't need to be a publicly accessible URL.
Create a security configuration class to enable Auth0 JWT authentication. Create `src/main/java/com/example/auth0api/SecurityConfig.java`:
```java src/main/java/com/example/auth0api/SecurityConfig.java lines expandable theme={null}
package com.example.auth0api;
import com.auth0.spring.boot.Auth0AuthenticationFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@Configuration
public class SecurityConfig {
@Bean
SecurityFilterChain apiSecurity(HttpSecurity http, Auth0AuthenticationFilter authFilter) throws Exception {
return http
.csrf(csrf -> csrf.disable())
.sessionManagement(session ->
session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/public").permitAll()
.requestMatchers("/api/private").authenticated()
.anyRequest().permitAll())
.addFilterBefore(authFilter, UsernamePasswordAuthenticationFilter.class)
.build();
}
}
```
Create API endpoints to test authentication. Create `src/main/java/com/example/auth0api/ApiController.java`:
```java src/main/java/com/example/auth0api/ApiController.java expandable theme={null}
package com.example.auth0api;
import com.auth0.spring.boot.Auth0AuthenticationToken;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
@RestController
@RequestMapping("/api")
public class ApiController {
// Public endpoint - no authentication required
@GetMapping("/public")
public ResponseEntity
Start your Spring Boot application:
**Maven:**
```bash theme={null}
./mvnw spring-boot:run
```
**Gradle:**
```bash theme={null}
./gradlew bootRun
```
Your API is now running on `http://localhost:8080` (check your console output for the exact URL).
**Checkpoint**
You should now have a fully functional Auth0-protected API running on your [localhost](http://localhost:8080/)
***
## Advanced Usage
Test your protected endpoints with an access token.
**1. Get an access token** from Auth0 using the Client Credentials flow:
```bash theme={null}
curl --request POST \
--url https://YOUR_DOMAIN/oauth/token \
--header 'content-type: application/json' \
--data '{"client_id":"YOUR_CLIENT_ID","client_secret":"YOUR_CLIENT_SECRET","audience":"YOUR_AUDIENCE","grant_type":"client_credentials"}'
```
To get `YOUR_CLIENT_ID` and `YOUR_CLIENT_SECRET`, create a Machine to Machine
Application in the [Auth0 Dashboard](https://manage.auth0.com/#/applications)
and authorize it for your API.
**2. Test the public endpoint** (should return 200 OK):
```bash theme={null}
curl http://localhost:8080/api/public
```
**3. Test the protected endpoint without authentication** (should return 401 Unauthorized):
```bash theme={null}
curl http://localhost:8080/api/private
```
**4. Call the protected endpoint with the token:**
```bash theme={null}
curl http://localhost:8080/api/private \
--header 'Authorization: Bearer YOUR_ACCESS_TOKEN'
```
Access additional user information and token claims in your endpoints.
```java theme={null}
@GetMapping("/profile")
public ResponseEntity> getUserProfile(Authentication authentication) {
Auth0AuthenticationToken auth0Token = (Auth0AuthenticationToken) authentication;
Map claims = auth0Token.getAuthenticationContext().getClaims();
return ResponseEntity.ok(Map.of(
"userId", authentication.getName(),
"email", claims.get("email"),
"scope", claims.get("scope"),
"issuer", claims.get("iss"),
"audience", claims.get("aud")
));
}
```
Implement fine-grained access control using JWT scopes for enhanced security.
**1. Define scopes in your Auth0 API:**
In the [Auth0 Dashboard](https://manage.auth0.com) → APIs → Your API → Permissions, add scopes:
* `read:users` - Read user data
* `write:users` - Write user data
* `admin` - Administrative access
**2. Configure authorization policies:**
```java theme={null}
@Configuration
public class SecurityConfig {
@Bean
SecurityFilterChain apiSecurity(HttpSecurity http, Auth0AuthenticationFilter authFilter) throws Exception {
return http
.csrf(csrf -> csrf.disable())
.sessionManagement(s -> s.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/admin/**").hasAuthority("SCOPE_admin")
.requestMatchers("/api/users/**").hasAnyAuthority("SCOPE_read:users", "SCOPE_write:users")
.requestMatchers("/api/private").authenticated()
.anyRequest().permitAll())
.addFilterBefore(authFilter, UsernamePasswordAuthenticationFilter.class)
.build();
}
}
```
When requesting an access token, include the required scope:
```bash theme={null}
curl --request POST \
--url https://YOUR_DOMAIN/oauth/token \
--header 'content-type: application/json' \
--data '{"client_id":"YOUR_CLIENT_ID","client_secret":"YOUR_CLIENT_SECRET","audience":"YOUR_AUDIENCE","grant_type":"client_credentials","scope":"read:users write:users admin"}'
```
Enable DPoP (Demonstration of Proof-of-Possession) for enhanced token security that binds access tokens to cryptographic keys.
**Configure DPoP support in application.yml:**
```yaml theme={null}
auth0:
domain: "your-tenant.auth0.com"
audience: "https://my-springboot-api"
dpopMode: ALLOWED # DISABLED, ALLOWED (default), REQUIRED
dpopIatOffsetSeconds: 300 # 5 minutes (default)
dpopIatLeewaySeconds: 60 # 1 minute leeway (default: 30s)
```
**DPoP Modes:**
* `ALLOWED` (default): Accepts both Bearer and DPoP tokens
* `REQUIRED`: Only accepts DPoP tokens, rejects Bearer tokens
* `DISABLED`: Standard JWT Bearer validation only
Learn more about DPoP in the [Auth0 DPoP Documentation](https://auth0.com/docs/secure/sender-constraining/demonstrating-proof-of-possession-dpop).
***
## Common Issues
**Problem:** API returns 401 even with valid tokens.
**Solution:** Ensure `auth0.audience` exactly matches your Auth0 API identifier. The audience claim in the token must match this value.
```yaml theme={null}
# ❌ WRONG
auth0:
audience: "my-api"
# ✅ CORRECT
auth0:
audience: "https://my-springboot-api"
```
**Problem:** Token issuer validation fails.
**Solution:** Verify your Domain is correct and does not include `https://`. Use domain without `https://` prefix.
```yaml theme={null}
# ❌ WRONG
auth0:
domain: "https://your-tenant.auth0.com"
# ✅ CORRECT
auth0:
domain: "your-tenant.auth0.com"
```
**Problem:** Application fails to start with configuration errors.
**Solution:** Verify `application.yml` structure and property names. Ensure the auth0 section contains Domain and Audience values.
```yaml theme={null}
# ✅ CORRECT structure
auth0:
domain: "your-tenant.auth0.com"
audience: "https://your-api-identifier"
spring:
application:
name: auth0-api
```
**Problem:** Authentication not working despite correct configuration.
**Solution:** Ensure Auth0AuthenticationFilter is properly integrated with Spring Security chain. The filter must be added before UsernamePasswordAuthenticationFilter.
```java theme={null}
// ✅ CORRECT filter order
.addFilterBefore(authFilter, UsernamePasswordAuthenticationFilter.class)
```
**Problem:** JWKS retrieval failures or connection timeouts.
**Solution:** Corporate firewall may be blocking Auth0 endpoints. Whitelist Auth0 domains for HTTPS access:
```bash theme={null}
# Required firewall rules (outbound HTTPS/443)
*.auth0.com
*.us.auth0.com # For US region tenants
*.eu.auth0.com # For EU region tenants
*.au.auth0.com # For AU region tenants
```
**Problem:** Scope-based authorization policies always fail.
**Solution:** Ensure your access token includes the required scopes. When requesting a token, specify the scopes:
```bash theme={null}
curl --request POST \
--url https://YOUR_DOMAIN/oauth/token \
--data '{"client_id":"...","client_secret":"...","audience":"...","grant_type":"client_credentials","scope":"read:users write:users admin"}'
```
Also verify scopes are defined in your Auth0 API settings (Dashboard → APIs → Your API → Permissions).
***
## Additional Resources
Complete SDK documentation and API reference
Comprehensive code examples and integration patterns
Learn about proof-of-possession security enhancement
Official Spring Security documentation
Manage your Auth0 APIs and applications
Get help from the Auth0 community
***
## Sample Application
A complete sample application demonstrating all features is available in the SDK repository.
Includes public and protected endpoints, DPoP support, and comprehensive
examples
Clone and run:
```bash theme={null}
git clone https://github.com/auth0/auth0-auth-java.git
cd auth0-auth-java/auth0-springboot-api-playground
# Update src/main/resources/application.yml with your Auth0 configuration
# Then run:
./mvnw spring-boot:run
```
**Testing with curl:**
```bash theme={null}
# Test public endpoint
curl http://localhost:8080/api/public
# Get access token (replace with your Auth0 credentials)
curl -X POST https://YOUR_DOMAIN/oauth/token \
-H "Content-Type: application/json" \
-d '{
"client_id": "YOUR_CLIENT_ID",
"client_secret": "YOUR_CLIENT_SECRET",
"audience": "https://my-springboot-api",
"grant_type": "client_credentials"
}'
# Test protected endpoint with Bearer token
curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
http://localhost:8080/api/private
```
# Add Authorization to Your Laravel Application
Source: https://auth0.com/docs/quickstart/backend/laravel/interactive
This guide demonstrates how to integrate Auth0 with a new (or existing) Laravel 9 or 10 application.
[Auth0's Laravel SDK](https://github.com/auth0/laravel-auth0)
allows you to quickly add token-based authorization and route access control to your Laravel application. This guide
demonstrates how to integrate Auth0 with a new (or existing) [Laravel 9
or 10](https://github.com/auth0/laravel-auth0#support-policy) application.
**Backend applications differ from traditional web applications in that they do not handle user authentication or
have a user interface. They provide an API that other applications can interact with. They accept **[access tokens](https://auth0.com/docs/secure/tokens/access-tokens)** from
**`Authorization`** headers in requests to control access to routes.**
Separate front-end applications are usually built to interact with these types of backends. These can be anything
from [single-page applications](https://auth0.com/docs/quickstart/spa) or [native or mobile apps](https://auth0.com/docs/quickstart/native) (all of which Auth0 also
provides SDKs for!)
When users need to interact with your backend application, they first authenticate with Auth0 using the frontend
application. The frontend application then retrieves an access token from Auth0, which it can use to make requests
to your backend application on behalf of the user.
As their name implies, [access
tokens](https://auth0.com/docs/secure/tokens/access-tokens) are designed to address matters of access control (authorization), and do not contain information about
the user. **Backend applications work exclusively with access tokens.** You can retrieve information about the
user who created the token using the [Management
API](https://auth0.com/docs/api/management/v2), which we will demonstrate later.
**If you do not already have a Laravel application set up**, open a shell to a suitable directory for a new
project and run the following command:
```bash lines wrap theme={null}
composer create-project --prefer-dist laravel/laravel auth0-laravel-api ^9.0
```
All the commands in this guide assume you are running them from the root of your Laravel project, directory so
you should `cd` into the new project directory:
```bash lines theme={null}
cd auth0-laravel-api
```
Run the following command within your project directory to install the [Auth0 Laravel SDK](https://github.com/auth0/laravel-auth0):
```bash lines theme={null}
composer require auth0/login:^7.8 --update-with-all-dependencies
```
Then generate an SDK configuration file for your application:
```bash lines theme={null}
php artisan vendor:publish --tag auth0
```
Run the following command from your project directory to download the [Auth0 CLI](https://github.com/auth0/auth0-cli):
```bash lines wrap theme={null}
curl -sSfL https://raw.githubusercontent.com/auth0/auth0-cli/main/install.sh | sh -s -- -b .
```
Then authenticate the CLI with your Auth0 account, choosing "as a user" when prompted:
```bash lines theme={null}
./auth0 login
```
Next, create a new application with Auth0:
```bash lines theme={null}
./auth0 apps create \
--name "My Laravel Backend" \
--type "regular" \
--auth-method "post" \
--callbacks "http://localhost:8000/callback" \
--logout-urls "http://localhost:8000" \
--reveal-secrets \
--no-input \
--json > .auth0.app.json
```
You should also create a new API:
```bash lines theme={null}
./auth0 apis create \
--name "My Laravel Backend API" \
--identifier "https://github.com/auth0/laravel-auth0" \
--offline-access \
--no-input \
--json > .auth0.api.json
```
This produces two files in your project directory that configure the SDK.
As these files contain credentials it's important to treat these as sensitive. You should ensure you do not
commit these to version control. If you're using Git, you should add them to your `.gitignore` file:
```bash lines theme={null}
echo ".auth0.*.json" >> .gitignore
```
The SDK automatically registers its authorization guard with your Laravel application for use with the
`api` middleware, which by default Laravel applies to all routes in your application's
`routes/api.php` file.
For the SDK to work as expected without additional configuration, **you should define your routes in
the **`routes/api.php`** file.**
You can use the Auth0 SDK's authorization guard to restrict access to your application's routes.
To reject requests that do not contain a valid access token in the `Authorization` header, you can use
Laravel's `auth` middleware:
```php lines theme={null}
Route::get('/private', function () {
return response()->json([
'message' => 'Your token is valid; you are authorized.',
]);
})->middleware('auth');
```
You can also require the provided token to have specific [permissions](https://auth0.com/docs/manage-users/access-control/rbac) by combining this
with Laravel's `can` middleware:
```php lines theme={null}
Route::get('/scope', function () {
return response()->json([
'message' => 'Your token is valid and has the read:messages permission; you are authorized.',
]);
})->middleware('auth')->can('read:messages');
```
Information about the provided access token is available through Laravel's `Auth` Facade, or the
`auth()` helper function.
For example, to retrieve the user's identifier and email address:
```php lines theme={null}
Route::get('/', function () {
if (! auth()->check()) {
return response()->json([
'message' => 'You did not provide a valid token.',
]);
}
return response()->json([
'message' => 'Your token is valid; you are authorized.',
'id' => auth()->id(),
'token' => auth()?->user()?->getAttributes(),
]);
});
```
You can retrieve information about the user who created the access token from Auth0 using the [Auth0 Management API](https://github.com/auth0/laravel-auth0/blob/main/docs/Management.md). The SDK provides a convenient wrapper for this API,
accessible through the SDK's `management()` method.
**Before making Management API calls you must enable your application to communicate with the Management
API.** This can be done from the [Auth0 Dashboard's API page](https://manage.auth0.com/#/apis/), choosing `Auth0 Management API`, and
selecting the 'Machine to Machine Applications' tab. Authorize your Laravel application, and then click the down
arrow to choose the scopes you wish to grant.
For the following example, you should grant the `read:users` scope. A list of API endpoints and the
required scopes can be found in [the Management
API documentation](https://auth0.com/docs/api/management/v2).
```php lines theme={null}
use Auth0\Laravel\Facade\Auth0;
Route::get('/me', function () {
$user = auth()->id();
$profile = cache()->get($user);
if (null === $profile) {
$endpoint = Auth0::management()->users();
$profile = $endpoint->get($user);
$profile = Auth0::json($profile);
cache()->put($user, $profile, 120);
}
$name = $profile['name'] ?? 'Unknown';
$email = $profile['email'] ?? 'Unknown';
return response()->json([
'name' => $name,
'email' => $email,
]);
})->middleware('auth');
```
**You should cache user information in your application for brief periods.** This reduces the number
of requests your application makes to Auth0, and improves performance. You should avoid storing user
information in your application for long periods as this can lead to stale data. You should also avoid
storing user information beyond the user's identifier in persistent databases.
You are now ready to start your Laravel application, so it can accept requests:
```bash lines theme={null}
php artisan serve
```
You can learn more about [retrieving access tokens here](https://auth0.com/docs/secure/tokens/access-tokens/get-access-tokens). For this quickstart, however, you can simply use an access
token from [your API settings'
"test" view](https://manage.auth0.com/#/apis).
The `/me` route we created above will not work with a test token as there is no actual user
associated with it.
##### Checkpoint
Open a shell and try issuing requests to your application.
Begin by requesting the public route:
`curl --request GET \ --url http://localhost:8000/api \ --header 'Accept: application/json'`
Next, use your access token in an `Authorization` header to request a protected route:
`curl --request GET \ --url http://localhost:8000/api/private \ --header 'Accept: application/json' \ --header 'Authorization: Bearer YOUR_ACCESS_TOKEN'`
Finally, try requesting the scope-protected route, which will only succeed if the access token has the
`read:messages` scope granted:
`curl --request GET \ --url http://localhost:8000/api/scope \ --header 'Accept: application/json' \ --header 'Authorization: Bearer YOUR_ACCESS_TOKEN'`
### Additional Reading
* [User Repositories and Models](https://github.com/auth0/laravel-auth0/blob/main/docs/Users.md) extends the Auth0 Laravel SDK to use custom user
models, and how to store and retrieve users from a database.
* [Hooking Events](https://github.com/auth0/laravel-auth0/blob/main/docs/Events.md) covers how to listen for events raised by the Auth0 Laravel
SDK, to fully customize the behavior of your integration.
* [Management API](https://github.com/auth0/laravel-auth0/blob/main/docs/Management.md) support is built into the Auth0 Laravel SDK, allowing you to
interact with the Management API from your Laravel application.
## Next Steps
Excellent work! If you made it this far, you should now have login, logout, and user profile information running in your application.
This concludes our quickstart tutorial, but there is so much more to explore. To learn more about what you can do with Auth0, check out:
* [Auth0 Dashboard](https://manage.auth0.com/dashboard/us/dev-gja8kxz4ndtex3rq) - Learn how to configure and manage your Auth0 tenant and applications
* [laravel-auth0 SDK](https://github.com/auth0/laravel-auth0) - Explore the SDK used in this tutorial more fully
* [Auth0 Marketplace](https://marketplace.auth0.com/) - Discover integrations you can enable to extend Auth0’s functionality
```php routes/api.php lines highlight={6-16} theme={null}
json([
'message' => 'Your token is valid; you are authorized.',
]);
})->middleware('auth');
Route::get('/scope', function () {
return response()->json([
'message' => 'Your token is valid and has the `read:messages` permission; you are authorized.',
]);
})->middleware('auth')->can('read:messages');
Route::get('/', function () {
if (! auth()->check()) {
return response()->json([
'message' => 'You did not provide a valid token.',
]);
}
return response()->json([
'message' => 'Your token is valid; you are authorized.',
'id' => auth()->id(),
'token' => auth()?->user()?->getAttributes(),
]);
});
Route::get('/me', function () {
$user = auth()->id();
$profile = cache()->get($user);
if (null === $profile) {
$endpoint = Auth0::management()->users();
$profile = $endpoint->get($user);
$profile = Auth0::json($profile);
cache()->put($user, $profile, 120);
}
$name = $profile['name'] ?? 'Unknown';
$email = $profile['email'] ?? 'Unknown';
return response()->json([
'name' => $name,
'email' => $email,
]);
})->middleware('auth');
```
```php routes/api.php lines highlight={18-30} theme={null}
json([
'message' => 'Your token is valid; you are authorized.',
]);
})->middleware('auth');
Route::get('/scope', function () {
return response()->json([
'message' => 'Your token is valid and has the `read:messages` permission; you are authorized.',
]);
})->middleware('auth')->can('read:messages');
Route::get('/', function () {
if (! auth()->check()) {
return response()->json([
'message' => 'You did not provide a valid token.',
]);
}
return response()->json([
'message' => 'Your token is valid; you are authorized.',
'id' => auth()->id(),
'token' => auth()?->user()?->getAttributes(),
]);
});
Route::get('/me', function () {
$user = auth()->id();
$profile = cache()->get($user);
if (null === $profile) {
$endpoint = Auth0::management()->users();
$profile = $endpoint->get($user);
$profile = Auth0::json($profile);
cache()->put($user, $profile, 120);
}
$name = $profile['name'] ?? 'Unknown';
$email = $profile['email'] ?? 'Unknown';
return response()->json([
'name' => $name,
'email' => $email,
]);
})->middleware('auth');
```
```php routes/api.php lines highlight={32-51} theme={null}
json([
'message' => 'Your token is valid; you are authorized.',
]);
})->middleware('auth');
Route::get('/scope', function () {
return response()->json([
'message' => 'Your token is valid and has the `read:messages` permission; you are authorized.',
]);
})->middleware('auth')->can('read:messages');
Route::get('/', function () {
if (! auth()->check()) {
return response()->json([
'message' => 'You did not provide a valid token.',
]);
}
return response()->json([
'message' => 'Your token is valid; you are authorized.',
'id' => auth()->id(),
'token' => auth()?->user()?->getAttributes(),
]);
});
Route::get('/me', function () {
$user = auth()->id();
$profile = cache()->get($user);
if (null === $profile) {
$endpoint = Auth0::management()->users();
$profile = $endpoint->get($user);
$profile = Auth0::json($profile);
cache()->put($user, $profile, 120);
}
$name = $profile['name'] ?? 'Unknown';
$email = $profile['email'] ?? 'Unknown';
return response()->json([
'name' => $name,
'email' => $email,
]);
})->middleware('auth');
```
# Protect Your Express.js API
Source: https://auth0.com/docs/quickstart/backend/nodejs
This guide demonstrates how to protect Express.js API endpoints using JWT access tokens with the express-oauth2-jwt-bearer SDK.
A new **Beta** version of this quickstart is available using the `@auth0/auth0-express-api` SDK, which will soon replace this guide. [Try the Beta quickstart →](/docs/quickstart/backend/express-api-beta)
If you use an AI coding assistant like Claude Code, Cursor, or GitHub Copilot, you can add Auth0 API authentication automatically in minutes using [agent skills](https://agentskills.io/home).
**Install:**
```bash theme={null}
npx skills add auth0/agent-skills --skill auth0
```
**Then ask your AI assistant:**
```text theme={null}
Add Auth0 JWT authentication to my Express API
```
Your AI assistant will automatically create your Auth0 API, fetch credentials, install `express-oauth2-jwt-bearer`, configure the JWT middleware, and protect your API endpoints with token validation. [Full agent skills documentation →](/docs/quickstart/agent-skills)
**Prerequisites:** Before you begin, ensure you have the following installed:
* **[Node.js](https://nodejs.org/en/download)** 18 LTS or newer (supports `^18.12.0 || ^20.2.0 || ^22.1.0 || ^24.0.0`)
* **[npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm)** 8+ or **[yarn](https://classic.yarnpkg.com/lang/en/docs/install/)** 1.22+ or **[pnpm](https://pnpm.io/installation)** 8+
Verify installation: `node --version && npm --version`
**Express Version Compatibility:** This quickstart works with **Express 4.x** and **Express 5.x**.
## Get Started
This quickstart demonstrates how to protect Express.js API endpoints using JWT access tokens. You'll build a secure API that validates Auth0 access tokens, protects routes, and implements scope-based authorization.
Create a new directory for your Express API and initialize a Node.js project.
```shellscript theme={null}
mkdir auth0-express-api && cd auth0-express-api
```
Initialize the project
```shellscript theme={null}
npm init -y
```
Create the project structure
```shellscript theme={null}
touch server.js .env
```
Install the required dependencies
```shellscript theme={null}
npm install express express-oauth2-jwt-bearer dotenv
```
Add start scripts to your `package.json`:
```json package.json theme={null}
{
"scripts": {
"start": "node server.js",
"dev": "node --watch server.js"
}
}
```
Next, you need to create a new API on your Auth0 tenant and add the environment variables to your project.
You have two options to set up your Auth0 API: use a CLI command or configure manually via the Dashboard:
Run the following command in your project's root directory to create an Auth0 API:
```shellscript Mac theme={null}
# Install Auth0 CLI (if not already installed)
brew tap auth0/auth0-cli && brew install auth0
# Create Auth0 API
auth0 apis create \
--name "My Express API" \
--identifier https://my-express-api.example.com
```
```powershell Windows theme={null}
# Install Auth0 CLI (if not already installed)
scoop bucket add auth0 https://github.com/auth0/scoop-auth0-cli.git
scoop install auth0
# Create Auth0 API
auth0 apis create `
--name "My Express API" `
--identifier https://my-express-api.example.com
```
This command will:
1. Check if you're authenticated (and prompt for login if needed)
2. Create an Auth0 API with the specified identifier
3. Display the API details including the domain and identifier
After creation, copy the **Identifier** and your **Domain** values, then create your `.env` file:
```bash .env theme={null}
AUTH0_DOMAIN=YOUR_AUTH0_DOMAIN
AUTH0_AUDIENCE=YOUR_API_IDENTIFIER
```
Replace `YOUR_AUTH0_DOMAIN` with your Auth0 tenant domain (e.g., `dev-abc123.us.auth0.com`) and `YOUR_API_IDENTIFIER` with your API identifier (e.g., `https://my-express-api.example.com`).
1. Go to the [Auth0 Dashboard](https://manage.auth0.com/dashboard/)
2. Navigate to **Applications** → **APIs** → **Create API**
3. Enter a name for your API (e.g., "My Express API")
4. Set the **Identifier** (e.g., `https://my-express-api.example.com`)
* This is your API audience and must be a valid URL format
* It doesn't need to be a real URL - it's just an identifier
5. Keep **Signing Algorithm** as **RS256**
6. Click **Create**
7. Copy the **Identifier** value from the **Settings** tab
Create your `.env` file with the following values:
```bash .env theme={null}
AUTH0_DOMAIN=YOUR_AUTH0_DOMAIN
AUTH0_AUDIENCE=YOUR_API_IDENTIFIER
```
Replace `YOUR_AUTH0_DOMAIN` with your Auth0 tenant domain (e.g., `dev-abc123.us.auth0.com`) and `YOUR_API_IDENTIFIER` with your API identifier from the dashboard (e.g., `https://my-express-api.example.com`).
Verify your `.env` file exists: `cat .env` (Mac/Linux) or `type .env` (Windows)
Create your Express server and configure JWT validation:
```javascript server.js {1-3,6-7,10-13} lines theme={null}
require('dotenv').config();
const express = require('express');
const { auth } = require('express-oauth2-jwt-bearer');
const app = express();
const port = process.env.PORT || 3001;
// Configure JWT validation middleware
const checkJwt = auth({
issuerBaseURL: `https://${process.env.AUTH0_DOMAIN}`,
audience: process.env.AUTH0_AUDIENCE,
});
// Start server
app.listen(port, () => {
console.log(`API server running at http://localhost:${port}`);
});
```
**What this does:**
* Creates JWT validation middleware using your Auth0 domain and API audience
* Validates the `iss` and `aud` claims on incoming access tokens
* Makes `checkJwt` available for protecting individual routes
Add public and protected routes to your `server.js`:
```javascript server.js expandable lines theme={null}
require('dotenv').config();
const express = require('express');
const { auth, requiredScopes } = require('express-oauth2-jwt-bearer');
const app = express();
const port = process.env.PORT || 3001;
// Configure JWT validation middleware
const checkJwt = auth({
issuerBaseURL: `https://${process.env.AUTH0_DOMAIN}`,
audience: process.env.AUTH0_AUDIENCE,
});
// Public route - no authentication required
app.get('/api/public', (req, res) => {
res.json({
message: 'Hello from a public endpoint! You don\'t need to be authenticated to see this.',
timestamp: new Date().toISOString(),
});
});
// Protected route - requires valid access token
app.get('/api/private', checkJwt, (req, res) => {
res.json({
message: 'Hello from a protected endpoint! You successfully authenticated.',
user: req.auth.payload.sub,
timestamp: new Date().toISOString(),
});
});
// Protected route with scope - requires 'read:messages' scope
app.get('/api/private-scoped', checkJwt, requiredScopes('read:messages'), (req, res) => {
res.json({
message: 'Hello from a scoped endpoint! You have the required permission.',
user: req.auth.payload.sub,
scope: req.auth.payload.scope,
timestamp: new Date().toISOString(),
});
});
// Error handling middleware
app.use((err, req, res, next) => {
const status = err.status || 500;
const message = err.message || 'Internal Server Error';
res.status(status).json({
error: err.code || 'server_error',
message: status === 401 ? 'Authentication required' : message,
});
});
// Start server
app.listen(port, () => {
console.log(`API server running at http://localhost:${port}`);
});
```
**Key points:**
* Public routes don't require authentication
* Protected routes use the `checkJwt` middleware to require a valid JWT
* Scoped routes use `requiredScopes()` to require specific permissions in the token
* `req.auth.payload` contains the decoded JWT claims for authenticated requests
* The `sub` claim contains the user's unique identifier
Start the development server:
```shellscript theme={null}
npm run dev
```
Your API is now running at [http://localhost:3001](http://localhost:3001).
The `--watch` flag in Node.js 18+ automatically restarts the server when files change.
Test the public endpoint (no authentication required):
```bash theme={null}
curl http://localhost:3001/api/public
```
You should see:
```json theme={null}
{
"message": "Hello from a public endpoint! You don't need to be authenticated to see this.",
"timestamp": "2024-01-15T10:30:00.000Z"
}
```
Test the protected endpoint without a token (should fail):
```bash theme={null}
curl http://localhost:3001/api/private
```
You should see a 401 Unauthorized error:
```json theme={null}
{
"error": "unauthorized",
"message": "Authentication required"
}
```
To test with a valid token:
1. Go to [Auth0 Dashboard](https://manage.auth0.com/) → **Applications** → **APIs**
2. Select your API → **Test** tab
3. Copy the generated access token
Test your protected endpoint:
```bash theme={null}
curl http://localhost:3001/api/private \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
```
You should see:
```json theme={null}
{
"message": "Hello from a protected endpoint! You successfully authenticated.",
"user": "auth0|abc123...",
"timestamp": "2024-01-15T10:30:00.000Z"
}
```
**Checkpoint**
You should now have a protected API. Your API:
1. Accepts requests to public endpoints without authentication
2. Rejects requests to protected endpoints without a valid token
3. Validates JWT tokens against your Auth0 domain and audience
4. Provides user information from the token claims via `req.auth.payload`
***
## Advanced Usage
Scopes allow fine-grained access control. You can require specific scopes for different endpoints.
**Configure scopes in Auth0:**
1. In the [Auth0 Dashboard](https://manage.auth0.com/), go to **Applications** → **APIs** → Your API
2. Navigate to the **Permissions** tab
3. Add permissions like `read:messages`, `write:messages`, `admin:access`
**Protect routes with scopes:**
```javascript server.js theme={null}
const { auth, requiredScopes } = require('express-oauth2-jwt-bearer');
// Requires 'read:messages' scope
app.get('/api/messages', checkJwt, requiredScopes('read:messages'), (req, res) => {
res.json({
messages: [
{ id: 1, text: 'Hello!' },
{ id: 2, text: 'World!' },
],
});
});
// Requires 'admin:access' scope
app.get('/api/admin', checkJwt, requiredScopes('admin:access'), (req, res) => {
res.json({
message: 'Admin access granted',
userId: req.auth.payload.sub,
});
});
```
If a request lacks the required scope, the API returns `403 Forbidden` with an `insufficient_scope` error. Ensure the client application requests the correct scopes when obtaining an access token.
Beyond scopes, you can validate custom claims in the JWT payload:
```javascript server.js theme={null}
const { auth, claimEquals, claimIncludes, claimCheck } = require('express-oauth2-jwt-bearer');
// Require exact claim value
app.get('/api/org/:orgId',
checkJwt,
claimEquals('org_id', 'org_123'),
(req, res) => {
res.json({ message: 'Organization access granted' });
}
);
// Require claim to include all specified values
app.get('/api/roles',
checkJwt,
claimIncludes('roles', 'editor', 'viewer'),
(req, res) => {
res.json({ message: 'Role check passed' });
}
);
// Custom claim validation logic
app.get('/api/premium',
checkJwt,
claimCheck((claims) => {
return claims.subscription === 'premium' && claims.verified === true;
}),
(req, res) => {
res.json({ message: 'Premium feature access granted' });
}
);
```
Custom claims must use namespaced URLs (e.g., `https://myapp.com/roles`) unless they're standard OIDC claims. [Learn more about custom claims](https://auth0.com/docs/secure/tokens/json-web-tokens/create-custom-claims).
Allow both authenticated and anonymous access to the same route:
```javascript server.js theme={null}
const optionalAuth = auth({
issuerBaseURL: `https://${process.env.AUTH0_DOMAIN}`,
audience: process.env.AUTH0_AUDIENCE,
authRequired: false,
});
app.get('/api/feed', optionalAuth, (req, res) => {
if (req.auth) {
res.json({
message: `Welcome back, ${req.auth.payload.sub}!`,
personalizedContent: true,
});
} else {
res.json({
message: 'Welcome, guest!',
personalizedContent: false,
});
}
});
```
Enable CORS to allow requests from web applications:
```bash theme={null}
npm install cors
```
```javascript server.js theme={null}
const cors = require('cors');
app.use(cors({
origin: ['http://localhost:3000', 'http://localhost:5173'],
allowedHeaders: ['Authorization', 'Content-Type'],
exposedHeaders: ['WWW-Authenticate'],
}));
```
For production, specify exact origins:
```javascript server.js theme={null}
app.use(cors({
origin: [
'https://myapp.com',
'https://www.myapp.com'
],
credentials: true,
methods: ['GET', 'POST', 'PUT', 'DELETE'],
}));
```
Add comprehensive error handling for authentication errors:
```javascript server.js theme={null}
const { UnauthorizedError, InvalidTokenError, InsufficientScopeError } = require('express-oauth2-jwt-bearer');
app.use((err, req, res, next) => {
if (err instanceof InsufficientScopeError) {
return res.status(403).json({
error: 'forbidden',
message: 'You do not have permission to access this resource',
required_scopes: err.requiredScopes,
});
}
if (err instanceof InvalidTokenError) {
return res.status(401).json({
error: 'invalid_token',
message: 'The provided token is invalid or expired',
});
}
if (err instanceof UnauthorizedError) {
return res.status(401).set(err.headers).json({
error: 'unauthorized',
message: 'Authentication required',
});
}
next(err);
});
```
For TypeScript projects, install type definitions and configure your project:
```bash theme={null}
npm install -D typescript @types/express @types/node
```
Create `server.ts`:
```typescript server.ts theme={null}
import 'dotenv/config';
import express, { Request, Response, NextFunction } from 'express';
import { auth, requiredScopes, UnauthorizedError } from 'express-oauth2-jwt-bearer';
const app = express();
const port = process.env.PORT || 3001;
const checkJwt = auth({
issuerBaseURL: `https://${process.env.AUTH0_DOMAIN}`,
audience: process.env.AUTH0_AUDIENCE,
});
app.get('/api/public', (req: Request, res: Response) => {
res.json({ message: 'Public endpoint - no authentication required' });
});
app.get('/api/private', checkJwt, (req: Request, res: Response) => {
res.json({
message: 'Private endpoint',
user: req.auth?.payload.sub,
});
});
app.use((err: Error, req: Request, res: Response, next: NextFunction) => {
if (err instanceof UnauthorizedError) {
res.status(err.status).set(err.headers).json({
error: err.code || 'unauthorized',
message: 'Authentication required',
});
} else {
res.status(500).json({
error: 'server_error',
message: 'Internal Server Error',
});
}
});
app.listen(port, () => {
console.log(`API server running at http://localhost:${port}`);
});
```
Add a `tsconfig.json`:
```json tsconfig.json theme={null}
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"outDir": "./dist"
},
"include": ["*.ts"]
}
```
Run with: `npx ts-node server.ts`
***
## Troubleshooting
### "No authorization token was found"
**Problem:** The API cannot find the access token in the request.
**Solutions:**
1. Ensure the `Authorization` header is present: `Authorization: Bearer YOUR_TOKEN`
2. Check that "Bearer" is included before the token
3. Verify the token is not expired
### "Invalid token" or "jwt malformed"
**Problem:** The token format is invalid.
**Solutions:**
1. Ensure you're using an **access token**, not an ID token
2. The token should be obtained with your API's `audience` parameter
3. Check that the token is a valid JWT (should have three parts separated by dots)
### Unexpected "iss" or "aud" value
**Problem:** The issuer or audience in the token doesn't match your configuration.
**Solutions:**
1. Decode your token at [jwt.io](https://jwt.io)
2. Check the `iss` claim matches `https://YOUR_AUTH0_DOMAIN/` (note the trailing slash)
3. Check the `aud` claim matches your `AUTH0_AUDIENCE` exactly
4. Verify your `.env` values:
```bash theme={null}
AUTH0_DOMAIN=dev-abc123.us.auth0.com
AUTH0_AUDIENCE=https://my-express-api.example.com
```
### "You must provide an issuerBaseURL" or "audience is required"
**Problem:** Environment variables are not being loaded.
**Solutions:**
1. Ensure `.env` file exists in your project root
2. Verify `dotenv` is installed: `npm install dotenv`
3. Add `require('dotenv').config()` at the very top of your server file
4. Check variable names match exactly (case-sensitive)
### 401 Unauthorized on all requests
**Possible causes:**
* Token is expired
* Audience doesn't match
* Issuer doesn't match
**Debug steps:**
1. Decode your token at [jwt.io](https://jwt.io)
2. Check the `exp` claim hasn't passed
3. Verify `aud` claim matches your `AUTH0_AUDIENCE` exactly
4. Verify `iss` claim is `https://{AUTH0_DOMAIN}/`
5. Ensure Authorization header format is `Bearer YOUR_TOKEN` (with space)
### 403 Forbidden with "insufficient\_scope"
**Problem:** The token doesn't have the required scopes.
**Solutions:**
1. Verify the scopes are defined in your Auth0 API (Dashboard → **Applications** → **APIs** → **Permissions**)
2. Request the scopes when obtaining the token
3. Check the token's `scope` claim includes the required scopes
### CORS errors in browser
**Problem:** Browser blocks API requests due to CORS policy.
**Solution:** Install and configure `cors`:
```bash theme={null}
npm install cors
```
```javascript theme={null}
const cors = require('cors');
app.use(cors({
origin: 'http://localhost:3000',
}));
```
***
## Next Steps
Now that you have a protected API, consider exploring:
* **[Role-Based Access Control](https://auth0.com/docs/manage-users/access-control/rbac)** - Implement fine-grained permissions
* **[API Authorization Best Practices](https://auth0.com/docs/secure/tokens/access-tokens)** - Learn about access token best practices
* **[Monitor Your API](https://auth0.com/docs/deploy-monitor/logs)** - Set up logging and monitoring
* **[Auth0 Community](https://community.auth0.com/)** - Get help from the community
***
## Resources
* **[express-oauth2-jwt-bearer GitHub](https://github.com/auth0/node-oauth2-jwt-bearer/tree/main/packages/express-oauth2-jwt-bearer)** - Source code and examples
* **[Express.js Documentation](https://expressjs.com/)** - Learn more about Express
* **[Auth0 API Authentication](https://auth0.com/docs/secure/tokens/access-tokens)** - Understanding access tokens
* **[JWT.io](https://jwt.io/)** - Debug and decode JWTs
# Add Authorization to Your PHP Application
Source: https://auth0.com/docs/quickstart/backend/php/interactive
This guide demonstrates how to integrate Auth0, add token-based authorization, and protect application routes using the Auth0 PHP SDK.
Auth0 allows you to add token-based endpoint authorization to almost any application type quickly. This guide
demonstrates how to integrate Auth0, add token-based authorization, and protect application routes using the Auth0
PHP SDK.
To use this quickstart, you’ll need to:
To use Auth0 services, you need to have an application registered in the Auth0 Dashboard. The Auth0 application
is where you configure how you want authentication to work for your project.
### Configure an application
Use the interactive selector to create a new Auth0 application or select an existing application that represents
the project you want to integrate. Every application in Auth0 is assigned an alphanumeric, unique client ID that
your application code uses to call Auth0 APIs through the SDK.
Any settings you configure using this quickstart automatically updates for your application in the [Dashboard](https://manage.auth0.com/#/), which is where you
can manage your applications in the future.
If you would rather explore a complete configuration, you can view a sample application instead.
### Configure an API
Similarly, you need to create a new Auth0 API or use an existing API that represents the project you're
integrating from the [Dashboard](https://manage.auth0.com/#/). Choose a unique identifier for the API and make a note of it. You need
that identifier to configure your application below.
Auth0 provides a [PHP
SDK](https://github.com/auth0/auth0-PHP) (Auth0-PHP) to simplify the process of implementing Auth0 authentication and authorization in PHP apps.
The Auth0 PHP SDK requires [PSR-17](https://www.php-fig.org/psr/psr-17/) and [PSR-18](https://www.php-fig.org/psr/psr-18/) installed, compatible HTTP libraries for managing network requests. If you
don't have libraries available, you can install reliable choices by running the following commands in your
terminal:
```bash lines theme={null}
cd
composer require symfony/http-client nyholm/psr7
```
Now, install the Auth0 PHP SDK by running the following command in your terminal:
```bash lines theme={null}
composer require auth0/auth0-php
```
### Configure the Auth0 SDK
For the SDK to function properly, you must set the following properties in the Auth0 SDK during initialization:
* `strategy`: The strategy helps guide the behavior of the SDK for the use case of your app. In this
case, you want to set this to the constant
`Auth0\SDK\Configuration\SdkConfiguration::STRATEGY_API`
* domain: The domain of your Auth0 tenant. Generally, you find this in the Auth0 Dashboard under Application's
Settings in the Domain field. If you are using a custom domain, set this to the value of your custom domain
instead.
* clientId: The ID of the Auth0 Application you set up earlier in this quickstart. You can find this in the
Auth0 Dashboard under your Application's Settings in the Client ID field.
* clientSecret: The secret of the Auth0 application you created earlier in this quickstart. Client secret is in
the Auth0 Dashboard under your Application's Settings in the Client Secret field.
* audience: The identifier of the Auth0 API you registered above. This must be provided as an array.
##### Checkpoint
Your Auth0 SDK is now properly configured. Run your application to verify that:
* The SDK is initializing correctly.
* Your application is not throwing any errors related to Auth0.
Next, expand your application to retrieve and process bearer tokens. Bearer tokens are access tokens provided to
your API with requests from clients on a users' behalf. Access tokens approve or deny access to routes in your
application. This is referred to as endpoint authorization.
The easiest way to retrieve access tokens from a request is using the PHP SDK's `getBearerToken()`
method. This method fetches tokens from GET parameters, POST bodies, request headers, and other sources. In this
case, the PHP SDK processes tokens passed from GET requests in the `token` parameter or from the HTTP
`Authorization` header.
Now, install a routing library to help direct incoming requests to your application. This isn't a required step,
but simplifies the application structure for the purposes of this quickstart.
```bash lines theme={null}
composer require steampixel/simple-php-router
```
Create a new file in your application called `router.php` to define the routes. Copy in the code from
the interactive panel to the right under the **router.php** tab.
Now that you have configured your Auth0 application, the Auth0 PHP SDK, and you application retrieves bearer
tokens from requests, the next step is to set up endpoint authorization for your project. The
`getBearerToken()` method you implemented above returns a `Token` class that includes
details on the request's access.
Since the `getBearerToken()` method automatically validates and verifies the incoming request, your
application determines the details of the access token by evaluating the method's response. When the response is
null, no valid token has been provided. Otherwise, inspect the contents of the response to learn more about the
request.
In the interactive panel to the right, you can see a check if the response is null or not to filter access to
your `/api/private` route.
In some cases, you may want to filter access to a specific route based on the requested scopes in an access
token. As shown in the interactive panel on the right, evaluate the contents of the 'scope' property from the
`getBearerToken()` method's response to check the scopes granted by the access token.
## Next Steps
Excellent work! If you made it this far, you should now have login, logout, and user profile information running in your application.
This concludes our quickstart tutorial, but there is so much more to explore. To learn more about what you can do with Auth0, check out:
* [Auth0 Dashboard](https://manage.auth0.com/dashboard/us/dev-gja8kxz4ndtex3rq) - Learn how to configure and manage your Auth0 tenant and applications
* [Auth0-PHP SDK](https://github.com/auth0/auth0-php) - Explore the SDK used in this tutorial more fully
* [Auth0 Marketplace](https://marketplace.auth0.com/) - Discover integrations you can enable to extend Auth0’s functionality
```php index.php lines highlight={} theme={null}
getBearerToken(
get: ['token'],
server: ['Authorization']
);
require('router.php');
```
```php router.php lines highlight={} theme={null}
'Hello from a public endpoint! You don\'t need to be authenticated to see this.',
'token' => $token
]);
});
Route::add('/api/private', function() use ($token) {
if ($token === null) {
http_response_code(401);
exit;
}
routeResponse([
'message' => 'Hello from a private endpoint! You need to be authenticated to see this.',
'token' => $token,
]);
});
Route::add('/api/private-scoped', function() use ($token) {
if ($token === null) {
http_response_code(401);
exit;
}
if (! in_array('read:messages', $token['scopes'], true)) {
http_response_code(401);
exit;
}
routeResponse([
'message' => 'Hello from a private endpoint! You need to be authenticated and have a scope of read:messages to see this.',
'token' => $token,
]);
});
// The following route is just to avoid confusion.
// We're not using an 'index route' in this app, so redirect requests to /api/public.
Route::add('/', function() {
header('Location: /api/public');
});
Route::run();
```
```php index.php lines highlight={20-23} theme={null}
getBearerToken(
get: ['token'],
server: ['Authorization']
);
require('router.php');
```
```php router.php lines highlight={} theme={null}
'Hello from a public endpoint! You don\'t need to be authenticated to see this.',
'token' => $token
]);
});
Route::add('/api/private', function() use ($token) {
if ($token === null) {
http_response_code(401);
exit;
}
routeResponse([
'message' => 'Hello from a private endpoint! You need to be authenticated to see this.',
'token' => $token,
]);
});
Route::add('/api/private-scoped', function() use ($token) {
if ($token === null) {
http_response_code(401);
exit;
}
if (! in_array('read:messages', $token['scopes'], true)) {
http_response_code(401);
exit;
}
routeResponse([
'message' => 'Hello from a private endpoint! You need to be authenticated and have a scope of read:messages to see this.',
'token' => $token,
]);
});
// The following route is just to avoid confusion.
// We're not using an 'index route' in this app, so redirect requests to /api/public.
Route::add('/', function() {
header('Location: /api/public');
});
Route::run();
```
```php router.php lines highlight={} theme={null}
'Hello from a public endpoint! You don\'t need to be authenticated to see this.',
'token' => $token
]);
});
Route::add('/api/private', function() use ($token) {
if ($token === null) {
http_response_code(401);
exit;
}
routeResponse([
'message' => 'Hello from a private endpoint! You need to be authenticated to see this.',
'token' => $token,
]);
});
Route::add('/api/private-scoped', function() use ($token) {
if ($token === null) {
http_response_code(401);
exit;
}
if (! in_array('read:messages', $token['scopes'], true)) {
http_response_code(401);
exit;
}
routeResponse([
'message' => 'Hello from a private endpoint! You need to be authenticated and have a scope of read:messages to see this.',
'token' => $token,
]);
});
// The following route is just to avoid confusion.
// We're not using an 'index route' in this app, so redirect requests to /api/public.
Route::add('/', function() {
header('Location: /api/public');
});
Route::run();
```
```php index.php lines highlight={} theme={null}
getBearerToken(
get: ['token'],
server: ['Authorization']
);
require('router.php');
```
```php router.php lines highlight={21-31} theme={null}
'Hello from a public endpoint! You don\'t need to be authenticated to see this.',
'token' => $token
]);
});
Route::add('/api/private', function() use ($token) {
if ($token === null) {
http_response_code(401);
exit;
}
routeResponse([
'message' => 'Hello from a private endpoint! You need to be authenticated to see this.',
'token' => $token,
]);
});
Route::add('/api/private-scoped', function() use ($token) {
if ($token === null) {
http_response_code(401);
exit;
}
if (! in_array('read:messages', $token['scopes'], true)) {
http_response_code(401);
exit;
}
routeResponse([
'message' => 'Hello from a private endpoint! You need to be authenticated and have a scope of read:messages to see this.',
'token' => $token,
]);
});
// The following route is just to avoid confusion.
// We're not using an 'index route' in this app, so redirect requests to /api/public.
Route::add('/', function() {
header('Location: /api/public');
});
Route::run();
```
```php index.php lines highlight={} theme={null}
getBearerToken(
get: ['token'],
server: ['Authorization']
);
require('router.php');
```
```php router.php lines highlight={33-48} theme={null}
'Hello from a public endpoint! You don\'t need to be authenticated to see this.',
'token' => $token
]);
});
Route::add('/api/private', function() use ($token) {
if ($token === null) {
http_response_code(401);
exit;
}
routeResponse([
'message' => 'Hello from a private endpoint! You need to be authenticated to see this.',
'token' => $token,
]);
});
Route::add('/api/private-scoped', function() use ($token) {
if ($token === null) {
http_response_code(401);
exit;
}
if (! in_array('read:messages', $token['scopes'], true)) {
http_response_code(401);
exit;
}
routeResponse([
'message' => 'Hello from a private endpoint! You need to be authenticated and have a scope of read:messages to see this.',
'token' => $token,
]);
});
// The following route is just to avoid confusion.
// We're not using an 'index route' in this app, so redirect requests to /api/public.
Route::add('/', function() {
header('Location: /api/public');
});
Route::run();
```
```php index.php lines highlight={} theme={null}
getBearerToken(
get: ['token'],
server: ['Authorization']
);
require('router.php');
```
# Flask API
Source: https://auth0.com/docs/quickstart/backend/python/index
This guide demonstrates how to integrate Auth0 with any new or existing Python API built with Flask.
**Prerequisites:** Before you begin, ensure you have the following installed:
* **Python 3.9** or higher
* **pip** or Poetry package manager
* **[jq](https://jqlang.org/)** - Required for Auth0 CLI setup
* Your preferred code editor
**Flask Version Compatibility:** This quickstart requires **Flask 3.0** or higher for native async support.
## Get Started
This guide demonstrates how to integrate Auth0 with any new or existing Python API built with [Flask](https://flask.palletsprojects.com/).
Create a new directory for your Flask API:
```bash theme={null}
mkdir flask-auth0-api
cd flask-auth0-api
```
Create a virtual environment and activate it:
```bash theme={null}
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
```
Create a `requirements.txt` file with the following dependencies:
```txt requirements.txt theme={null}
flask>=3.0
auth0-api-python
python-dotenv
```
Install the dependencies:
```bash theme={null}
pip install -r requirements.txt
```
Next up, you need to create a new API on your Auth0 tenant and configure your application.
You can choose to do this automatically by running a CLI command or do it manually via the Dashboard:
1. Go to the [Auth0 Dashboard](https://manage.auth0.com/) → **Applications** → **APIs**
2. Click **Create API**
3. Enter your API details:
* **Name**: `My Flask API`
* **Identifier**: `https://my-flask-api` (this will be your audience)
* **Signing Algorithm**: **RS256**
4. Click **Create**
5. Copy your **Domain** from the Dashboard (found under **Applications** → **Applications** → **\[Your App]** → **Settings**)
6. Copy the **Identifier** you just created (this is your audience)
Your **Domain** should not include `https://` - use only the domain name (e.g., `your-tenant.auth0.com`).
The **Audience** (API Identifier) is a unique identifier for your API and can be any valid URI.
Run the following shell command on your project's root directory to create an Auth0 API and generate a `.env` file:
```shellscript Mac theme={null}
AUTH0_API_NAME="My Flask API" && AUTH0_API_IDENTIFIER="https://my-flask-api" && brew tap auth0/auth0-cli && brew install auth0 && auth0 login --no-input && auth0 apis create --name "${AUTH0_API_NAME}" --identifier "${AUTH0_API_IDENTIFIER}" --signing-alg RS256 --json > auth0-api-details.json && DOMAIN=$(auth0 tenants list --json | jq -r '.[] | select(.active == true) | .name') && AUDIENCE=$(jq -r '.identifier' auth0-api-details.json) && echo "AUTH0_DOMAIN=${DOMAIN}" > .env && echo "AUTH0_AUDIENCE=${AUDIENCE}" >> .env && rm auth0-api-details.json && echo ".env file created with your Auth0 API details:" && cat .env
```
```shellscript Windows theme={null}
$ApiName = "My Flask API"; $ApiIdentifier = "https://my-flask-api"; winget install Auth0.CLI; auth0 login --no-input; auth0 apis create -n "$ApiName" -i "$ApiIdentifier" --signing-alg RS256 --json | Set-Content -Path auth0-api-details.json; $Domain = (auth0 tenants list --json | ConvertFrom-Json | Where-Object { $_.active -eq $true }).name; $Audience = (Get-Content -Raw auth0-api-details.json | ConvertFrom-Json).identifier; Set-Content -Path .env -Value "AUTH0_DOMAIN=$Domain"; Add-Content -Path .env -Value "AUTH0_AUDIENCE=$Audience"; Remove-Item auth0-api-details.json; Write-Output ".env file created with your Auth0 API details:"; Get-Content .env
```
Configure permissions (scopes) for your API to control access to specific resources:
1. In the [Auth0 Dashboard](https://manage.auth0.com/), navigate to **Applications** → **APIs**
2. Select your API (`My Flask API`)
3. Go to the **Permissions** tab
4. Click **Add Permission**
5. Add the following permission:
* **Permission (Scope)**: `read:messages`
* **Description**: `Read messages`
6. Click **Add**
Permissions define what actions can be performed on your API. You can add multiple permissions like `write:messages`, `delete:messages`, etc. The `/api/private-scoped` endpoint in this quickstart requires the `read:messages` permission.
If you used the **CLI** method in Step 3, your `.env` file was automatically created. Skip to creating the `app.py` file below.
If you used the **Dashboard** method, create a `.env` file in your project root to store your Auth0 configuration:
```bash .env theme={null}
AUTH0_DOMAIN=your-tenant.us.auth0.com
AUTH0_AUDIENCE=https://my-flask-api
```
Replace `your-tenant.us.auth0.com` with your actual Auth0 domain and update the `API_IDENTIFIER` to match your API identifier from the dashboard.
Create an `app.py` file and configure the Auth0 API client:
```python app.py theme={null}
import os
import asyncio
from flask import Flask, request, jsonify, g
from functools import wraps
from dotenv import load_dotenv
from auth0_api_python import ApiClient, ApiClientOptions
from auth0_api_python.errors import BaseAuthError
# Load environment variables
load_dotenv()
app = Flask(__name__)
# Initialize Auth0 API client (singleton - created once)
api_client = ApiClient(ApiClientOptions(
domain=os.getenv("AUTH0_DOMAIN"),
audience=os.getenv("AUTH0_AUDIENCE")
))
```
Add a decorator for protecting routes and create public and private endpoints:
```python app.py theme={null}
# Authentication decorator
def require_auth(f):
@wraps(f)
def decorated_function(*args, **kwargs):
auth_header = request.headers.get("Authorization", "")
if not auth_header.startswith("Bearer "):
return jsonify({"error": "Missing or invalid authorization header"}), 401
token = auth_header.split(" ")[1]
try:
claims = asyncio.run(api_client.verify_access_token(token))
g.user_claims = claims
return f(*args, **kwargs)
except BaseAuthError as e:
return (
jsonify({"error": str(e)}),
e.get_status_code(),
e.get_headers()
)
return decorated_function
# Public endpoint - no authentication required
@app.route("/api/public", methods=["GET"])
def public():
return jsonify({"message": "This endpoint is public"})
# Protected endpoint - requires authentication
@app.route("/api/private", methods=["GET"])
@require_auth
def private():
return jsonify({
"message": "This endpoint requires authentication",
"user": g.user_claims.get("sub")
})
# Protected endpoint with permission validation
@app.route("/api/private-scoped", methods=["GET"])
@require_auth
def private_scoped():
scopes = g.user_claims.get("scope", "").split()
if "read:messages" not in scopes:
return jsonify({"error": "Insufficient permissions"}), 403
return jsonify({
"message": "Private scoped endpoint - read:messages permission granted",
"user": g.user_claims.get("sub")
})
if __name__ == "__main__":
app.run(debug=True, port=5000)
```
Start your Flask application:
```bash theme={null}
python app.py
```
Your API is now running on `http://localhost:5000`.
**Checkpoint**
You should now have a fully functional Auth0-protected Flask API running on your localhost with three endpoints:
* `/api/public` - Accessible without authentication
* `/api/private` - Requires a valid Auth0 access token
* `/api/private-scoped` - Requires authentication and the `read:messages` permission
## Test Your API
To test your protected endpoints, you need an access token.
### Get a test token
1. Go to the [Auth0 Dashboard](https://manage.auth0.com/)
2. Navigate to **Applications → APIs**
3. Select your API
4. Go to the **Test** tab
5. Copy the access token
### Make a request
Test the public endpoint (no token required):
```bash theme={null}
curl http://localhost:5000/api/public
```
Test the protected endpoint (token required):
```bash theme={null}
curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
http://localhost:5000/api/private
```
Replace `YOUR_ACCESS_TOKEN` with the token you copied from the Auth0 Dashboard.
## Advanced Usage
Require specific claims to be present in the access token:
```python theme={null}
try:
claims = await api_client.verify_access_token(
access_token=token,
required_claims=["email_verified", "org_id"]
)
except BaseAuthError as e:
return jsonify({"error": "Missing required claims"}), 401
```
For enhanced security, enable DPoP (Demonstrating Proof-of-Possession). DPoP enhances OAuth 2.0 by binding access tokens to cryptographic keys.
```python theme={null}
import asyncio
# Configure API client with DPoP enabled (Allowed mode)
api_client = ApiClient(ApiClientOptions(
domain=os.getenv("AUTH0_DOMAIN"),
audience=os.getenv("AUTH0_AUDIENCE"),
dpop_enabled=True, # Default - enables DPoP support
dpop_required=False # Default - allows both Bearer and DPoP tokens
))
# For Required mode (DPoP-only, rejects Bearer tokens)
# dpop_required=True
# DPoP-aware decorator
def require_auth_dpop(f):
@wraps(f)
def decorated_function(*args, **kwargs):
headers = {
"authorization": request.headers.get("Authorization", ""),
"dpop": request.headers.get("DPoP", "") # DPoP proof header
}
try:
# verify_request() automatically detects Bearer or DPoP scheme
claims = asyncio.run(api_client.verify_request(
headers=headers,
http_method=request.method,
http_url=request.url
))
g.user_claims = claims
return f(*args, **kwargs)
except BaseAuthError as e:
return jsonify({"error": str(e)}), e.get_status_code(), e.get_headers()
return decorated_function
@app.route("/api/dpop-protected")
@require_auth_dpop
def dpop_protected():
return jsonify({
"message": "Successfully authenticated with DPoP or Bearer",
"user": g.user_claims.get("sub")
})
```
The `verify_request()` method automatically detects whether the request uses Bearer or DPoP authentication. When DPoP is used, it validates both the access token and the DPoP proof according to RFC 9449.
Create a decorator to check for specific scopes:
```python theme={null}
def require_scope(required_scope):
def decorator(f):
@wraps(f)
async def wrapper(*args, **kwargs):
if not hasattr(g, "user_claims"):
return jsonify({"error": "Unauthorized"}), 401
scopes = g.user_claims.get("scope", "").split()
if required_scope not in scopes:
return jsonify({"error": "Insufficient permissions"}), 403
return await f(*args, **kwargs)
return wrapper
return decorator
@app.route("/api/admin")
@require_auth
@require_scope("admin:write")
async def admin_endpoint():
return jsonify({"message": "Admin access granted"})
```
Implement comprehensive error handling with specific error types:
```python theme={null}
from auth0_api_python.errors import (
BaseAuthError,
VerifyAccessTokenError,
GetTokenByExchangeProfileError,
ApiError
)
@app.errorhandler(BaseAuthError)
def handle_auth_error(error):
"""Handle all Auth0 authentication errors"""
return jsonify({
"error": error.get_error_code(),
"error_description": str(error)
}), error.get_status_code(), error.get_headers()
@app.errorhandler(VerifyAccessTokenError)
def handle_token_verification_error(error):
"""Handle token verification failures specifically"""
app.logger.warning(f"Token verification failed: {str(error)}")
return jsonify({
"error": "invalid_token",
"error_description": str(error)
}), 401, error.get_headers()
@app.errorhandler(ApiError)
def handle_api_error(error):
"""Handle Auth0 API errors (network, rate limits, etc.)"""
app.logger.error(f"Auth0 API error: {error.code} - {error.message}")
return jsonify({
"error": error.code,
"error_description": error.message
}), error.status_code or 500
@app.errorhandler(Exception)
def handle_generic_error(error):
"""Catch-all for unexpected errors"""
app.logger.error(f"Unexpected error: {str(error)}", exc_info=True)
return jsonify({"error": "Internal server error"}), 500
```
All authentication errors extend from `BaseAuthError`, which provides methods like `get_status_code()`, `get_headers()`, and `get_error_code()` for proper HTTP responses with WWW-Authenticate headers.
For applications where most endpoints require authentication, use Flask's `before_request` to validate tokens globally:
```python theme={null}
from flask import g
PUBLIC_ROUTES = ["/api/public", "/health"]
@app.before_request
async def verify_token():
# Skip auth for public routes
if request.path in PUBLIC_ROUTES:
return
auth_header = request.headers.get("Authorization", "")
if not auth_header.startswith("Bearer "):
return jsonify({"error": "Missing authorization"}), 401
token = auth_header.split(" ")[1]
try:
claims = await api_client.verify_access_token(token)
g.user_claims = claims
except BaseAuthError as e:
return jsonify({"error": str(e)}), e.get_status_code(), e.get_headers()
@app.route("/api/protected-data")
async def protected_data():
# Claims automatically available via g.user_claims
return jsonify({"user_id": g.user_claims["sub"]})
```
## Common Issues
**Symptom**: Getting 401 errors even with valid-looking tokens
**Cause**: The audience in your token doesn't match the audience configured in your API client
**Solution**:
1. Verify the `AUTH0_AUDIENCE` in your `.env` file matches your Auth0 API Identifier exactly
2. The audience is case-sensitive
3. Ensure the audience is a URL or URN format (e.g., `https://my-api` not `my-api`)
**Symptom**: Token validation fails with issuer mismatch
**Cause**: The domain configuration doesn't match the token issuer
**Solution**:
1. Verify `AUTH0_DOMAIN` is correct (e.g., `tenant.us.auth0.com`)
2. Don't include `https://` in the domain
3. Don't include a trailing slash
**Symptom**: `None` values or environment variable errors
**Cause**: Environment variables not loaded or `.env` file not found
**Solution**:
1. Ensure `.env` file exists in your project root
2. Verify `load_dotenv()` is called before accessing `os.getenv()`
3. Check that variable names match exactly (case-sensitive)
**Symptom**: `RuntimeError: This event loop is already running` or similar async errors
**Cause**: Using async routes without Flask 3.0+ or mixing sync/async incorrectly
**Solution**:
1. Upgrade to Flask 3.0 or higher: `pip install --upgrade flask`
2. Ensure all route handlers using `api_client` are declared as `async def`
3. Don't use `asyncio.run()` within route handlers
**Symptom**: `VerifyAccessTokenError: Token is expired`
**Cause**: The access token has passed its expiration time
**Solution**:
1. Request a new token from the Auth0 Dashboard Test tab
2. Implement token refresh in your client application
3. Tokens from the Dashboard are typically valid for 24 hours
**Symptom**: `Missing or invalid authorization header` error
**Cause**: Request doesn't include the `Authorization` header or uses incorrect format
**Solution**:
1. Ensure the header is named `Authorization` (capital A)
2. Use format: `Authorization: Bearer YOUR_TOKEN`
3. Don't include quotes around the token
## Additional Resources
Complete SDK documentation and API reference
Official Flask framework documentation
Manage your Auth0 tenant and APIs
Learn about access tokens and API security
Learn about proof-of-possession security
Get help from the Auth0 community
## Next Steps
Check out the [Auth0 Python API samples repository](https://github.com/auth0-samples/auth0-python-api-samples) for complete working examples with Flask.
# Add Authorization to Your Ruby on Rails API
Source: https://auth0.com/docs/quickstart/backend/rails/interactive
This tutorial performs access token validation using the jwt Gem within a custom Auth0Client class.
This tutorial performs access token validation using the [jwt](https://github.com/jwt/ruby-jwt) Gem within a custom `Auth0Client` class. A Concern called
`Secured` is used to authorize endpoints which require authentication through an incoming access token.
If you have not created an API in your Auth0 dashboard yet, use the interactive selector to create a new Auth0 API
or select an existing API for your project.
To set up your first API through the Auth0 dashboard, review [our getting started
guide](https://auth0.com/docs/get-started/auth0-overview/set-up-apis).
Each Auth0 API uses the API Identifier, which your application needs to validate the access token.
**New to Auth0?** Learn [how Auth0 works](https://auth0.com/docs/overview)
and read about [implementing API authentication
and authorization](https://auth0.com/docs/api-auth) using the OAuth 2.0 framework.
Permissions let you define how resources can be accessed on behalf of the user with a given access token. For
example, you might choose to grant read access to the `messages` resource if users have the manager
access level, and a write access to that resource if they have the administrator access level.
You can define allowed permissions in the **Permissions** view of the Auth0 Dashboard's [APIs](https://manage.auth0.com/#/apis) section.
This example uses the `read:messages` scope.
Install the \*\*jwt \*\*Gem.
```bash lines theme={null}
gem 'jwt'
bundle install
```
Create a class called `Auth0Client`. This class decodes and verifies the incoming access token taken
from the `Authorization` header of the request.
The `Auth0Client` class retrieves the public key for your Auth0 tenant and then uses it to verify the
signature of the access token. The `Token` struct defines a `validate_permissions` method to
look for a particular `scope` in an access token by providing an array of required scopes and check if
they are present in the payload of the token.
Create a Concern called `Secured` which looks for the access token in the `Authorization`
header of an incoming request.
If the token is present, the `Auth0Client.validate_token` will use the `jwt` Gem to verify
the token's signature and validate the token's claims.
In addition to verifying that the access token is valid, the Concern also includes a mechanism for confirming the
token has the sufficient **scope** to access the requested resources. In this example we define a
`validate_permissions` method that receives a block and checks the permissions by calling the
`Token.validate_permissions` method from the `Auth0Client` class.
For the `/private-scoped` route, the scopes defined will be intersected with the scopes coming in the
payload, to determine if it contains one or more items from the other array.
By adding the `Secure` concern to your application controller, you'll only need to use a
`before_action` filter in the controller that requires authorization.
Create a controller to handle the public endpoint `/api/public`.
The `/public` endpoint does not require any authorization so no `before_action` is needed.
Create a controller to handle the private endpoints: `/api/private` and
`/api/private-scoped`.
`/api/private` is available for authenticated requests containing an access token with no additional
scopes.
`/api/private-scoped` is available for authenticated requests containing an access token with the
`read:messages` scope granted
The protected endpoints need to call the `authorize` method from the `Secured` concern, for
that you use `before_action :authorize`, this ensure the `Secured.authorize` method is
called before every action in the `PrivateController`.
### Make a Call to Your API
To make calls to your API, you need an Access Token. You can get an Access Token for testing purposes from the
**Test** view in your [API
settings](https://manage.auth0.com/#/apis).
Provide the Access Token as an `Authorization` header in your requests.
```bash cURL lines theme={null}
curl --request get \
--url 'http:///%7ByourDomain%7D/api_path' \
--header 'authorization: Bearer YOUR_ACCESS_TOKEN_HERE'
```
```csharp C# lines theme={null}
var client = new RestClient("http:///%7ByourDomain%7D/api_path");
var request = new RestRequest(Method.GET);
request.AddHeader("authorization", "Bearer YOUR_ACCESS_TOKEN_HERE");
IRestResponse response = client.Execute(request);
```
```go Go lines theme={null}
package main
import (
"fmt"
"net/http"
"io/ioutil"
)
func main() {
url := "http:///%7ByourDomain%7D/api_path"
req, _ := http.NewRequest("get", url, nil)
req.Header.Add("authorization", "Bearer YOUR_ACCESS_TOKEN_HERE")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := ioutil.ReadAll(res.Body)
fmt.Println(res)
fmt.Println(string(body))
}
```
```java Java lines theme={null}
HttpResponse response = Unirest.get("http:///%7ByourDomain%7D/api_path")
.header("authorization", "Bearer YOUR_ACCESS_TOKEN_HERE")
.asString();
```
```javascript Node.JS lines theme={null}
var axios = require("axios").default;
var options = {
method: 'get',
url: 'http:///%7ByourDomain%7D/api_path',
headers: {authorization: 'Bearer YOUR_ACCESS_TOKEN_HERE'}
};
axios.request(options).then(function (response) {
console.log(response.data);
}).catch(function (error) {
console.error(error);
});
```
```objc Obj-C lines theme={null}
#import
NSDictionary *headers = @{ @"authorization": @"Bearer YOUR_ACCESS_TOKEN_HERE" };
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http:///%7ByourDomain%7D/api_path"]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:10.0];
[request setHTTPMethod:@"get"];
[request setAllHTTPHeaderFields:headers];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
NSLog(@"%@", error);
} else {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
NSLog(@"%@", httpResponse);
}
}];
[dataTask resume];
```
```php PHP lines theme={null}
#import
NSDictionary *headers = @{ @"authorization": @"Bearer YOUR_ACCESS_TOKEN_HERE" };
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http:///%7ByourDomain%7D/api_path"]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:10.0];
[request setHTTPMethod:@"get"];
[request setAllHTTPHeaderFields:headers];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
NSLog(@"%@", error);
} else {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
NSLog(@"%@", httpResponse);
}
}];
[dataTask resume];
```
```python Python lines theme={null}
import http.client
conn = http.client.HTTPConnection("")
headers = { 'authorization': "Bearer YOUR_ACCESS_TOKEN_HERE" }
conn.request("get", "/%7ByourDomain%7D/api_path", headers=headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
```
```ruby Ruby lines theme={null}
require 'uri'
require 'net/http'
url = URI("http:///%7ByourDomain%7D/api_path")
http = Net::HTTP.new(url.host, url.port)
request = Net::HTTP::Get.new(url)
request["authorization"] = 'Bearer YOUR_ACCESS_TOKEN_HERE'
response = http.request(request)
puts response.read_body
```
```swift Swift lines theme={null}
import Foundation
let headers = ["authorization": "Bearer YOUR_ACCESS_TOKEN_HERE"]
let request = NSMutableURLRequest(url: NSURL(string: "http:///%7ByourDomain%7D/api_path")! as URL,
cachePolicy: .useProtocolCachePolicy,
timeoutInterval: 10.0)
request.httpMethod = "get"
request.allHTTPHeaderFields = headers
let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
if (error != nil) {
print(error)
} else {
let httpResponse = response as? HTTPURLResponse
print(httpResponse)
}
})
dataTask.resume()
```
##### Checkpoint
Now that you have configured your application, run your application to verify that:
* `GET /api/public`is available for non-authenticated requests.
* `GET /api/private`is available for authenticated requests.
* `GET /api/private-scoped`is available for authenticated requests containing an Access
Token with the `read:messages`scope.
## Next Steps
Excellent work! If you made it this far, you should now have login, logout, and user profile information running in your application.
This concludes our quickstart tutorial, but there is so much more to explore. To learn more about what you can do with Auth0, check out:
* [Auth0 Dashboard](https://manage.auth0.com/dashboard/us/dev-gja8kxz4ndtex3rq) - Learn how to configure and manage your Auth0 tenant and applications
* [omniauth-auth0 SDK](https://github.com/auth0/omniauth-auth0) - Explore the SDK used in this tutorial more fully
* [Auth0 Marketplace](https://marketplace.auth0.com/) - Discover integrations you can enable to extend Auth0’s functionality
```rb app/controllers/concerns/secured.rb lines highlight={} theme={null}
# frozen_string_literal: true
module Secured
extend ActiveSupport::Concern
REQUIRES_AUTHENTICATION = { message: 'Requires authentication' }.freeze
BAD_CREDENTIALS = {
message: 'Bad credentials'
}.freeze
MALFORMED_AUTHORIZATION_HEADER = {
error: 'invalid_request',
error_description: 'Authorization header value must follow this format: Bearer access-token',
message: 'Bad credentials'
}.freeze
INSUFFICIENT_PERMISSIONS = {
error: 'insufficient_permissions',
error_description: 'The access token does not contain the required permissions',
message: 'Permission denied'
}.freeze
def authorize
token = token_from_request
return if performed?
validation_response = Auth0Client.validate_token(token)
@decoded_token = validation_response.decoded_token
return unless (error = validation_response.error)
render json: { message: error.message }, status: error.status
end
def validate_permissions(permissions)
raise 'validate_permissions needs to be called with a block' unless block_given?
return yield if @decoded_token.validate_permissions(permissions)
render json: INSUFFICIENT_PERMISSIONS, status: :forbidden
end
private
def token_from_request
authorization_header_elements = request.headers['Authorization']&.split
render json: REQUIRES_AUTHENTICATION, status: :unauthorized and return unless authorization_header_elements
unless authorization_header_elements.length == 2
render json: MALFORMED_AUTHORIZATION_HEADER,
status: :unauthorized and return
end
scheme, token = authorization_header_elements
render json: BAD_CREDENTIALS, status: :unauthorized and return unless scheme.downcase == 'bearer'
token
end
end
```
```rb app/controllers/application_controller.rb lines highlight={} theme={null}
# frozen_string_literal: true
class ApplicationController < ActionController::API
include Secured
end
```
```rb app/lib/auth0_client.rb lines highlight={} theme={null}
```
```rb app/controllers/public_controller.rb lines highlight={} theme={null}
# frozen_string_literal: true
class PublicController < ApplicationController
def public
render json: { message: 'All good. You don\'t need to be authenticated to call this.' }
end
end
```
```rb app/controllers/private_controller.rb lines highlight={} theme={null}
# frozen_string_literal: true
class PublicController < ApplicationController
def public
render json: { message: 'All good. You don\'t need to be authenticated to call this.' }
end
end
```
```rb app/controllers/concerns/secured.rb lines highlight={} theme={null}
# frozen_string_literal: true
module Secured
extend ActiveSupport::Concern
REQUIRES_AUTHENTICATION = { message: 'Requires authentication' }.freeze
BAD_CREDENTIALS = {
message: 'Bad credentials'
}.freeze
MALFORMED_AUTHORIZATION_HEADER = {
error: 'invalid_request',
error_description: 'Authorization header value must follow this format: Bearer access-token',
message: 'Bad credentials'
}.freeze
INSUFFICIENT_PERMISSIONS = {
error: 'insufficient_permissions',
error_description: 'The access token does not contain the required permissions',
message: 'Permission denied'
}.freeze
def authorize
token = token_from_request
return if performed?
validation_response = Auth0Client.validate_token(token)
@decoded_token = validation_response.decoded_token
return unless (error = validation_response.error)
render json: { message: error.message }, status: error.status
end
def validate_permissions(permissions)
raise 'validate_permissions needs to be called with a block' unless block_given?
return yield if @decoded_token.validate_permissions(permissions)
render json: INSUFFICIENT_PERMISSIONS, status: :forbidden
end
private
def token_from_request
authorization_header_elements = request.headers['Authorization']&.split
render json: REQUIRES_AUTHENTICATION, status: :unauthorized and return unless authorization_header_elements
unless authorization_header_elements.length == 2
render json: MALFORMED_AUTHORIZATION_HEADER,
status: :unauthorized and return
end
scheme, token = authorization_header_elements
render json: BAD_CREDENTIALS, status: :unauthorized and return unless scheme.downcase == 'bearer'
token
end
end
```
```rb app/controllers/application_controller.rb lines highlight={} theme={null}
# frozen_string_literal: true
class ApplicationController < ActionController::API
include Secured
end
```
```rb app/lib/auth0_client.rb lines highlight={} theme={null}
```
```rb app/controllers/public_controller.rb lines highlight={} theme={null}
# frozen_string_literal: true
class PublicController < ApplicationController
def public
render json: { message: 'All good. You don\'t need to be authenticated to call this.' }
end
end
```
```rb app/controllers/private_controller.rb lines highlight={} theme={null}
# frozen_string_literal: true
class PublicController < ApplicationController
def public
render json: { message: 'All good. You don\'t need to be authenticated to call this.' }
end
end
```
```rb app/controllers/application_controller.rb lines highlight={} theme={null}
# frozen_string_literal: true
class ApplicationController < ActionController::API
include Secured
end
```
```rb app/lib/auth0_client.rb lines highlight={} theme={null}
```
```rb app/controllers/concerns/secured.rb lines highlight={} theme={null}
# frozen_string_literal: true
module Secured
extend ActiveSupport::Concern
REQUIRES_AUTHENTICATION = { message: 'Requires authentication' }.freeze
BAD_CREDENTIALS = {
message: 'Bad credentials'
}.freeze
MALFORMED_AUTHORIZATION_HEADER = {
error: 'invalid_request',
error_description: 'Authorization header value must follow this format: Bearer access-token',
message: 'Bad credentials'
}.freeze
INSUFFICIENT_PERMISSIONS = {
error: 'insufficient_permissions',
error_description: 'The access token does not contain the required permissions',
message: 'Permission denied'
}.freeze
def authorize
token = token_from_request
return if performed?
validation_response = Auth0Client.validate_token(token)
@decoded_token = validation_response.decoded_token
return unless (error = validation_response.error)
render json: { message: error.message }, status: error.status
end
def validate_permissions(permissions)
raise 'validate_permissions needs to be called with a block' unless block_given?
return yield if @decoded_token.validate_permissions(permissions)
render json: INSUFFICIENT_PERMISSIONS, status: :forbidden
end
private
def token_from_request
authorization_header_elements = request.headers['Authorization']&.split
render json: REQUIRES_AUTHENTICATION, status: :unauthorized and return unless authorization_header_elements
unless authorization_header_elements.length == 2
render json: MALFORMED_AUTHORIZATION_HEADER,
status: :unauthorized and return
end
scheme, token = authorization_header_elements
render json: BAD_CREDENTIALS, status: :unauthorized and return unless scheme.downcase == 'bearer'
token
end
end
```
```rb app/controllers/public_controller.rb lines highlight={} theme={null}
# frozen_string_literal: true
class PublicController < ApplicationController
def public
render json: { message: 'All good. You don\'t need to be authenticated to call this.' }
end
end
```
```rb app/controllers/private_controller.rb lines highlight={} theme={null}
# frozen_string_literal: true
class PublicController < ApplicationController
def public
render json: { message: 'All good. You don\'t need to be authenticated to call this.' }
end
end
```
```rb app/controllers/public_controller.rb lines highlight={} theme={null}
# frozen_string_literal: true
class PublicController < ApplicationController
def public
render json: { message: 'All good. You don\'t need to be authenticated to call this.' }
end
end
```
```rb app/controllers/application_controller.rb lines highlight={} theme={null}
# frozen_string_literal: true
class ApplicationController < ActionController::API
include Secured
end
```
```rb app/lib/auth0_client.rb lines highlight={} theme={null}
```
```rb app/controllers/concerns/secured.rb lines highlight={} theme={null}
# frozen_string_literal: true
module Secured
extend ActiveSupport::Concern
REQUIRES_AUTHENTICATION = { message: 'Requires authentication' }.freeze
BAD_CREDENTIALS = {
message: 'Bad credentials'
}.freeze
MALFORMED_AUTHORIZATION_HEADER = {
error: 'invalid_request',
error_description: 'Authorization header value must follow this format: Bearer access-token',
message: 'Bad credentials'
}.freeze
INSUFFICIENT_PERMISSIONS = {
error: 'insufficient_permissions',
error_description: 'The access token does not contain the required permissions',
message: 'Permission denied'
}.freeze
def authorize
token = token_from_request
return if performed?
validation_response = Auth0Client.validate_token(token)
@decoded_token = validation_response.decoded_token
return unless (error = validation_response.error)
render json: { message: error.message }, status: error.status
end
def validate_permissions(permissions)
raise 'validate_permissions needs to be called with a block' unless block_given?
return yield if @decoded_token.validate_permissions(permissions)
render json: INSUFFICIENT_PERMISSIONS, status: :forbidden
end
private
def token_from_request
authorization_header_elements = request.headers['Authorization']&.split
render json: REQUIRES_AUTHENTICATION, status: :unauthorized and return unless authorization_header_elements
unless authorization_header_elements.length == 2
render json: MALFORMED_AUTHORIZATION_HEADER,
status: :unauthorized and return
end
scheme, token = authorization_header_elements
render json: BAD_CREDENTIALS, status: :unauthorized and return unless scheme.downcase == 'bearer'
token
end
end
```
```rb app/controllers/private_controller.rb lines highlight={} theme={null}
# frozen_string_literal: true
class PublicController < ApplicationController
def public
render json: { message: 'All good. You don\'t need to be authenticated to call this.' }
end
end
```
```rb app/controllers/private_controller.rb lines highlight={} theme={null}
# frozen_string_literal: true
class PublicController < ApplicationController
def public
render json: { message: 'All good. You don\'t need to be authenticated to call this.' }
end
end
```
```rb app/controllers/application_controller.rb lines highlight={} theme={null}
# frozen_string_literal: true
class ApplicationController < ActionController::API
include Secured
end
```
```rb app/lib/auth0_client.rb lines highlight={} theme={null}
```
```rb app/controllers/concerns/secured.rb lines highlight={} theme={null}
# frozen_string_literal: true
module Secured
extend ActiveSupport::Concern
REQUIRES_AUTHENTICATION = { message: 'Requires authentication' }.freeze
BAD_CREDENTIALS = {
message: 'Bad credentials'
}.freeze
MALFORMED_AUTHORIZATION_HEADER = {
error: 'invalid_request',
error_description: 'Authorization header value must follow this format: Bearer access-token',
message: 'Bad credentials'
}.freeze
INSUFFICIENT_PERMISSIONS = {
error: 'insufficient_permissions',
error_description: 'The access token does not contain the required permissions',
message: 'Permission denied'
}.freeze
def authorize
token = token_from_request
return if performed?
validation_response = Auth0Client.validate_token(token)
@decoded_token = validation_response.decoded_token
return unless (error = validation_response.error)
render json: { message: error.message }, status: error.status
end
def validate_permissions(permissions)
raise 'validate_permissions needs to be called with a block' unless block_given?
return yield if @decoded_token.validate_permissions(permissions)
render json: INSUFFICIENT_PERMISSIONS, status: :forbidden
end
private
def token_from_request
authorization_header_elements = request.headers['Authorization']&.split
render json: REQUIRES_AUTHENTICATION, status: :unauthorized and return unless authorization_header_elements
unless authorization_header_elements.length == 2
render json: MALFORMED_AUTHORIZATION_HEADER,
status: :unauthorized and return
end
scheme, token = authorization_header_elements
render json: BAD_CREDENTIALS, status: :unauthorized and return unless scheme.downcase == 'bearer'
token
end
end
```
```rb app/controllers/public_controller.rb lines highlight={} theme={null}
# frozen_string_literal: true
class PublicController < ApplicationController
def public
render json: { message: 'All good. You don\'t need to be authenticated to call this.' }
end
end
```
# ASP.NET Web API (OWIN): Authorization
Source: https://auth0.com/docs/quickstart/backend/webapi-owin
Add Auth0 JWT authorization to an ASP.NET OWIN API using the standard JWT middleware with protected endpoints
**New to Auth0?** Learn [how Auth0 works](/docs/get-started/auth0-overview) and read about [implementing API authentication and authorization](/docs/get-started/authentication-and-authorization-flow) using the OAuth 2.0 framework.
## Get Started
Auth0 allows you to add authorization to any kind of application. This guide demonstrates how to integrate Auth0 with any new or existing ASP.NET OWIN Web API application using the `Microsoft.Owin.Security.Jwt` package. Each Auth0 API uses the API Identifier, which your application needs to validate the access token.
This example demonstrates:
* How to check for a JSON Web Token (JWT) in the `Authorization` header of an incoming HTTP request.
* How to check if the token is valid, using the [JSON Web Key Set (JWKS)](/docs/secure/tokens/json-web-tokens/json-web-key-sets) for your Auth0 account. To learn more about validating Access Tokens, see [Validate Access Tokens](/docs/secure/tokens/access-tokens/validate-access-tokens).
In the [APIs](https://manage.auth0.com/#/apis) section of the Auth0 dashboard, click **Create API**. Provide a name and an identifier for your API, for example, `https://quickstarts/api`. You will use the identifier as an `audience` later, when you are configuring the Access Token verification. Leave the **Signing Algorithm** as **RS256**.

By default, your API uses RS256 as the algorithm for signing tokens. Since RS256 uses a private/public keypair, it verifies the tokens against the public key for your Auth0 account. The public key is in the [JSON Web Key Set (JWKS)](/docs/secure/tokens/json-web-tokens/json-web-key-sets) format, and can be accessed [here](https://\{yourDomain}/.well-known/jwks.json).
Permissions let you define how resources can be accessed on behalf of the user with a given access token. For example, you might choose to grant read access to the `messages` resource if users have the manager access level, and a write access to that resource if they have the administrator access level.
You can define allowed permissions in the **Permissions** view of the Auth0 Dashboard's [APIs](https://manage.auth0.com/#/apis) section.

This example uses the `read:messages` scope.
The sample code has an `appsettings` section in `Web.config` which configures it to use the correct Auth0 **Domain** and **API Identifier** for your API. If you download the code from this page it will be automatically filled. If you use the example from Github, you will need to fill it yourself.
```xml web.config lines theme={null}
```
To use Auth0 Access Tokens with ASP.NET you will use the OWIN JWT Middleware which is available in the `Microsoft.Owin.Security.Jwt` NuGet package.
```bash lines theme={null}
Install-Package Microsoft.Owin.Security.Jwt
```
As the OWIN JWT middleware doesn't use Open ID Connect Discovery by default, you will need to provide a custom `IssuerSigningKeyResolver`. To do this, add the following to the `Support/OpenIdConnectSigningKeyResolver.cs` file:
Such a custom resolver was previously published as part of the `Auth0.OpenIdConnectSigningKeyResolver` package through Nuget. As [this package is not available anymore](https://github.com/auth0/auth0-aspnet-owin/blob/master/SECURITY-NOTICE.md), you will need to provide this yourself.
```cs OpenIdConnectSigningKeyResolver.cs lines theme={null}
public class OpenIdConnectSigningKeyResolver
{
private readonly OpenIdConnectConfiguration openIdConfig;
public OpenIdConnectSigningKeyResolver(string authority)
{
var cm = new ConfigurationManager($"{authority.TrimEnd('/')}/.well-known/openid-configuration", new OpenIdConnectConfigurationRetriever());
openIdConfig = AsyncHelper.RunSync(async () => await cm.GetConfigurationAsync());
}
public SecurityKey[] GetSigningKey(string kid)
{
return new[] { openIdConfig.JsonWebKeySet.GetSigningKeys().FirstOrDefault(t => t.KeyId == kid) };
}
}
```
The `OpenIdConnectSigningKeyResolver` will automatically download the JSON Web Key Set used to sign the RS256 tokens from the OpenID Connect Configuration endpoint (at `/.well-known/openid-configuration`). You can then use it subsequently to resolve the Issuer Signing Key, as will be demonstrated in the JWT registration code below.
Go to the `Configuration` method of your `Startup` class and add a call to `UseJwtBearerAuthentication` passing in the configured `JwtBearerAuthenticationOptions`.
The `JwtBearerAuthenticationOptions` needs to specify your Auth0 API Identifier in the `ValidAudience` property, and the full path to your Auth0 domain as the `ValidIssuer`. You will need to configure the `IssuerSigningKeyResolver` to use the instance of `OpenIdConnectSigningKeyResolver` to resolve the signing key:
```cs Startup.cs lines theme={null}
public void Configuration(IAppBuilder app)
{
var domain = $"https://{ConfigurationManager.AppSettings["Auth0Domain"]}/";
var apiIdentifier = ConfigurationManager.AppSettings["Auth0ApiIdentifier"];
var keyResolver = new OpenIdConnectSigningKeyResolver(domain);
app.UseJwtBearerAuthentication(
new JwtBearerAuthenticationOptions
{
AuthenticationMode = AuthenticationMode.Active,
TokenValidationParameters = new TokenValidationParameters()
{
ValidAudience = apiIdentifier,
ValidIssuer = domain,
IssuerSigningKeyResolver = (token, securityToken, kid, parameters) => keyResolver.GetSigningKey(kid)
}
});
// Configure Web API
WebApiConfig.Configure(app);
}
```
### Do not forget the trailing backslash
Please ensure that the URL specified for `ValidIssuer` contains a trailing backslash as this needs to match exactly with the issuer claim of the JWT. This is a common misconfiguration error which will cause your API calls to not be authenticated correctly.
The JWT middleware above verifies that the Access Token included in the request is valid; however, it doesn't yet include any mechanism for checking that the token has the sufficient **scope** to access the requested resources.
Create a class called `ScopeAuthorizeAttribute` which inherits from `System.Web.Http.AuthorizeAttribute`. This Authorization Attribute will check that the `scope` claim issued by your Auth0 tenant is present, and if so it will ensure that the `scope` claim contains the requested scope.
```cs ScopeAuthorizeAttribute.cs lines theme={null}
public class ScopeAuthorizeAttribute : AuthorizeAttribute
{
private readonly string scope;
public ScopeAuthorizeAttribute(string scope)
{
this.scope = scope;
}
public override void OnAuthorization(HttpActionContext actionContext)
{
base.OnAuthorization(actionContext);
// Get the Auth0 domain, in order to validate the issuer
var domain = $"https://{ConfigurationManager.AppSettings["Auth0Domain"]}/";
// Get the claim principal
ClaimsPrincipal principal = actionContext.ControllerContext.RequestContext.Principal as ClaimsPrincipal;
// Get the scope claim. Ensure that the issuer is for the correct Auth0 domain
var scopeClaim = principal?.Claims.FirstOrDefault(c => c.Type == "scope" && c.Issuer == domain);
if (scopeClaim != null)
{
// Split scopes
var scopes = scopeClaim.Value.Split(' ');
// Succeed if the scope array contains the required scope
if (scopes.Any(s => s == scope))
return;
}
HandleUnauthorizedRequest(actionContext);
}
}
```
The routes shown below are available for the following requests:
* `GET /api/public`: available for non-authenticated requests
* `GET /api/private`: available for authenticated requests containing an access token with no additional scopes
* `GET /api/private-scoped`: available for authenticated requests containing an access token with the `read:messages` scope granted
The JWT middleware integrates with the standard ASP.NET Authentication and Authorization mechanisms, so you only need to decorate your controller action with the `[Authorize]` attribute to secure an endpoint. To ensure that a scope is present in order to call a particular API endpoint, decorate the action with the `ScopeAuthorize` attribute and pass the name of the required `scope` in the `scope` parameter.
```cs ApiController.cs lines theme={null}
[RoutePrefix("api")]
public class ApiController : ApiController
{
[HttpGet]
[Route("public")]
public IHttpActionResult Public()
{
return Json(new
{
Message = "Hello from a public endpoint!"
});
}
[HttpGet]
[Route("private")]
[Authorize]
public IHttpActionResult Private()
{
return Json(new
{
Message = "Hello from a private endpoint! You need to be authenticated to see this."
});
}
[HttpGet]
[Route("private-scoped")]
[ScopeAuthorize("read:messages")]
public IHttpActionResult Scoped()
{
return Json(new
{
Message = "Hello from a private endpoint! You need to be authenticated and have a scope of read:messages to see this."
});
}
}
```
**Checkpoint**
Now that you have configured your application, run your application and verify that:
* `GET /api/public` is available for non-authenticated requests.
* `GET /api/private` is available for authenticated requests.
* `GET /api/private-scoped` is available for authenticated requests containing an access token with the `read:messages` scope.
## Additional Resources
Complete sample application for this quickstart
Configure other identity providers
Enable multifactor authentication
Learn about attack protection
Extend Auth0 with custom logic
Get help from the Auth0 community
# Add Login to Your Android Application using the Auth0.Android SDK
Source: https://auth0.com/docs/quickstart/native/android
If you use an AI coding assistant like Claude Code, Cursor, or GitHub Copilot, you can add Auth0 authentication automatically in minutes using [agent skills](https://agentskills.io/home).
**Install:**
```bash theme={null}
npx skills add auth0/agent-skills --skill auth0
```
**Then ask your AI assistant:**
```text theme={null}
Add Auth0 authentication to my Android app
```
Your AI assistant will automatically create your Auth0 application, fetch credentials, add the Auth0 Android SDK dependency, configure manifest placeholders, and implement login/logout flows. [Full agent skills documentation →](/docs/quickstart/agent-skills)
## Get Started
Create a new Android project for this quickstart.
**In Android Studio:**
1. **File** → **New** → **New Project**
2. Select **Phone and Tablet** → **Empty Activity** template
3. Configure your project:
* **Name**: `Auth0-Android-Sample`
* **Package name**: `com.auth0.samples.android`
* **Language**: **Kotlin**
* **Minimum SDK**: **API 24 (Android 7.0)**
* **Build configuration language**: **Kotlin DSL**
4. Click **Finish**
This creates a modern Android app with Kotlin and Gradle Kotlin DSL, following current Android development best practices.
Add the Auth0 Android SDK to your project using Gradle.
**Update your app-level `build.gradle.kts` file:**
```kotlin app/build.gradle.kts lines theme={null}
dependencies {
// Auth0 SDK
implementation("com.auth0.android:auth0:4.0.0")
}
```
**Add manifest placeholders in your app-level `build.gradle.kts`:**
```kotlin app/build.gradle.kts lines theme={null}
android {
defaultConfig {
// Add these manifest placeholders
manifestPlaceholders += mapOf(
"auth0Domain" to "@string/com_auth0_domain", // this will be set in the next step
"auth0Scheme" to "https"
)
}
}
```
**Add Internet permission to `AndroidManifest.xml`:**
```xml app/src/main/AndroidManifest.xml lines theme={null}
```
The Auth0 SDK automatically handles dependency resolution and includes secure token storage capabilities.
Next up, you need to create a new app on your Auth0 tenant and add the configuration to your Android project.
First, prepare your `app/src/main/res/values/strings.xml` file with placeholder values:
```xml app/src/main/res/values/strings.xml theme={null}
{yourDomain}YOUR_AUTH0_CLIENT_IDhttps
```
1. Head to the [Auth0 Dashboard](https://manage.auth0.com/dashboard/)
2. Click on **Applications** > **Applications** > **Create Application**
3. In the popup, enter a name for your app, select `Native` as the app type and click **Create**
4. Switch to the **Settings** tab on the Application Details page
5. Replace `{yourDomain}` and `YOUR_AUTH0_CLIENT_ID` in the `strings.xml` file with the **Domain** and **Client ID** values from the dashboard
Finally, on the **Settings** tab of your Application Details page, configure the following URLs:
**Allowed Callback URLs:**
```
https://{yourDomain}/android/PACKAGE_NAME/callback
```
**Allowed Logout URLs:**
```
https://{yourDomain}/android/PACKAGE_NAME/callback
```
Replace `{yourDomain}` with your actual Auth0 domain (e.g., `dev-abc123.us.auth0.com`).
**Allowed Callback URLs** are a critical security measure to ensure users are safely returned to your application after authentication. Without a matching URL, the login process will fail, and users will be blocked by an Auth0 error page instead of accessing your app.
**Allowed Logout URLs** are essential for providing a seamless user experience upon signing out. Without a matching URL, users will not be redirected back to your application after logout and will instead be left on a generic Auth0 page.
The URL scheme includes your package name (`com.auth0.samples.android`) to ensure the callback is routed to your specific app.
**Important**: Ensure the package name in your callback URLs matches your `applicationId` in `build.gradle.kts`. If authentication fails, verify these values are identical.
When using the `https` scheme (as configured above), you must set up Android App Links so that Android routes the callback URL directly to your app instead of opening it in a browser. See the **Configure Android App Links** section under [Troubleshooting & Advanced](#troubleshooting--advanced) below.
Create an Auth0 instance in your Activity to communicate with Auth0.
**In your `MainActivity.kt`:**
```kotlin MainActivity.kt lines theme={null}
import com.auth0.android.Auth0
import com.auth0.android.authentication.AuthenticationException
import com.auth0.android.callback.Callback
import com.auth0.android.provider.WebAuthProvider
import com.auth0.android.result.Credentials
class MainActivity : ComponentActivity() {
private lateinit var auth0: Auth0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Initialize Auth0
auth0 = Auth0.getInstance(
getString(R.string.com_auth0_client_id),
getString(R.string.com_auth0_domain)
)
}
}
```
The Auth0 instance is initialized with your client ID and domain from the `strings.xml` file you configured earlier. This instance will be used for all authentication operations.
**Implement Login:** Use WebAuthProvider to launch the universal login page.
Add these methods to your `MainActivity`:
```kotlin MainActivity.kt lines theme={null}
private fun login() {
WebAuthProvider.login(auth0)
.withScheme("https")
.withScope("openid profile email offline_access")
.start(this, object : Callback {
override fun onSuccess(credentials: Credentials) {
// Save the credentials
// User is authenticated
}
override fun onFailure(exception: AuthenticationException) {
// Handle error cases
}
})
}
```
```kotlin MainActivity.kt lines theme={null}
private fun login() {
lifecycleScope.launch {
try {
val credentials = WebAuthProvider.login(auth0)
.withScheme("https")
.withScope("openid profile email offline_access")
.await(this@MainActivity)
// Save the credentials
// User is authenticated
} catch (exception: AuthenticationException) {
// Handle error
}
}
}
```
**Implement Logout:** Use WebAuthProvider to clear the user's session.
```kotlin MainActivity.kt lines theme={null}
private fun logout() {
WebAuthProvider.logout(auth0)
.withScheme("https")
.start(this, object : Callback {
override fun onSuccess(result: Void?) {
// Clear saved credentials
// User is logged out
}
override fun onFailure(exception: AuthenticationException) {
// Handle error
}
})
}
```
```kotlin MainActivity.kt lines theme={null}
private fun logout() {
lifecycleScope.launch {
try {
WebAuthProvider.logout(auth0)
.withScheme("https")
.await(this@MainActivity)
// Clear saved credentials
// User is logged out
} catch (exception: AuthenticationException) {
// Handle error
}
}
}
```
The `login()` and `logout()` methods should be called when the user taps the respective buttons in your UI. The code uses `this` (referring to the Activity) as the context parameter, which is required for WebAuthProvider to launch Chrome Custom Tabs and handle the authentication flow.
Build and run your Android application.
**In Android Studio:**
```shellscript theme={null}
# Sync project with Gradle files (or use Android Studio's "Sync Now")
./gradlew clean build
# Build and install on connected device or emulator
./gradlew installDebug
# Or run directly from Android Studio
# Click the "Run" button or press Shift+F10
```
**Expected flow:**
1. App launches with "Log In" button and shield icon
2. Tap "Log In" → Chrome Custom Tab opens → Complete login
3. Returns to app automatically
4. Success!!
Android will show a browser selection dialog if multiple browsers are installed. Chrome Custom Tabs provide the best user experience for Auth0 authentication.
**Checkpoint**
You should now have a fully functional Auth0 login experience running on your Android device or emulator. The app uses Chrome Custom Tabs for secure authentication and automatically stores credentials.
***
## Troubleshooting & Advanced
### Chrome Custom Tab doesn't redirect back to app
**Solutions:**
1. Check **Allowed Callback URLs** in Auth0 Dashboard match your `applicationId` exactly
2. Verify manifest placeholders in `build.gradle.kts` are correct
3. Ensure both HTTPS and custom scheme URLs are configured
4. Clean and rebuild: **Build** → **Clean Project** → **Rebuild Project**
### App crashes: 'Auth0 domain not found'
**Fix:**
1. Check `com_auth0_domain` and `com_auth0_client_id` values are correct
2. Ensure no typos in domain format (should not include `https://`)
### Build errors with dependencies
**Fix:**
1. Update to latest Android Gradle Plugin in `build.gradle` (project level)
2. Sync project: **File** → **Sync Project with Gradle Files**
3. Clean build: `./gradlew clean build`
### Authentication cancelled by user
Handle gracefully in your error callback:
```kotlin {3,4,5,6} expandable theme={null}
override fun onFailure(exception: AuthenticationException) {
when {
exception.isAuthenticationCanceled ->
showMessage("Login was cancelled")
exception.isBrowserAppNotAvailable ->
showMessage("No browser available")
else ->
showMessage("Login failed: ${exception.getDescription()}")
}
}
```
### No compatible browser error
* Install Chrome or another modern browser on your device/emulator
* Enable Chrome Custom Tabs for better user experience
* Test on real device with Chrome installed
[Android App Links](https://developer.android.com/training/app-links) allow your app to designate itself as the default handler for Auth0 callback URLs, providing a more secure and seamless authentication experience. Without App Links, Android may show a disambiguation dialog asking the user to choose between your app and a browser.
App Links use verified `https` scheme callbacks. This is more secure than custom URL schemes, which can be subject to [client impersonation attacks](https://datatracker.ietf.org/doc/html/rfc8252#section-8.6).
### Get your signing certificate fingerprint
You need the SHA256 fingerprint of your app's signing certificate. Run the following command in your terminal:
```shellscript theme={null}
# For debug builds
keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android
# For release builds
keytool -list -v -keystore my-release-key.keystore
```
Copy the **SHA256** fingerprint value from the output.
### Configure in the Auth0 Dashboard
1. Go to [Auth0 Dashboard > Applications > Applications](https://manage.auth0.com/#/applications), and select your application
2. Scroll to the bottom of the **Settings** page and select **Show Advanced Settings**
3. Select the **Device Settings** tab
4. Under **Android**, provide:
* **App Package Name**: Your `applicationId` (e.g., `com.auth0.samples.android`)
* **SHA256 Cert Fingerprints**: The fingerprint you copied above
5. Click **Save Changes**
### Verify the configuration
Auth0 automatically generates the `assetlinks.json` file used by Android to verify your app. Test it by navigating to:
```
https://{yourDomain}/.well-known/assetlinks.json
```
You should see a JSON response containing your package name and certificate fingerprint:
```json theme={null}
[{
"relation": ["delegate_permission/common.handle_all_urls"],
"target": {
"namespace": "android_app",
"package_name": "[YOUR_PACKAGE_NAME]",
"sha256_cert_fingerprints": ["YOUR_SHA256_FINGERPRINT"]
}
}]
```
The quickstart already uses `https` as the scheme in the manifest placeholders and `WebAuthProvider` calls, which is required for App Links. No code changes are needed if you followed the steps above.
To learn more, see the [Enable Android App Links Support](/docs/get-started/applications/enable-android-app-links-support) documentation and Android's [Verify App Links](https://developer.android.com/training/app-links/verify-site-associations) guide.
If you cannot use Android App Links (for example, when targeting Android API versions below 23), you can configure a custom URL scheme instead.
Custom URL schemes are less secure than App Links because they can be subject to [client impersonation attacks](https://datatracker.ietf.org/doc/html/rfc8252#section-8.6). Use App Links whenever possible.
1. Update the `auth0Scheme` manifest placeholder in your `app/build.gradle.kts`:
```kotlin app/build.gradle.kts lines theme={null}
android {
defaultConfig {
manifestPlaceholders += mapOf(
"auth0Domain" to "@string/com_auth0_domain",
"auth0Scheme" to "myapp" // Use a unique custom scheme
)
}
}
```
2. Update the **Allowed Callback URLs** and **Allowed Logout URLs** in your [Auth0 Dashboard](https://manage.auth0.com/#/applications) application settings to use the custom scheme:
```
myapp://{yourDomain}/android/PACKAGE_NAME/callback
```
3. Pass the custom scheme when calling `WebAuthProvider`:
```kotlin MainActivity.kt lines theme={null}
WebAuthProvider.login(auth0)
.withScheme("myapp")
.withScope("openid profile email offline_access")
.start(this, callback)
```
Custom schemes [can only contain lowercase letters](https://developer.android.com/guide/topics/manifest/data-element).
### App Store Preparation
* Configure Android App Links for seamless authentication
* Test on multiple Android versions and screen sizes
* Implement proper error handling for network failures
* Add ProGuard rules for Auth0 SDK if using code obfuscation
* Follow Google Play Store policies for authentication flows
### Security Considerations
* Use `SecureCredentialsManager` for production credential storage
* Implement certificate pinning for additional API security
* Consider Android Keystore for enhanced credential protection
* Enable biometric authentication for sensitive operations
### Enhanced Credential Security
Implement biometric authentication for credential access:
```kotlin AuthenticationManager.kt expandable lines theme={null}
class AuthenticationManager(private val context: Context) {
private val credentialsManager: SecureCredentialsManager
init {
val authentication = AuthenticationAPIClient(auth0)
val storage = SharedPreferencesStorage(context)
credentialsManager = SecureCredentialsManager(context, authentication, storage)
// Enable biometric authentication
credentialsManager.requireAuthentication(
context as FragmentActivity,
REQUEST_CODE_BIOMETRIC,
"Biometric Authentication",
"Please authenticate to access your account"
)
}
companion object {
private const val REQUEST_CODE_BIOMETRIC = 321
}
}
```
### Custom Scopes and Audience
Request specific scopes and audience for your API:
```kotlin AuthenticationManager.kt expandable lines theme={null}
fun login() {
WebAuthProvider.login(auth0)
.withScheme("https")
.withScope("openid profile email offline_access read:posts")
.withAudience("https://myapi.example.com")
.withParameter("prompt", "login")
.start(context as MainActivity, loginCallback)
}
```
### Network Configuration
Handle network security and certificate pinning:
```xml app/src/main/res/xml/network_security_config.xml expandable lines theme={null}
your-auth0-domain.auth0.comAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
```
Add to `AndroidManifest.xml`:
```xml theme={null}
```
# Add Native Facebook Login to Your Android Application
Source: https://auth0.com/docs/quickstart/native/android-facebook-login
## Before You Start
Complete these prerequisites before following this quickstart:
1. **Set up Facebook Login SDK** - Install and configure the [Facebook Login SDK for Android](https://developers.facebook.com/docs/facebook-login/). Create a Facebook app at [developers.facebook.com](https://developers.facebook.com). When done, your app should have Facebook Login working.
2. **Configure Auth0 for Facebook Native** - Configure your Auth0 application to use Facebook Native Sign In. See [Add Facebook Login to Native Apps](/docs/authenticate/identity-providers/social-identity-providers/facebook-native).
## Get Started
Update the Facebook Login Button in your Activity to request the correct permissions.
Your app already supports Facebook Login, but to get a rich user profile you need to request `public_profile` and `email` permissions. You'll also add a callback to kick off the Auth0 authentication flow.
```kotlin MainActivity.kt lines theme={null}
private lateinit var fbCallbackManager: CallbackManager
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_login)
fbCallbackManager = CallbackManager.Factory.create()
val loginButton = findViewById(R.id.login_button)
// Request email and public_profile permissions
loginButton.setPermissions("email", "public_profile")
loginButton.registerCallback(fbCallbackManager,
object : FacebookCallback {
override fun onSuccess(result: LoginResult) {
val accessToken = result.accessToken
performLogin(accessToken)
}
override fun onCancel() {
// User closed the dialog. Safe to ignore
}
override fun onError(error: FacebookException) {
// Handle Facebook authentication error
}
})
}
private fun performLogin(accessToken: AccessToken) {
// Steps 2–4 will fill this in
}
```
The `email` permission is optional — the user must consent to sharing it. The email returned from Facebook will be **flagged as non-verified** on the Auth0 user profile.
Add the Auth0 Android SDK to your project and configure your application credentials.
**Add the dependency to `app/build.gradle.kts`:**
```kotlin app/build.gradle.kts lines theme={null}
dependencies {
implementation("com.auth0.android:auth0:3.+")
}
```
Sync Gradle after adding the dependency.
**Add your Auth0 credentials to `strings.xml`:**
Go to the **Applications** section of the [Auth0 Dashboard](https://manage.auth0.com/) and select the application where you enabled Facebook Native Sign In. Copy the **Domain** and **Client ID** values.
```xml app/src/main/res/values/strings.xml lines theme={null}
{yourDomain}{yourClientId}
```
**Initialize the Auth0 SDK in your Activity:**
```kotlin MainActivity.kt lines theme={null}
private val account: Auth0 by lazy {
Auth0.getInstance(
getString(R.string.com_auth0_client_id),
getString(R.string.com_auth0_domain)
)
}
private val authenticationApiClient: AuthenticationAPIClient by lazy {
AuthenticationAPIClient(account)
}
```
If your app does not use Auth0 Web Authentication, remove the unused activity from `AndroidManifest.xml` to avoid Manifest Placeholder errors:
```xml app/src/main/AndroidManifest.xml lines theme={null}
```
If you do plan to support Web Authentication, see [Authentication via Universal Login](/docs/libraries/auth0-android#authentication-via-universal-login).
After Facebook Login succeeds, fetch a **session access token** from the Facebook API. Auth0 requires this token to verify the user's identity on the backend.
Make a GET request to Facebook's `/oauth/access_token` endpoint using the `GraphRequest` class:
```kotlin MainActivity.kt lines theme={null}
private interface SimpleCallback {
fun onResult(result: T)
fun onError(cause: Throwable)
}
private fun fetchSessionToken(accessToken: AccessToken, callback: SimpleCallback) {
val request = GraphRequest()
request.graphPath = "oauth/access_token"
val bundle = Bundle()
bundle.putString("grant_type", "fb_attenuate_token")
bundle.putString("client_id", getString(R.string.facebook_app_id))
bundle.putString("fb_exchange_token", accessToken.token)
request.parameters = bundle
request.callback = GraphRequest.Callback { response ->
if (response.error != null) {
response.error?.exception?.let { callback.onError(it) }
} else {
response.jsonObject?.let { callback.onResult(it.getString("access_token")) }
}
}
request.executeAsync()
}
```
The required query parameters are:
* `grant_type`: `fb_attenuate_token`
* `fb_exchange_token`: the access token from Facebook Login
* `client_id`: your Facebook App ID (already in your app from the Facebook SDK setup)
Fetch the user's profile from Facebook. Auth0 uses this data to create or update the user's Auth0 profile.
```kotlin MainActivity.kt lines theme={null}
private fun fetchUserProfile(
accessToken: AccessToken,
callback: SimpleCallback
) {
val request = GraphRequest.newMeRequest(accessToken) { _, response ->
val error = response?.error
if (error != null) {
error.exception?.let { callback.onError(it) }
} else {
callback.onResult(response?.rawResponse.toString())
}
}
val bundle = Bundle()
bundle.putString("fields", "first_name,last_name,email")
request.parameters = bundle
request.executeAsync()
}
```
The `fields` parameter maps directly to the Facebook permissions you requested. Requesting `first_name`, `last_name`, and `email` is sufficient for Auth0 to create a complete user profile.
Use the session token and user profile from the previous steps to authenticate with Auth0 and receive Auth0 tokens.
Call `loginWithNativeSocialToken` on the `AuthenticationAPIClient`, passing the session token with the Facebook subject token type:
```kotlin MainActivity.kt lines theme={null}
private fun exchangeTokens(
sessionToken: String,
userProfile: String,
callback: SimpleCallback
) {
authenticationApiClient
.loginWithNativeSocialToken(
sessionToken,
"http://auth0.com/oauth/token-type/facebook-info-session-access-token"
)
.setScope("openid profile email offline_access")
.addParameter(name = "user_profile", value = userProfile)
.start(object : Callback {
override fun onSuccess(result: Credentials) {
callback.onResult(result)
}
override fun onFailure(error: AuthenticationException) {
callback.onError(error)
}
})
}
```
The subject token type `http://auth0.com/oauth/token-type/facebook-info-session-access-token` tells Auth0 to use the Facebook native connection for authentication.
Complete the `performLogin` method to chain all three steps: fetch session token → fetch user profile → exchange for Auth0 tokens.
```kotlin MainActivity.kt lines theme={null}
private fun performLogin(accessToken: AccessToken) {
fetchSessionToken(accessToken, object : SimpleCallback {
override fun onResult(sessionToken: String) {
fetchUserProfile(accessToken, object : SimpleCallback {
override fun onResult(userProfile: String) {
exchangeTokens(sessionToken, userProfile, object : SimpleCallback {
override fun onResult(result: Credentials) {
// Authenticated! Use result.accessToken or result.idToken
}
override fun onError(cause: Throwable) {
// Handle token exchange error
}
})
}
override fun onError(cause: Throwable) {
// Handle profile request error
}
})
}
override fun onError(cause: Throwable) {
// Handle session token request error
}
})
}
```
Keep constants (subject token type, Facebook permissions, Auth0 scopes) at the top of your class to avoid magic strings scattered throughout the code.
**Checkpoint**
You should now be able to authenticate natively with Facebook. If the Facebook app is installed on the device, authentication is handled through the app directly — no browser required.
***
## Troubleshooting & Advanced
### Token exchange fails with authentication error
**Solutions:**
1. Verify your Auth0 application has **Facebook Native Sign In** enabled in the Dashboard
2. Check that the Facebook App ID in your `strings.xml` matches the one in the Facebook Developer Console
3. Confirm the subject token type string matches exactly: `http://auth0.com/oauth/token-type/facebook-info-session-access-token`
4. Ensure the Facebook access token hasn't expired before calling `performLogin`
### Session token request returns an error
**Fix:**
* Verify `R.string.facebook_app_id` is correctly set in your `strings.xml`
* Ensure the `fb_exchange_token` is the raw token string from the Facebook `AccessToken` object
* Check that your Facebook app is not in Development Mode if testing with non-admin users
### `AuthenticationException`: "Connection not found"
**Fix:**
1. Go to Auth0 Dashboard → **Authentication** → **Social**
2. Verify **Sign in with Facebook** is enabled
3. Confirm **Facebook Native Social Login** is turned on in the connection settings
4. Check the Auth0 application is associated with the Facebook connection
### User profile fields are missing
* Confirm `public_profile` and `email` are listed in the `setPermissions` call
* The user may have declined the `email` permission — handle null email gracefully
* Verify the same fields are in the `fields` bundle in `fetchUserProfile`
### Security Best Practices
* **Disable logging in production**: Remove or gate `enableLogging = true` on the `DefaultClient` — it logs network traffic
* **Secure token storage**: Use `SecureCredentialsManager` to store Auth0 tokens in the Android Keystore
* **Refresh tokens**: Request `offline_access` scope and implement token refresh to maintain sessions
### Facebook App Configuration
* Switch your Facebook app from **Development Mode** to **Live** before releasing
* Add your app's SHA-1 key fingerprint to the Facebook Developer Console
* Review Facebook's [Data Policy](https://developers.facebook.com/policy/) requirements for apps using the Login SDK
### Google Play Store
* Follow Google Play's policies for apps that use third-party authentication
* Include Facebook Login in your app's privacy policy
***
## Next Steps
Add Google, Apple, and other social login providers
Protect against brute force and bot attacks
Customize authentication flows with serverless code
# Device Authorization Flow
Source: https://auth0.com/docs/quickstart/native/device/interactive
This tutorial demonstrates how to call your API from an input-constrained device using the Device Authorization Flow.
This tutorial demonstrates how to call your API from an input-constrained device using the Device Authorization Flow. We recommend that you log in to
follow this quickstart with examples configured for your account.
For an interactive experience, you can use the [Device Flow Playground](https://auth0.github.io/device-flow-playground/).
* Register a Native Application.
* Ensure the **OIDC Conformant** toggle is enabled. For more information, read OIDC-Conformant Authentication.
* Add **Device Code** to the Application's grant types. For more information, read Update Grant Types.
* Add **Refresh Token** to the Application’s grant types if you want to enable Refresh Tokens.
* Configure and enable at least one connection for the
application.
* Register your API with Auth0.
* Enable **Allow Offline Access** if you are using refresh tokens. For more information, read API Settings.
* Configure Device User Code Settings to define the
character set, format, and length of your randomly-generated user code.
When the user starts the device application and wants to authorize it, your application must request a device
code from the Auth0 Authentication API to associate with the user session.
To get the device code, your application must call the Authentication API Device Authorization Flow [Authorize endpoint](https://auth0.com/docs/api/authentication#-post-oauth-device-code-):
```bash cURL lines theme={null}
curl --request post \
--url 'https://{yourDomain}/oauth/device/code' \
--header 'content-type: application/x-www-form-urlencoded'
```
```csharp C# lines theme={null}
var client = new RestClient("https://{yourDomain}/oauth/device/code");
var request = new RestRequest(Method.POST);
request.AddHeader("content-type", "application/x-www-form-urlencoded");
IRestResponse response = client.Execute(request);
```
```go Go lines theme={null}
package main
import (
"fmt"
"net/http"
"io/ioutil"
)
func main() {
url := "https://{yourDomain}/oauth/device/code"
req, _ := http.NewRequest("post", url, nil)
req.Header.Add("content-type", "application/x-www-form-urlencoded")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := ioutil.ReadAll(res.Body)
fmt.Println(res)
fmt.Println(string(body))
}
```
```java Java lines theme={null}
HttpResponse response = Unirest.post("https://{yourDomain}/oauth/device/code")
.header("content-type", "application/x-www-form-urlencoded")
.asString();
```
```javascript Node.JS lines theme={null}
var axios = require("axios").default;
var options = {
method: 'post',
url: 'https://{yourDomain}/oauth/device/code',
headers: {'content-type': 'application/x-www-form-urlencoded'}
};
axios.request(options).then(function (response) {
console.log(response.data);
}).catch(function (error) {
console.error(error);
});
```
```objc Obj-C lines theme={null}
#import
NSDictionary *headers = @{ @"content-type": @"application/x-www-form-urlencoded" };
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://{yourDomain}/oauth/device/code"]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:10.0];
[request setHTTPMethod:@"post"];
[request setAllHTTPHeaderFields:headers];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
NSLog(@"%@", error);
} else {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
NSLog(@"%@", httpResponse);
}
}];
[dataTask resume];
```
```php PHP lines theme={null}
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://{yourDomain}/oauth/device/code",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "post",
CURLOPT_HTTPHEADER => [
"content-type: application/x-www-form-urlencoded"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
```
```python Python lines theme={null}
import http.client
conn = http.client.HTTPSConnection("")
headers = { 'content-type': "application/x-www-form-urlencoded" }
conn.request("post", "/{yourDomain}/oauth/device/code", headers=headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
```
```ruby Ruby lines theme={null}
require 'uri'
require 'net/http'
require 'openssl'
url = URI("https://{yourDomain}/oauth/device/code")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
request = Net::HTTP::Post.new(url)
request["content-type"] = 'application/x-www-form-urlencoded'
response = http.request(request)
puts response.read_body
```
```swift Swift lines theme={null}
import Foundation
let headers = ["content-type": "application/x-www-form-urlencoded"]
let request = NSMutableURLRequest(url: NSURL(string: "https://{yourDomain}/oauth/device/code")! as URL,
cachePolicy: .useProtocolCachePolicy,
timeoutInterval: 10.0)
request.httpMethod = "post"
request.allHTTPHeaderFields = headers
let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
if (error != nil) {
print(error)
} else {
let httpResponse = response as? HTTPURLResponse
print(httpResponse)
}
})
dataTask.resume()
```
The device application should receive an HTTP 200 response and a payload similar to this:
```json lines theme={null}
{
"device_code": "GmRh...k9eS",
"user_code": "WDJB-MJHT",
"verification_uri": "https://my-tenant.auth0.com/device",
"verification_uri_complete": "https://my-tenant.auth0.com/device?user_code=WDJB-MJHT",
"expires_in": 900,
"interval": 5
}
```
After your device application receives the `device_code` and the `user_code`, it should
instruct the user to go to the `verification_uri` and enter the `user_code`.
The `device_code` is not intended for the user directly and should not be displayed during
the interaction to avoid confusing the user.
When building a CLI, you could skip this step and immediately open the browser with
`verification_uri_complete`.
While your device application waits for the user to activate it, it should call the Authentication API [POST /oauth/token endpoint](https://auth0.com/docs/api/authentication#-post-oauth-token-) intermittently
and handle the response appropriately.
Ensure your device application waits for the length of the `interval` (in seconds) or until
it receives a successful response, whichever is longer, to avoid network latency issues.
```bash theme={null}
curl --request POST \
--url 'https://{yourDomain}/oauth/token' \
--header 'content-type: application/x-www-form-urlencoded' \
--data grant_type=urn:ietf:params:oauth:grant-type:device_code \
--data device_code=AUTH0_SCOPES \
--data 'client_id={yourClientId}'
```
The user will either scan the QR code, or else will open the activation page and enter the user code:
A confirmation page will be shown to have the user confirm that this is the right device:
The user will complete the transaction by signing in. This step may include one or more of the following
processes:
* Authenticating the user
* Redirecting the user to an Identity Provider to handle authentication
* Checking for active SSO sessions
* Obtaining user consent for the device, unless consent has been previously given
Upon successful authentication and consent, the confirmation prompt will be shown:
At this point, the user has authenticated and the device has been authorized.
After the user authorizes the device application, it receives an HTTP 200 response and the following payload:
```json lines theme={null}
{
"access_token": "eyJz93a...k4laUWw",
"refresh_token": "GEbRxBN...edjnXbL",
"id_token": "eyJ0XAi...4faeEoQ",
"token_type": "Bearer",
"expires_in": 86400
}
```
You should validate your tokens before saving them. To learn how, read Validate Access Tokens and Validate ID Tokens.
Access tokens are used to call the Authentication API [Get User Info endpoint](https://auth0.com/docs/api/authentication#get-user-info) (if your device
application requested the `openid` scope) or the API that was specified by the `audience`
parameter. If you are calling your own API, your device application must verify the access token before using it.
ID tokens contain user information that must be [decoded and extracted](/docs/secure/tokens/id-tokens#id-token-payload). The Authentication API
only returns an `id_token` if your device application requested the `openid` scope.
Refresh tokens are used to obtain a new access token or
ID token after the previous one has expired. The Authentication API only returns a `refresh_token` if
the **Allow Offline Access** setting is enabled for the API specified by the `audience` parameter,
and your device application requested the `offline_access` scope.
To call your API, your device application must pass the access token as a Bearer token in the
`Authorization` header of your HTTP request.
```bash lines theme={null}
curl --request GET \
--url https://myapi.com/api \
--header 'authorization: Bearer AUTH0_API_ACCESS_TOKEN' \
--header 'content-type: application/json'
```
To get a new access token for a user, your device application can call the Authentication API [POST /oauth/token endpoint](https://auth0.com/docs/api/authentication#-post-oauth-token-) with the
`refresh_token` parameter.
```bash lines theme={null}
curl --request POST \
--url 'https://{yourDomain}/oauth/token' \
--header 'content-type: application/x-www-form-urlencoded' \
--data grant_type=refresh_token \
--data 'client_id={yourClientId}' \
--data 'client_secret={yourClientSecret}' \
--data refresh_token=AUTH0_REFRESH_TOKEN
```
If the request was successful, your device application receives an HTTP 200 response with the following payload:
```json lines theme={null}
{
"access_token": "eyJ...MoQ",
"expires_in": 86400,
"scope": "openid offline_access",
"id_token": "eyJ...0NE",
"token_type": "Bearer"
}
```
To learn more about refresh tokens, read [Refresh Tokens](https://auth0.com/docs/secure/tokens/refresh-tokens).
Tenant logs are created for any interaction that takes
place and can be used to troubleshoot issues.
### Token responses
While you wait for the user to authorize the device, you may receive a few different HTTP 4xx responses.
#### Authorization pending
You will see this error while waiting for the user to take action. Continue polling using the suggested
`interval` retrieved in the previous step of this tutorial.
```json lines theme={null}
`HTTP 403`
{
"error": "authorization_pending",
"error_description": "..."
}
```
#### Slow down
You are polling too fast. Slow down and use the suggested interval retrieved in the previous step of this
tutorial. To avoid receiving this error due to network latency, you should start counting each interval after
receipt of the last polling request's response.
```json lines theme={null}
`HTTP 429`
{
"error": "slow_down",
"error_description": "..."
}
```
#### Expired token
The user has not authorized the device quickly enough, so the `device_code` has expired. Your
application should notify the user that the flow has expired and prompt them to reinitiate the flow.
The `expired_token` error is returned exactly once. After that, the endpoint returns the
`invalid_grant` error.
```json lines theme={null}
`HTTP 403`
{
"error": "expired_token",
"error_description": "..."
}
```
#### Access Denied
If access is denied, you receive:
```json lines theme={null}
`HTTP 403`
{
"error": "access_denied",
"error_description": "..."
}
```
This can occur for a variety of reasons, including:
* The user refused to authorize the device.
* The authorization server denied the transaction.
* A configured Action denied access.
Refer to the samples below to learn how to implement this flow in real-world applications.
* [Device
Authorization Playground](https://auth0.github.io/device-flow-playground/)
* [AppleTV (Swift)](https://github.com/pushpabrol/auth0-device-flow-appletv): Simple application that shows how Auth0 can be used with the
Device Authorization Flow from an AppleTV.
* [CLI (Node.js)](https://gist.github.com/panva/652c61e7d847e0ed99926c324fa91b36): Sample implementation of a CLI that uses the Device
Authorization Flow instead of the Authorization Code Flow. The major difference is that your CLI does not need
to host a webserver and listen on a port.
To use the Device Authorization Flow, a device application must:
* Support Server Name Indication (SNI)
* Be a Native Application
* Have the [Authentication Method](/docs/secure/application-credentials#application-authentication-methods) set to **None**
* Be [OIDC-conformant](/docs/get-started/applications/application-settings#oauth)
* Not be created through Dynamic Client Registration
In addition, the Device Authorization Flow does not allow:
* Social Connections using Auth0 developer keys unless you are using New Universal Login Experience
* Query string parameters to be accessed from a hosted login page or Actions.
## Next Steps
Excellent work! If you made it this far, you should now have login, logout, and user profile information running in your application.
This concludes our quickstart tutorial, but there is so much more to explore. To learn more about what you can do with Auth0, check out:
* [Auth0 Dashboard](https://manage.auth0.com/dashboard/us/dev-gja8kxz4ndtex3rq) - Learn how to configure and manage your Auth0 tenant and applications
* [Auth0 Marketplace](https://marketplace.auth0.com/) - Discover integrations you can enable to extend Auth0’s functionality
# Add Login to Your Flutter Application
Source: https://auth0.com/docs/quickstart/native/flutter
This guide demonstrates how to integrate Auth0 with any Flutter app using the Auth0 Flutter SDK.
If you use an AI coding assistant like Claude Code, Cursor, or GitHub Copilot, you can add Auth0 authentication automatically in minutes using [agent skills](https://agentskills.io/home).
**Install:**
```bash theme={null}
npx skills add auth0/agent-skills --skill auth0
```
**Then ask your AI assistant:**
```text theme={null}
Add Auth0 authentication to my Flutter app
```
Your AI assistant will automatically create your Auth0 application, fetch credentials, add the auth0\_flutter SDK dependency, configure the Android and iOS callback URLs, and implement Web Auth login/logout with secure credential storage. [Full agent skills documentation →](/quickstart/agent-skills)
This guide demonstrates how to integrate Auth0 with a Flutter application using the [Auth0 Flutter SDK](https://github.com/auth0/auth0-flutter). This guide covers setup for **Android**, **iOS**, and **macOS** platforms.
The Auth0 Flutter SDK also supports **Web** and **Windows** (beta). These platforms have dedicated quickstarts:
* [Flutter Web Quickstart](/docs/quickstart/spa/flutter) — for Flutter apps targeting the browser
* [Flutter Windows Quickstart](/docs/quickstart/native/flutter-windows) — for Flutter desktop apps on Windows (beta)
## Get Started
Create a new Flutter project for this quickstart.
**In your terminal:**
1. Navigate to your workspace directory
2. Run: `flutter create auth0_flutter_sample`
3. Navigate into the project: `cd auth0_flutter_sample`
4. Open in your IDE:
* **VS Code**: `code .`
* **Android Studio**: `open -a "Android Studio" .`
```shellscript theme={null}
# Create new Flutter project
flutter create auth0_flutter_sample
# Navigate into project directory
cd auth0_flutter_sample
# Open in VS Code
code .
```
This creates a modern Flutter app with the latest project structure. Run `flutter doctor` to verify your environment is set up correctly.
Add the Auth0 Flutter SDK to your project using the Flutter CLI.
```shellscript theme={null}
flutter pub add auth0_flutter
```
This will add `auth0_flutter` to your `pubspec.yaml` dependencies:
```yaml pubspec.yaml lines theme={null}
dependencies:
auth0_flutter: ^2.0.0-beta.1
```
The Auth0 Flutter SDK requires **Flutter 3.24.0+** and **Dart 3.5.0+**. Run `flutter doctor` to verify your environment meets these requirements.
Next up, you need to create a new app on your Auth0 tenant and configure the callback URLs.
1. Head to the [Auth0 Dashboard](https://manage.auth0.com/dashboard/)
2. Click on **Applications** > **Applications** > **Create Application**
3. In the popup, enter a name for your app, select `Native` as the app type and click **Create**
4. Switch to the **Settings** tab on the Application Details page
5. Note down the **Domain** and **Client ID** values - you'll need these later
On the **Settings** tab, configure the following URLs based on your target platform(s):
**Allowed Callback URLs:**
```text theme={null}
https://{yourDomain}/android/{yourPackageName}/callback
```
```text theme={null}
https://{yourDomain}/ios/{yourBundleIdentifier}/callback,
{yourBundleIdentifier}://{yourDomain}/ios/{yourBundleIdentifier}/callback
```
```text theme={null}
https://{yourDomain}/macos/{yourBundleIdentifier}/callback,
{yourBundleIdentifier}://{yourDomain}/macos/{yourBundleIdentifier}/callback
```
**Allowed Logout URLs:**
Add the same URLs from the callback configuration above to the **Allowed Logout URLs** field.
**Allowed Callback URLs** are a critical security measure to ensure users are safely returned to your application after authentication. Without a matching URL, the login process will fail.
**Allowed Logout URLs** are essential for providing a seamless user experience upon signing out. Without a matching URL, users will not be redirected back to your application after logout.
For example, if your Auth0 domain is `example.us.auth0.com` and your Android package name is `com.example.myapp`, your Android callback URL would be: `https://example.us.auth0.com/android/com.example.myapp/callback`
**Important**: Ensure the package name (Android) or bundle identifier (iOS/macOS) in your callback URLs matches your actual app identifier. If authentication fails, verify these values are identical.
Platform-specific configuration is required to enable the authentication flow. Follow the instructions for each platform you're targeting.
Open the `android/app/build.gradle` file and add the following manifest placeholders inside `android > defaultConfig`:
```groovy android/app/build.gradle lines theme={null}
android {
// ...
defaultConfig {
// Add the following line
manifestPlaceholders += [auth0Domain: "{yourDomain}", auth0Scheme: "https"]
}
// ...
}
```
Replace `{yourDomain}` with your Auth0 domain (e.g., `example.us.auth0.com`).
**https scheme**
To use `https` scheme for your callback url, set up [Android app links](https://auth0.com/docs/get-started/applications/enable-android-app-links-support) for your application.
**For Biometric Authentication (Optional):**
If you plan to use biometric authentication, update your `MainActivity.kt` to extend `FlutterFragmentActivity`:
```kotlin android/app/src/main/kotlin/.../MainActivity.kt lines theme={null}
import io.flutter.embedding.android.FlutterFragmentActivity
class MainActivity: FlutterFragmentActivity() {
}
```
To use Universal Links (HTTPS callback URLs) on iOS 17.4+, configure an Associated Domain:
1. Open your app in Xcode: `open ios/Runner.xcworkspace`
2. Select the **Runner** target and go to **Signing & Capabilities**
3. Click **+ Capability** and add **Associated Domains**
4. Add the entry: `webcredentials:{yourDomain}`
5. In the [Auth0 Dashboard](https://manage.auth0.com/#/applications), go to **Settings > Advanced Settings > Device Settings**
6. In the **iOS** section, set your **Team ID** and **App ID** (bundle identifier)
Universal Links configuration is optional. Skip this if you don't need Universal Links support - the SDK will fall back to custom URL schemes automatically.
Follow the same steps as iOS, but open `macos/Runner.xcworkspace` instead.
**Android**: Ensure the `auth0Domain` value matches your Auth0 domain exactly. If authentication fails, verify this value is identical to the domain shown in your Auth0 Dashboard.
**iOS/macOS**: Universal Links require a paid Apple Developer account and iOS 17.4+/macOS 14.4+. On older versions, the SDK automatically falls back to custom URL schemes.
[Universal Login](https://auth0.com/docs/authenticate/login/auth0-universal-login) is the easiest way to set up authentication in your application. We recommend using it for the best experience, best security, and the fullest array of features.
**Implement Login:**
Import the Auth0 Flutter SDK and create an `Auth0` instance:
```dart lib/auth_service.dart lines theme={null}
import 'package:auth0_flutter/auth0_flutter.dart';
class AuthService {
final auth0 = Auth0('{yourDomain}', '{yourClientId}');
Future login() async {
final credentials = await auth0.webAuthentication().login(useHTTPS: true);
// Access token -> credentials.accessToken
// ID token -> credentials.idToken
// User profile -> credentials.user
return credentials;
}
}
```
**Implement Logout:**
```dart lib/auth_service.dart lines theme={null}
Future logout() async {
await auth0.webAuthentication().logout(useHTTPS: true);
// User is now logged out
// Credentials have been cleared from secure storage
}
```
**iOS/macOS**: The `useHTTPS: true` parameter enables Universal Links on iOS 17.4+ and macOS 14.4+ for enhanced security.
**Android**: If you are using a custom scheme, pass this scheme to the login method so that the SDK can route to the login page and back again correctly:
```dart theme={null}
await auth0.webAuthentication(scheme: 'YOUR CUSTOM SCHEME').login();
```
The user profile is automatically retrieved when the user logs in. The `Credentials` object contains a `user` property with all the user profile information, populated by decoding the ID token.
```dart lib/profile_screen.dart lines theme={null}
void displayUserProfile(Credentials credentials) {
final user = credentials.user;
print('User ID: ${user.sub}');
print('Email: ${user.email}');
print('Name: ${user.name}');
print('Picture: ${user.pictureUrl}');
print('Nickname: ${user.nickname}');
}
```
Request the appropriate scopes during login to access specific user profile fields. The default scopes are `openid`, `profile`, `email`, and `offline_access`.
Build and run your Flutter application.
**In your terminal:**
```shellscript theme={null}
# List available devices
flutter devices
# Run on Android
flutter run -d android
# Run on iOS Simulator
flutter run -d ios
# Run on macOS
flutter run -d macos
```
**Expected flow:**
1. App launches with your login UI
2. User taps **Log In** → Browser/Custom Tab opens with Auth0 Universal Login
3. User completes authentication
4. Browser redirects back to your app
5. User is now authenticated and credentials are stored
**Checkpoint**
You should now have a fully functional Auth0 login experience in your Flutter application. The app uses secure browser-based authentication and automatically stores credentials for session persistence.
***
## Troubleshooting & Advanced Usage
### Callback URL Mismatch
**Symptom**: Error "redirect\_uri\_mismatch" or authentication fails silently.
**Solutions:**
1. Check **Allowed Callback URLs** in Auth0 Dashboard match your app configuration exactly
2. Verify the scheme (`https://` vs `http://`)
3. Ensure the package name (Android) or bundle identifier (iOS/macOS) is correct
4. Check for trailing slashes
### Android: Chrome Custom Tab Doesn't Open
**Symptom**: Nothing happens when calling `login()`.
**Fix:**
1. Verify `manifestPlaceholders` are correctly set in `build.gradle`
2. Ensure internet permission is in `AndroidManifest.xml`:
```xml theme={null}
```
3. Check that Chrome or another browser is installed on the device
### iOS: "Open in App" Alert
**Symptom**: Alert box appears asking to open in your app.
**Fix:** This is expected behavior with `ASWebAuthenticationSession`. To remove it:
* Use Universal Links (requires iOS 17.4+ and paid Apple Developer account)
* Or set `useEphemeralSession: true` (disables SSO):
```dart expandable theme={null}
await auth0.webAuthentication().login(
useHTTPS: true,
useEphemeralSession: true,
);
```
### Authentication cancelled by user
Handle gracefully in your error handling:
```dart expandable theme={null}
try {
final credentials = await auth0.webAuthentication().login(useHTTPS: true);
// Handle successful login
} on WebAuthenticationException catch (e) {
if (e.code == 'USER_CANCELLED') {
showMessage('Login was cancelled');
} else {
showMessage('Login failed: ${e.message}');
}
}
```
The Auth0 Flutter SDK includes a built-in Credentials Manager that securely stores user credentials. On mobile platforms, credentials are encrypted and stored in the platform's secure storage (Keychain on iOS/macOS, encrypted SharedPreferences on Android).
### Check for Stored Credentials
Before prompting the user to log in, check if valid credentials already exist:
```dart lib/auth_service.dart expandable lines theme={null}
Future checkAuthentication() async {
return await auth0.credentialsManager.hasValidCredentials();
}
```
### Retrieve Stored Credentials
Retrieve credentials to access tokens or user information. The Credentials Manager automatically refreshes expired tokens when possible:
```dart lib/auth_service.dart expandable lines theme={null}
Future getCredentials() async {
return await auth0.credentialsManager.credentials();
}
```
You don't need to manually store credentials after login—the SDK handles this automatically. You also don't need to manually refresh tokens; the Credentials Manager refreshes them when needed.
Handle authentication errors gracefully to provide a good user experience.
```dart lib/auth_service.dart expandable lines theme={null}
import 'package:auth0_flutter/auth0_flutter.dart';
Future login() async {
try {
final credentials = await auth0.webAuthentication().login(useHTTPS: true);
// Handle successful login
} on WebAuthenticationException catch (e) {
if (e.code == 'USER_CANCELLED') {
// User cancelled the login
print('Login cancelled by user');
} else {
// Handle other errors
print('Login error: ${e.message}');
}
}
}
Future getCredentials() async {
try {
return await auth0.credentialsManager.credentials();
} on CredentialsManagerException catch (e) {
if (e.isNoCredentialsFound) {
// No stored credentials, user needs to log in
throw Exception('Please log in first');
} else if (e.isTokenRenewFailed) {
// Refresh token expired, re-authentication required
return await auth0.webAuthentication().login(useHTTPS: true);
}
rethrow;
}
}
```
### Enhanced Credential Security with Biometrics
Implement biometric authentication for credential access on mobile:
```dart lib/secure_auth_service.dart expandable lines theme={null}
class SecureAuthService {
final auth0 = Auth0('{yourDomain}', '{yourClientId}');
Future enableBiometrics() async {
// Enable local authentication (Face ID, Touch ID, Fingerprint)
await auth0.credentialsManager.enableLocalAuthentication(
title: 'Authenticate to access your account',
cancelTitle: 'Cancel',
fallbackTitle: 'Use passcode',
);
}
Future getCredentialsWithBiometrics() async {
// This will now require biometric authentication
return await auth0.credentialsManager.credentials();
}
}
```
**Android**: Requires `MainActivity` to extend `FlutterFragmentActivity` as configured in Step 4.
**iOS/macOS**: Requires adding `NSFaceIDUsageDescription` to your `Info.plist`.
### Custom Scopes and Audience
Request specific scopes and audience for your API:
```dart lib/auth_service.dart expandable lines theme={null}
Future loginWithCustomScopes() async {
return await auth0.webAuthentication().login(
useHTTPS: true,
scopes: {'openid', 'profile', 'email', 'offline_access', 'read:posts'},
audience: 'https://myapi.example.com',
parameters: {'prompt': 'login'},
);
}
```
### Organizations (B2B/Enterprise)
Authenticate users within a specific organization:
```dart lib/auth_service.dart expandable lines theme={null}
Future loginWithOrganization(String organizationId) async {
return await auth0.webAuthentication().login(
useHTTPS: true,
organizationId: organizationId,
);
}
// Or prompt user to select an organization
Future loginWithOrganizationName(String organizationName) async {
return await auth0.webAuthentication().login(
useHTTPS: true,
organizationName: organizationName,
);
}
```
### App Store Preparation
* Configure Universal Links (iOS) and App Links (Android) for seamless authentication
* Test on multiple device sizes and OS versions
* Implement proper error handling for network failures
* Add ProGuard rules for Android if using code obfuscation
* Follow platform-specific App Store/Play Store policies
### Security Considerations
* Use the built-in Credentials Manager for production credential storage
* Enable biometric authentication for sensitive operations
* Consider certificate pinning for additional API security
* Implement proper token refresh handling
* Use `useHTTPS: true` for Universal Links on supported platforms
***
## Next Steps
Check out the [EXAMPLES.md](https://github.com/auth0/auth0-flutter/blob/main/auth0_flutter/EXAMPLES.md) file in the SDK repository for comprehensive code examples covering advanced scenarios like DPoP, biometric authentication, passwordless login and many more features.
# Add Login to Your Flutter Windows Application
Source: https://auth0.com/docs/quickstart/native/flutter-windows
This guide demonstrates how to integrate Auth0 with a Flutter Windows desktop application using the Auth0 Flutter SDK (beta).
**Prerequisites:**
* Flutter SDK 3.24.0+ and Dart 3.5.0+.
* Windows 10 or newer.
* Visual Studio 2022 with **Desktop development with C++** workload.
* Auth0 account — [sign up free](https://auth0.com/signup).
This feature is in **beta** (`auth0_flutter` 2.1.0-beta.1). The API may change before general availability.
This guide walks you through adding login, logout, and user profile display to a Flutter Windows desktop app using the `auth0_flutter` SDK with OAuth 2.0 [Authorization Code Flow + PKCE](/docs/get-started/authentication-and-authorization-flow/authorization-code-flow-with-pkce).
## Get Started
Create a new Flutter project with Windows platform support.
```shellscript theme={null}
flutter create --platforms=windows my_app
cd my_app
```
Verify Windows is available:
```shellscript theme={null}
flutter devices
```
You should see a Windows desktop device listed.
Run `flutter doctor` to verify your environment is set up correctly and Visual Studio 2022 with C++ desktop development is detected.
Add the beta version of the SDK that includes Windows support:
```shellscript theme={null}
flutter pub add auth0_flutter:2.1.0-beta.1
flutter pub add flutter_dotenv
```
Your `pubspec.yaml` should include:
The Auth0 Flutter SDK requires **Flutter 3.24.0+** and **Dart 3.5.0+**. The Windows platform additionally requires **Visual Studio 2022** with the C++ desktop development workload.
Create or configure an Auth0 application with the callback URLs required for Windows desktop authentication.
Create a **Native** application in your Auth0 Dashboard with the following settings:
| Field | Value |
| - | - |
| Allowed Callback URLs | `auth0flutter://callback` |
| Allowed Logout URLs | `auth0flutter://callback` |
Your credentials:
* **Domain:** `{yourDomain}`
* **Client ID:** `{yourClientId}`
```shellscript theme={null}
auth0 apps create \
--name "My Flutter Windows App" \
--type native \
--callbacks "auth0flutter://callback" \
--logout-urls "auth0flutter://callback"
```
1. Go to [Auth0 Dashboard](https://manage.auth0.com/) → **Applications > Applications**.
2. Select **Create Application**.
3. Name it "My Flutter Windows App" and choose **Native** as the application type.
4. Go to the **Settings** tab of your new application.
5. Set **Allowed Callback URLs** to `auth0flutter://callback`.
6. Set **Allowed Logout URLs** to `auth0flutter://callback`.
7. Scroll down and click **Save Changes**.
8. Copy the **Domain** and **Client ID** values from the top of Application Settings.
The `auth0flutter://callback` URL is a custom scheme that routes the browser callback back to your desktop application after authentication completes.
Create a `.env` file in the root of your project:
Add the `.env` file to your Flutter assets in `pubspec.yaml`:
Never commit your `.env` file to version control. Add it to `.gitignore`.
The Windows authentication flow requires callback plumbing in your app's runner. The Flutter plugin does not automatically receive protocol-scheme activations from the OS — you must add single-instance enforcement and URI forwarding.
Replace the contents of `windows/runner/main.cpp`:
This code:
* Enforces single-instance via a Windows mutex.
* Captures `auth0flutter://callback` URIs passed as command-line arguments.
* Forwards URIs from secondary launches to the running instance via a named pipe.
* Sets the `PLUGIN_STARTUP_URL` environment variable for the Auth0 plugin to read.
Register `auth0flutter` as a custom URL scheme so Windows routes callback URIs to your app.
Create a file `windows/url_scheme.reg`:
Replace `C:\path\to\your\app.exe` with the actual path to your built executable. During development this is typically:
```text theme={null}
build\windows\x64\runner\Debug\my_app.exe
```
Double-click the `.reg` file to import it into the Windows Registry.
For production distribution, register the custom URL scheme programmatically in your app's installer (MSIX, Inno Setup, etc.) rather than relying on a `.reg` file.
**Verify the scheme works:**
Open Command Prompt and run:
```shellscript theme={null}
start auth0flutter://test
```
Your app should launch (or come to the foreground if already running).
Create `lib/auth_service.dart` to handle Windows authentication:
The Auth0 Flutter Windows SDK does not currently support credential management. You must manually store credentials if you need sessions to persist across app restarts.
Create the main app UI in `lib/main.dart`:
Build and run the app:
```shellscript theme={null}
flutter run -d windows
```
**Expected flow:**
1. App launches with a **Log In** button.
2. Select **Log In**. Your system browser opens the Auth0 Universal Login page.
3. Complete authentication in the browser.
4. Browser redirects to `auth0flutter://callback` → your app comes to the foreground.
5. User's name, email, and profile picture are displayed.
Ensure the custom URL scheme is registered (Step 6) before testing. Without it, the browser callback cannot reach your application.
**Checkpoint**
You should now have a fully functional Auth0 login experience in your Flutter Windows application. The app opens the system browser for Auth0 Universal Login, receives the callback via the custom URL scheme, and displays the authenticated user's profile.
***
## Troubleshoot & Advanced Use
### Browser opens but app doesn't receive callback
**Symptom**: Auth0 login succeeds in browser but the app never receives the credentials.
**Fix:**
1. Open Registry Editor → `HKEY_CURRENT_USER\Software\Classes\auth0flutter\shell\open\command` and confirm the path to your `.exe`.
2. Test with `start auth0flutter://test` in Command Prompt — your app should launch.
3. Ensure `windows/runner/main.cpp` includes the pipe server and mutex code.
4. Check that no stale instances are running in Task Manager.
5. Rebuild completely: `flutter clean && flutter run -d windows`.
### Authentication times out after 5 minutes
**Symptom**: Login appears to hang and eventually fails.
**Fix:** The app never received the callback URI. Verify:
1. The registry entry points to the correct executable path.
2. The mutex name `auth0flutter_single_instance_mutex` is consistent in `main.cpp`.
3. No firewall or antivirus is blocking the named pipe.
4. Kill all stale instances and rebuild.
### Second app instance launches instead of forwarding URI
**Symptom**: A new window opens instead of the existing app receiving the callback.
**Fix:**
1. Kill all running instances in Task Manager.
2. Ensure the mutex name is consistent in `main.cpp`.
3. Rebuild with the following command: `flutter clean && flutter run -d windows`.
### WindowsWebAuthentication not found
**Symptom**: Compilation error referencing `windowsWebAuthentication`.
**Fix:** Ensure your `pubspec.yaml` specifies the beta version:
```yaml theme={null}
dependencies:
auth0_flutter: 2.1.0-beta.1
```
Run `flutter pub get` to update.
### Callback URL mismatch error
**Symptom**: Error "redirect\_uri\_mismatch" from Auth0.
**Fix:**
1. Verify **Allowed Callback URLs** in [Auth0 Dashboard](https://manage.auth0.com/) → Application Settings is exactly `auth0flutter://callback`.
2. Ensure the `appCustomURL` parameter in your code matches: `'auth0flutter://callback'`.
3. Check for trailing slashes or whitespace.
When Auth0 redirects directly to a custom scheme, the browser may show a prompt or leave a blank tab. For a smoother experience, use an intermediary HTTPS server:
1. Set up a server endpoint (e.g., `https://your-app.example.com/callback`) that redirects to `auth0flutter://callback?code=...&state=...`.
2. In [Auth0 Dashboard](https://manage.auth0.com/) → Application Settings, set **Allowed Callback URLs** to `https://your-app.example.com/callback`.
3. Pass both URLs to the login method:
```dart theme={null}
final result = await auth0.windowsWebAuthentication().login(
appCustomURL: 'auth0flutter://callback',
redirectUrl: 'https://your-app.example.com/callback',
);
```
The server page can display "Redirecting..." and close itself for a cleaner experience.
Request additional scopes or an API audience:
```dart theme={null}
final result = await auth0.windowsWebAuthentication().login(
appCustomURL: 'auth0flutter://callback',
scopes: {'openid', 'profile', 'email', 'read:messages'},
audience: 'https://your-api.example.com',
);
```
Configure the API in [Auth0 Dashboard](https://manage.auth0.com/) → **Applications > APIs** before using the `audience` parameter.
***
## Next Steps
* [Auth0 Flutter SDK on GitHub](https://github.com/auth0/auth0-flutter) — source code and issue tracker.
* [Auth0 Flutter SDK on pub.dev](https://pub.dev/packages/auth0_flutter) — API reference.
* [Flutter quickstart (Android, iOS, macOS, Web)](/docs/quickstart/native/flutter) — other platform guides.
* [Token Storage Best Practices](/docs/secure/security-guidance/data-security/token-storage) — secure credential management.
* [Auth0 Universal Login](/docs/authenticate/login/auth0-universal-login) — customize the login experience.
# Add Login to Your Ionic Angular with Capacitor Application
Source: https://auth0.com/docs/quickstart/native/ionic-angular
This guide demonstrates how to integrate Auth0 with an Ionic Angular & Capacitor application using the Auth0 Angular SDK.
If you use an AI coding assistant like Claude Code, Cursor, or GitHub Copilot, you can add Auth0 authentication automatically in minutes using [agent skills](https://agentskills.io/home).
First, install the Auth0 agent skills:
```bash theme={null}
npx skills add auth0/agent-skills --skill auth0
```
Then, ask your AI assistant:
```text theme={null}
Add Auth0 authentication to my Ionic Angular app
```
Your AI assistant will automatically create your Auth0 application, fetch credentials, install the Auth0 Angular SDK and Capacitor plugins, configure deep linking, and implement login/logout flows with native browser integration. Learn more about [Auth0 agent skills](/docs/quickstart/agent-skills).
## Get Started
This quickstart demonstrates how to add Auth0 authentication to an Ionic Angular application with Capacitor. You'll build a mobile-ready app with login, logout, and user profile features using the Auth0 Angular SDK and Capacitor's native browser plugins.
Create a new Ionic Angular project with Capacitor
```shellscript theme={null}
npx ionic start auth0-ionic-angular tabs --type=angular-standalone --capacitor
```
Open the project
```shellscript theme={null}
cd auth0-ionic-angular
```
Make sure you're using the `@ionic/cli` package (not the deprecated `ionic` package). If you see errors about `--npm-client` during project creation, update your CLI:
```shellscript theme={null}
npm uninstall -g ionic
npm i -g @ionic/cli
```
Install the Auth0 Angular SDK along with Capacitor's Browser and App plugins:
```shellscript theme={null}
npm install @auth0/auth0-angular @capacitor/browser @capacitor/app
```
* [`@capacitor/browser`](https://capacitorjs.com/docs/apis/browser) - opens the Auth0 login page in the device's system browser ([SFSafariViewController](https://developer.apple.com/documentation/safariservices/sfsafariviewcontroller) on iOS, [Chrome Custom Tabs](https://developer.chrome.com/docs/android/custom-tabs) on Android)
* [`@capacitor/app`](https://capacitorjs.com/docs/apis/app) - handles deep link callbacks from Auth0 after authentication
Capacitor's Browser plugin on iOS uses `SFSafariViewController`, which on iOS 11+ does not share cookies with Safari. This means [SSO](https://auth0.com/docs/sso) will not work on those devices. If you need SSO, use a compatible plugin that uses [ASWebAuthenticationSession](https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession).
Next up, you need to create a new app on your Auth0 tenant and add the environment variables to your project.
You have three options to set up your Auth0 app: use the Quick Setup tool (recommended), run a CLI command, or configure manually via the Dashboard:
Create a Native Auth0 App and copy the pre-filled environment file with the right configuration values.
After creating your app, update the **Allowed Callback URLs** and **Allowed Logout URLs** in the [Auth0 Dashboard](https://manage.auth0.com/dashboard/) **Settings** tab. Replace `YOUR_PACKAGE_ID` with the `appId` from your `capacitor.config.ts` (default: `io.ionic.starter`):
**Allowed Callback URLs** and **Allowed Logout URLs:**
```text theme={null}
YOUR_PACKAGE_ID://{yourDomain}/capacitor/YOUR_PACKAGE_ID/callback
```
Run the following command in your project's root directory to create a Native Auth0 app and generate an environment file. Update `PACKAGE_ID` if your `capacitor.config.ts` uses a different `appId`:
```shellscript Mac theme={null}
# Install Auth0 CLI (if not already installed)
brew tap auth0/auth0-cli && brew install auth0
# Set up Auth0 app and generate environment file
auth0 qs setup --app --type native --framework ionic-angular --name "My Ionic Angular App"
```
```powershell Windows theme={null}
# Install Auth0 CLI (if not already installed)
scoop bucket add auth0 https://github.com/auth0/scoop-auth0-cli.git
scoop install auth0
# Set up Auth0 app and generate environment file
auth0 qs setup --app --type native --framework ionic-angular --name "My Ionic Angular App"
```
This command will:
1. Check if you're authenticated (and prompt for login if needed)
2. Create an Auth0 Native application
3. Generate `src/environments/environment.ts` with your Auth0 domain and client ID
Before you start, create an environment file in your project
```typescript src/environments/environment.ts lines theme={null}
export const environment = {
production: false,
auth0: {
domain: 'YOUR_AUTH0_APP_DOMAIN',
clientId: 'YOUR_AUTH0_APP_CLIENT_ID'
}
};
```
1. Head to the [Auth0 Dashboard](https://manage.auth0.com/dashboard/)
2. Click on **Applications** > **Applications** > **Create Application**
3. Enter a name for your app (e.g., `Ionic Angular App`), select **Native** as the application type, and click **Create**
4. Switch to the **Settings** tab and note your **Domain** and **Client ID** values
5. Replace `YOUR_AUTH0_APP_DOMAIN` and `YOUR_AUTH0_APP_CLIENT_ID` in `src/environments/environment.ts` with your values
Throughout this quickstart, `YOUR_PACKAGE_ID` refers to the `appId` field in your `capacitor.config.ts`. The default value is `io.ionic.starter`. See [Capacitor's Config schema](https://capacitorjs.com/docs/config#schema) for more info.
Configure the following URLs on the **Settings** tab (replace `YOUR_PACKAGE_ID` with your actual package ID):
**Allowed Callback URLs:**
```text theme={null}
YOUR_PACKAGE_ID://{yourDomain}/capacitor/YOUR_PACKAGE_ID/callback
```
**Allowed Logout URLs:**
```text theme={null}
YOUR_PACKAGE_ID://{yourDomain}/capacitor/YOUR_PACKAGE_ID/callback
```
**Allowed Origins:**
```text theme={null}
capacitor://localhost, http://localhost
```
**Allowed Callback URLs** are a critical security measure to ensure users are safely returned to your application after authentication. Without a matching URL, the login process will fail.
**Allowed Logout URLs** are essential for providing a seamless user experience upon signing out. Without a matching URL, users will receive an error when logging out.
**Allowed Origins** are required for silent authentication. The `capacitor://localhost` origin is for iOS and `http://localhost` is for Android.
With your environment file in place from the previous step, configure the Auth0 module in your app:
```typescript src/main.ts {4-6,10,17-25} lines theme={null}
import { bootstrapApplication } from '@angular/platform-browser';
import { RouteReuseStrategy, provideRouter } from '@angular/router';
import { IonicRouteStrategy, provideIonicAngular } from '@ionic/angular/standalone';
import { provideAuth0 } from '@auth0/auth0-angular';
import { environment } from './environments/environment';
import config from '../capacitor.config';
import { routes } from './app/app.routes';
import { AppComponent } from './app/app.component';
const redirect_uri = `${config.appId}://${environment.auth0.domain}/capacitor/${config.appId}/callback`;
bootstrapApplication(AppComponent, {
providers: [
{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
provideIonicAngular(),
provideRouter(routes),
provideAuth0({
domain: environment.auth0.domain,
clientId: environment.auth0.clientId,
useRefreshTokens: true,
useRefreshTokensFallback: false,
authorizationParams: {
redirect_uri,
},
}),
],
});
```
The `provideAuth0` configuration includes:
* `useRefreshTokens: true` — **required** for mobile. Capacitor apps cannot use iframe-based silent authentication, so refresh tokens are used to renew sessions.
* `useRefreshTokensFallback: false` — **required** for mobile. Prevents the SDK from falling back to iframe-based silent auth, which is unavailable in native apps.
* `authorizationParams.redirect_uri` — uses your app's custom URL scheme to redirect back after authentication.
To persist authentication after closing and reopening the application, you may want to set `cacheLocation` to `localstorage`, but please be aware of [the risks of storing tokens in localstorage](https://auth0.com/docs/libraries/auth0-single-page-app-sdk#change-storage-options). Also, localstorage should be treated as **transient** in Capacitor apps. Please read the [guidance on storage in the Capacitor docs](https://capacitorjs.com/docs/guides/storage#why-cant-i-just-use-localstorage-or-indexeddb).
Create the component files
```shellscript Mac/Linux theme={null}
touch src/app/login-button.component.ts && touch src/app/logout-button.component.ts && touch src/app/profile.component.ts
```
```powershell Windows theme={null}
New-Item -ItemType File -Path src/app/login-button.component.ts
New-Item -ItemType File -Path src/app/logout-button.component.ts
New-Item -ItemType File -Path src/app/profile.component.ts
```
Add the following code to each component:
```typescript src/app/login-button.component.ts expandable lines theme={null}
import { Component, inject } from '@angular/core';
import { AuthService } from '@auth0/auth0-angular';
import { Browser } from '@capacitor/browser';
import { IonButton } from '@ionic/angular/standalone';
@Component({
selector: 'app-login-button',
standalone: true,
imports: [IonButton],
template: `Log in`,
})
export class LoginButtonComponent {
private auth = inject(AuthService);
login(): void {
this.auth
.loginWithRedirect({
async openUrl(url: string) {
await Browser.open({ url, windowName: '_self' });
},
})
.subscribe();
}
}
```
```typescript src/app/logout-button.component.ts expandable lines theme={null}
import { Component, inject } from '@angular/core';
import { AuthService } from '@auth0/auth0-angular';
import { Browser } from '@capacitor/browser';
import { IonButton } from '@ionic/angular/standalone';
import { environment } from '../environments/environment';
import config from '../../capacitor.config';
const returnTo = `${config.appId}://${environment.auth0.domain}/capacitor/${config.appId}/callback`;
@Component({
selector: 'app-logout-button',
standalone: true,
imports: [IonButton],
template: `Log out`,
})
export class LogoutButtonComponent {
private auth = inject(AuthService);
logout(): void {
this.auth
.logout({
logoutParams: { returnTo },
async openUrl(url: string) {
await Browser.open({ url });
},
})
.subscribe();
}
}
```
```typescript src/app/profile.component.ts expandable lines theme={null}
import { Component, inject } from '@angular/core';
import { CommonModule } from '@angular/common';
import { AuthService } from '@auth0/auth0-angular';
import { IonAvatar, IonItem, IonLabel } from '@ionic/angular/standalone';
@Component({
selector: 'app-profile',
standalone: true,
imports: [CommonModule, IonAvatar, IonItem, IonLabel],
template: `
@if (auth.user$ | async; as user) {
{{ user.name }}
{{ user.email }}
}
`,
})
export class ProfileComponent {
protected auth = inject(AuthService);
}
```
Now update the App Component to handle Auth0 callbacks, and the home page to use your components:
Replace the contents of `src/app/app.component.ts`:
```typescript src/app/app.component.ts expandable lines theme={null}
import { Component, OnInit, NgZone, inject } from '@angular/core';
import { AuthService } from '@auth0/auth0-angular';
import { mergeMap } from 'rxjs/operators';
import { Browser } from '@capacitor/browser';
import { App } from '@capacitor/app';
import { IonApp, IonRouterOutlet } from '@ionic/angular/standalone';
import { environment } from '../environments/environment';
import config from '../../capacitor.config';
const callbackUri = `${config.appId}://${environment.auth0.domain}/capacitor/${config.appId}/callback`;
@Component({
selector: 'app-root',
standalone: true,
imports: [IonApp, IonRouterOutlet],
template: '',
})
export class AppComponent implements OnInit {
private auth = inject(AuthService);
private ngZone = inject(NgZone);
ngOnInit(): void {
App.addListener('appUrlOpen', ({ url }) => {
this.ngZone.run(() => {
if (url?.startsWith(callbackUri)) {
if (
url.includes('state=') &&
(url.includes('error=') || url.includes('code='))
) {
this.auth
.handleRedirectCallback(url)
.pipe(mergeMap(() => Browser.close()))
.subscribe();
} else {
Browser.close();
}
}
});
});
}
}
```
Replace the contents of `src/app/tab1/tab1.page.ts`:
```typescript src/app/tab1/tab1.page.ts expandable lines theme={null}
import { Component, inject } from '@angular/core';
import { CommonModule } from '@angular/common';
import { AuthService } from '@auth0/auth0-angular';
import {
IonHeader, IonToolbar, IonTitle, IonContent,
IonCard, IonCardHeader, IonCardTitle, IonCardContent,
} from '@ionic/angular/standalone';
import { LoginButtonComponent } from '../login-button.component';
import { LogoutButtonComponent } from '../logout-button.component';
import { ProfileComponent } from '../profile.component';
@Component({
selector: 'app-tab1',
standalone: true,
imports: [
CommonModule,
IonHeader, IonToolbar, IonTitle, IonContent,
IonCard, IonCardHeader, IonCardTitle, IonCardContent,
LoginButtonComponent, LogoutButtonComponent, ProfileComponent,
],
template: `
Home
@if (auth.isAuthenticated$ | async) {
Welcome!
} @else {
Get Started
Sign in to your account to get started.
}
`,
})
export class Tab1Page {
protected auth = inject(AuthService);
}
```
The `appUrlOpen` event callback in the App Component is wrapped in `this.ngZone.run()`. This is **required** because Capacitor plugin callbacks execute outside Angular's zone, and without it Angular won't detect the auth state changes after login. See [Using Angular with Capacitor](https://capacitorjs.com/docs/guides/angular) for details.
Test in the browser first:
```shellscript theme={null}
ionic serve
```
When running in the browser with `ionic serve`, the custom URL scheme redirect won't work because browsers cannot handle custom URL schemes. For browser testing, temporarily change `redirect_uri` to `http://localhost:8100` in `src/main.ts` and add `http://localhost:8100` to your Auth0 app's **Allowed Callback URLs** and **Allowed Logout URLs** in the Dashboard. Remember to revert this change before building for native.
To run on a device or simulator, first add the native platforms:
```shellscript theme={null}
npx cap add ios
npx cap add android
```
Then build, sync, and run:
```shellscript iOS theme={null}
ionic build && npx cap sync && npx cap run ios
```
```shellscript Android theme={null}
ionic build && npx cap sync && npx cap run android
```
You must add native platforms with `npx cap add` before you can run on them. This only needs to be done once per platform. Make sure your custom URL scheme is registered (see Advanced Usage below).
**Checkpoint**
You should now have a fully functional Auth0 login page running on your [localhost](http://localhost:8100/)
***
## Advanced Usage
If you created your project with `--type=angular` (instead of `--type=angular-standalone`) or prefer using NgModules, configure the SDK with `AuthModule.forRoot`:
```typescript src/app/app.module.ts expandable lines theme={null}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { RouteReuseStrategy } from '@angular/router';
import { IonicModule, IonicRouteStrategy } from '@ionic/angular';
import { AuthModule } from '@auth0/auth0-angular';
import { environment } from '../environments/environment';
import config from '../../capacitor.config';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
const redirect_uri = `${config.appId}://${environment.auth0.domain}/capacitor/${config.appId}/callback`;
@NgModule({
declarations: [AppComponent],
imports: [
BrowserModule,
IonicModule.forRoot(),
AppRoutingModule,
AuthModule.forRoot({
domain: environment.auth0.domain,
clientId: environment.auth0.clientId,
useRefreshTokens: true,
useRefreshTokensFallback: false,
authorizationParams: {
redirect_uri,
},
}),
],
providers: [{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy }],
bootstrap: [AppComponent],
})
export class AppModule {}
```
When using NgModules, inject `AuthService` via the constructor (`constructor(public auth: AuthService)`) instead of `inject()`. Use `*ngIf="auth.user$ | async as user"` in templates instead of `@if` control flow syntax. Components should be declared in the module rather than marked as `standalone: true`.
To test authentication on a real device, register your custom URL scheme for each platform.
### iOS
Register your custom URL scheme in `ios/App/App/Info.plist`:
```xml lines theme={null}
CFBundleURLTypesCFBundleURLSchemesYOUR_PACKAGE_ID
```
Replace `YOUR_PACKAGE_ID` with your `appId` from `capacitor.config.ts`. To learn more, read [Defining a Custom URL Scheme](https://developer.apple.com/documentation/xcode/defining-a-custom-url-scheme-for-your-app).
### Android
Add an intent filter to `android/app/src/main/AndroidManifest.xml` inside the `` tag:
```xml lines theme={null}
```
Replace `YOUR_PACKAGE_ID` with your `appId` from `capacitor.config.ts`. To learn more, read [Create Deep Links to App Content](https://developer.android.com/training/app-links/deep-linking).
### Build and run on device
```shellscript theme={null}
ionic build && npx cap sync && npx cap open ios
```
Or for Android:
```shellscript theme={null}
ionic build && npx cap sync && npx cap open android
```
Use the functional guard to protect routes that require authentication:
```typescript src/app/app.routes.ts lines theme={null}
import { Routes } from '@angular/router';
import { authGuardFn } from '@auth0/auth0-angular';
export const routes: Routes = [
{
path: 'tabs',
loadComponent: () => import('./tabs/tabs.page').then((m) => m.TabsPage),
children: [
{
path: 'tab1',
loadComponent: () => import('./tab1/tab1.page').then((m) => m.Tab1Page),
},
{
path: 'tab2',
loadComponent: () => import('./tab2/tab2.page').then((m) => m.Tab2Page),
canActivate: [authGuardFn],
},
{
path: 'tab3',
loadComponent: () => import('./tab3/tab3.page').then((m) => m.Tab3Page),
canActivate: [authGuardFn],
},
{
path: '',
redirectTo: '/tabs/tab1',
pathMatch: 'full',
},
],
},
{
path: '',
redirectTo: '/tabs/tab1',
pathMatch: 'full',
},
];
```
When unauthenticated users navigate to a protected route, `authGuardFn` automatically redirects them to the Auth0 login page.
Configure the HTTP interceptor to automatically attach access tokens to API calls:
```typescript src/main.ts expandable lines theme={null}
import { bootstrapApplication } from '@angular/platform-browser';
import { RouteReuseStrategy, provideRouter } from '@angular/router';
import { IonicRouteStrategy, provideIonicAngular } from '@ionic/angular/standalone';
import { provideHttpClient, withInterceptors } from '@angular/common/http';
import { provideAuth0, authHttpInterceptorFn } from '@auth0/auth0-angular';
import { environment } from './environments/environment';
import config from '../capacitor.config';
import { routes } from './app/app.routes';
import { AppComponent } from './app/app.component';
const redirect_uri = `${config.appId}://${environment.auth0.domain}/capacitor/${config.appId}/callback`;
bootstrapApplication(AppComponent, {
providers: [
{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
provideIonicAngular(),
provideRouter(routes),
provideAuth0({
domain: environment.auth0.domain,
clientId: environment.auth0.clientId,
useRefreshTokens: true,
useRefreshTokensFallback: false,
authorizationParams: {
redirect_uri,
audience: 'YOUR_API_IDENTIFIER',
},
httpInterceptor: {
allowedList: [
'http://localhost:3001/api/*',
],
},
}),
provideHttpClient(
withInterceptors([authHttpInterceptorFn])
),
],
});
```
Then make API calls using Angular's `HttpClient` — the interceptor automatically attaches the Bearer token:
```typescript src/app/api.service.ts lines theme={null}
import { Injectable, inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Injectable({ providedIn: 'root' })
export class ApiService {
private http = inject(HttpClient);
getData() {
return this.http.get('http://localhost:3001/api/data');
}
}
```
The `httpInterceptor.allowedList` determines which API endpoints receive access tokens. Include the `audience` parameter to request an access token for your API. Replace `YOUR_API_IDENTIFIER` with the identifier from [Auth0 Dashboard > APIs](https://manage.auth0.com/dashboard/).
### Callback URL mismatch error
**Solution:** Verify the callback URL in your Auth0 Dashboard matches exactly with the URL constructed in your app. Ensure `YOUR_PACKAGE_ID` matches the `appId` field in your `capacitor.config.ts`.
### Screen does not update after login
**Solution:** Ensure the `appUrlOpen` event callback is wrapped in `this.ngZone.run()`. Without this, Angular won't detect the state changes from `handleRedirectCallback`. See [Using Angular with Capacitor](https://capacitorjs.com/docs/guides/angular).
### "PKCE not allowed" error
**Fix:**
1. Go to Auth0 Dashboard > Applications > Your Application
2. Change the **Application Type** to **Native**
3. Set **Token Endpoint Authentication Method** to `None`
4. Save changes and try again
### SSO not working on iOS
Capacitor's Browser plugin uses `SFSafariViewController`, which does not share cookies with Safari on iOS 11+. If you need SSO, use a compatible plugin that uses [ASWebAuthenticationSession](https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession).
### Login works but user stays unauthenticated after app restart
Enable `cacheLocation: 'localstorage'` in the `provideAuth0` configuration to persist tokens across app restarts. Be aware of the [security implications](https://auth0.com/docs/libraries/auth0-single-page-app-sdk#change-storage-options) and [Capacitor storage limitations](https://capacitorjs.com/docs/guides/storage#why-cant-i-just-use-localstorage-or-indexeddb).
### Observable never executes
All `AuthService` methods return cold Observables. You must call `.subscribe()` for them to execute. If `loginWithRedirect()` or `logout()` appears to do nothing, check that `.subscribe()` is chained at the end.
## Next Steps
Check out the following resources to learn more:
* [Sample Application](https://github.com/auth0-samples/auth0-ionic-samples/tree/main/angular) — A complete Ionic Angular sample app with Auth0 integration
* [Auth0 Angular SDK Documentation](https://github.com/auth0/auth0-angular) — Full SDK reference and examples
* [Auth0 Dashboard](https://manage.auth0.com/dashboard/) — Configure and manage your Auth0 tenant and applications
* [Auth0 Marketplace](https://marketplace.auth0.com/) — Discover integrations you can enable to extend Auth0's functionality
# Add Login to Your Ionic React with Capacitor Application
Source: https://auth0.com/docs/quickstart/native/ionic-react
This guide demonstrates how to integrate Auth0 with an Ionic React & Capacitor application using the Auth0 React SDK.
If you use an AI coding assistant like Claude Code, Cursor, or GitHub Copilot, you can add Auth0 authentication automatically in minutes using [agent skills](https://agentskills.io/home).
First, install the Auth0 agent skills:
```bash theme={null}
npx skills add auth0/agent-skills --skill auth0
```
Then, ask your AI assistant:
```text theme={null}
Add Auth0 authentication to my Ionic React app
```
Your AI assistant will automatically create your Auth0 application, fetch credentials, install the Auth0 React SDK and Capacitor plugins, configure deep linking, and implement login/logout flows with native browser integration. Learn more about [Auth0 agent skills](/docs/quickstart/agent-skills).
## Get Started
This quickstart demonstrates how to add Auth0 authentication to an Ionic React application with Capacitor. You'll build a mobile-ready app with login, logout, and user profile features using the Auth0 React SDK and Capacitor's native browser integration.
Create a new Ionic React app with Capacitor
```shellscript theme={null}
npx ionic start auth0-ionic-react tabs --type=react --capacitor
```
Open the project
```shellscript theme={null}
cd auth0-ionic-react
```
Make sure you're using the `@ionic/cli` package (not the deprecated `ionic` package). If you see errors about `--npm-client` during project creation, update your CLI:
```shellscript theme={null}
npm uninstall -g ionic
npm i -g @ionic/cli
```
If you already have an Ionic React app, make sure Capacitor is enabled. You can add it with `ionic integrations enable capacitor` and then `npx cap init`.
The Ionic starter template may scaffold `react@19.0.0`, which is not compatible with the Auth0 React SDK. First, ensure you have a supported React version:
```shellscript theme={null}
npm install react@^19.0.1 react-dom@^19.0.1
```
Then install the Auth0 SDK and Capacitor plugins:
```shellscript theme={null}
npm install @auth0/auth0-react @capacitor/browser @capacitor/app && npx cap sync
```
* [`@auth0/auth0-react`](https://github.com/auth0/auth0-react): Provides React hooks and components for Auth0 authentication
* [`@capacitor/browser`](https://capacitorjs.com/docs/apis/browser): Opens the login page in the device's system browser ([SFSafariViewController](https://developer.apple.com/documentation/safariservices/sfsafariviewcontroller) on iOS, [Chrome Custom Tabs](https://developer.chrome.com/docs/android/custom-tabs) on Android)
* [`@capacitor/app`](https://capacitorjs.com/docs/apis/app): Handles deep link callbacks when Auth0 redirects back to your app
Capacitor's Browser plugin on iOS uses `SFSafariViewController`, which on iOS 11+ does not share cookies with Safari on the device. This means [SSO](https://auth0.com/docs/sso) will not work on those devices. If you need SSO, use a compatible plugin that uses [ASWebAuthenticationSession](https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession).
Next up, you need to create a new app on your Auth0 tenant and add the environment variables to your project.
You have three options to set up your Auth0 app: use the Quick Setup tool (recommended), run a CLI command, or configure manually via the Dashboard.
Throughout this quickstart, `YOUR_PACKAGE_ID` is your application's package ID. This is the `appId` field in your `capacitor.config.ts` file (e.g. `io.ionic.starter`). See [Capacitor's Config schema](https://capacitorjs.com/docs/config#schema) for more info.
Create an Auth0 App and copy the pre-filled `.env` file with the right configuration values.
After creating the app, go to its **Settings** in the [Auth0 Dashboard](https://manage.auth0.com/dashboard/) and update the **Allowed Callback URLs** and **Allowed Logout URLs** to replace `YOUR_PACKAGE_ID` with your actual package ID and `YOUR_AUTH0_DOMAIN` with your Auth0 domain:
```text theme={null}
YOUR_PACKAGE_ID://YOUR_AUTH0_DOMAIN/capacitor/YOUR_PACKAGE_ID/callback
```
Also ensure the **Application Type** is set to **Native** and the **Token Endpoint Authentication Method** is set to **None**.
Run the following command in your project's root directory to create an Auth0 app and generate a `.env` file:
```shellscript Mac theme={null}
# Install Auth0 CLI (if not already installed)
brew tap auth0/auth0-cli && brew install auth0
# Set up Auth0 app and generate .env file
auth0 qs setup --app --type native --framework ionic-react --build-tool vite --name "My Ionic React App"
```
```powershell Windows theme={null}
# Install Auth0 CLI (if not already installed)
scoop bucket add auth0 https://github.com/auth0/scoop-auth0-cli.git
scoop install auth0
# Set up Auth0 app and generate .env file
auth0 qs setup --app --type native --framework ionic-react --build-tool vite --name "My Ionic React App"
```
This command will:
1. Check if you're authenticated (and prompt for login if needed)
2. Create an Auth0 Native application
3. Generate a `.env` file with `VITE_AUTH0_DOMAIN` and `VITE_AUTH0_CLIENT_ID`
Create a `.env` file with the values from the CLI output:
Before you start, create a `.env` file in your project's root directory
```shellscript .env theme={null}
VITE_AUTH0_DOMAIN=YOUR_AUTH0_APP_DOMAIN
VITE_AUTH0_CLIENT_ID=YOUR_AUTH0_APP_CLIENT_ID
```
1. Head to the [Auth0 Dashboard](https://manage.auth0.com/dashboard/)
2. Click on **Applications** > **Applications** > **Create Application**
3. In the popup, enter a name for your app, select `Native` as the app type and click **Create**
4. Switch to the **Settings** tab on the Application Details page
5. Replace `YOUR_AUTH0_APP_DOMAIN` and `YOUR_AUTH0_APP_CLIENT_ID` in the `.env` file with the **Domain** and **Client ID** values from the dashboard
6. Set the **Token Endpoint Authentication Method** to `None`
Finally, on the **Settings** tab of your Application Details page, configure the following URLs (replace `YOUR_PACKAGE_ID` with your `appId` from `capacitor.config.ts`):
**Allowed Callback URLs:**
```text theme={null}
YOUR_PACKAGE_ID://YOUR_AUTH0_DOMAIN/capacitor/YOUR_PACKAGE_ID/callback
```
**Allowed Logout URLs:**
```text theme={null}
YOUR_PACKAGE_ID://YOUR_AUTH0_DOMAIN/capacitor/YOUR_PACKAGE_ID/callback
```
**Allowed Origins:**
```text theme={null}
capacitor://localhost, http://localhost
```
**Allowed Callback URLs** are a critical security measure to ensure users are safely returned to your application after authentication. Without a matching URL, the login process will fail, and users will be blocked by an Auth0 error page instead of accessing your app.
**Allowed Logout URLs** are essential for providing a seamless user experience upon signing out. Without a matching URL, users will not be redirected back to your application after logout and will instead be left on a generic Auth0 page.
**Allowed Origins** (`capacitor://localhost` for iOS and `http://localhost` for Android) are required so your native app can communicate with the Auth0 API.
Verify your `.env` file exists: `cat .env` (Mac/Linux) or `type .env` (Windows)
Open `src/main.tsx` and wrap the `App` component with the `Auth0Provider`. The mobile-specific settings `useRefreshTokens` and `useRefreshTokensFallback` are required for Ionic apps on iOS and Android.
```javascript src/main.tsx {5,6,12,13,14,15,16,17,18,19} lines theme={null}
import React from 'react';
import { createRoot } from 'react-dom/client';
import App from './App';
import { Auth0Provider } from '@auth0/auth0-react';
// Must match the appId in your capacitor.config.ts
const appId = 'io.ionic.starter';
createRoot(document.getElementById('root')!).render(
);
```
* `useRefreshTokens`: Required for Ionic on Android and iOS. Mobile browsers block third-party cookies, so the SDK uses refresh tokens instead of iframe-based silent authentication.
* `useRefreshTokensFallback`: Must be `false` to prevent the SDK from attempting iframe-based silent auth, which is not available on mobile.
* `authorizationParams.redirect_uri`: Uses your package ID as a custom URL scheme so the OS can route the Auth0 callback back to your app.
To persist authentication after closing and reopening the application, you may want to set `cacheLocation` to `localstorage`, but be aware of [the risks of storing tokens in localstorage](https://auth0.com/docs/libraries/auth0-single-page-app-sdk#change-storage-options). On Capacitor, localstorage should be treated as **transient** — the OS may clear it unexpectedly. See [Capacitor's guidance on storage](https://capacitorjs.com/docs/guides/storage#why-cant-i-just-use-localstorage-or-indexeddb).
We recommend **against** using [Capacitor's Preferences plugin](https://capacitorjs.com/docs/apis/preferences) to store tokens, as it is backed by `UserDefaults` (iOS) and `SharedPreferences` (Android), which are not encrypted and could be synced to the cloud. The SDK supports [custom cache implementations](https://github.com/auth0/auth0-spa-js/blob/master/EXAMPLES.md#creating-a-custom-cache) if you need a more secure and persistent storage mechanism.
Create files
```shellscript Mac/Linux theme={null}
touch src/LoginButton.tsx && touch src/LogoutButton.tsx && touch src/Profile.tsx
```
```powershell Windows theme={null}
New-Item -ItemType File -Path src/LoginButton.tsx
New-Item -ItemType File -Path src/LogoutButton.tsx
New-Item -ItemType File -Path src/Profile.tsx
```
And add the following code snippets
```javascript src/LoginButton.tsx lines theme={null}
import { useAuth0 } from '@auth0/auth0-react';
import { Browser } from '@capacitor/browser';
import { IonButton } from '@ionic/react';
const LoginButton: React.FC = () => {
const { loginWithRedirect } = useAuth0();
const login = async () => {
await loginWithRedirect({
async openUrl(url) {
await Browser.open({
url,
windowName: "_self"
});
}
});
};
return Log in;
};
export default LoginButton;
```
```javascript src/LogoutButton.tsx lines theme={null}
import { useAuth0 } from '@auth0/auth0-react';
import { Browser } from '@capacitor/browser';
import { IonButton } from '@ionic/react';
const appId = 'io.ionic.starter';
const LogoutButton: React.FC = () => {
const { logout } = useAuth0();
const logoutUri = `${appId}://${import.meta.env.VITE_AUTH0_DOMAIN}/capacitor/${appId}/callback`;
const doLogout = async () => {
await logout({
logoutParams: {
returnTo: logoutUri,
},
async openUrl(url) {
await Browser.open({
url,
windowName: "_self"
});
}
});
};
return Log out;
};
export default LogoutButton;
```
```javascript src/Profile.tsx lines theme={null}
import { useAuth0 } from '@auth0/auth0-react';
import { IonAvatar, IonItem, IonLabel } from '@ionic/react';
const Profile: React.FC = () => {
const { user, isAuthenticated, isLoading } = useAuth0();
if (isLoading) {
return Loading profile...;
}
return (
isAuthenticated && user ? (
{
const target = e.target as HTMLImageElement;
target.src = `data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' viewBox='0 0 100 100'%3E%3Ccircle cx='50' cy='50' r='50' fill='%2363b3ed'/%3E%3Cpath d='M50 45c7.5 0 13.64-6.14 13.64-13.64S57.5 17.72 50 17.72s-13.64 6.14-13.64 13.64S42.5 45 50 45zm0 6.82c-9.09 0-27.28 4.56-27.28 13.64v3.41c0 1.88 1.53 3.41 3.41 3.41h47.74c1.88 0 3.41-1.53 3.41-3.41v-3.41c0-9.08-18.19-13.64-27.28-13.64z' fill='%23fff'/%3E%3C/svg%3E`;
}}
/>
)}
);
};
export default HomePage;
```
The `openUrl` callback in `LoginButton` and `LogoutButton` uses Capacitor's Browser plugin to open the Auth0 login and logout pages in the device's system browser component, rather than navigating away from the app entirely.
The `App` component listens for the `appUrlOpen` event, which fires when Auth0 redirects back to your app using the custom URL scheme. It calls `handleRedirectCallback` to exchange the authorization code for tokens, then closes the browser.
By default, the SDK's `loginWithRedirect` method uses `window.location.href` to navigate to the login page, which opens the device's default browser application. Setting `openUrl` to use `Browser.open` keeps the authentication flow within your app's context for a better user experience.
Test in the browser first
```shellscript theme={null}
ionic serve
```
When running in the browser with `ionic serve`, the custom URL scheme redirect (`io.ionic.starter://...`) won't work because browsers cannot handle custom URL schemes. For browser testing, temporarily change `redirect_uri` to `http://localhost:8100` in `src/main.tsx` and add `http://localhost:8100` to your Auth0 app's **Allowed Callback URLs** and **Allowed Logout URLs** in the Dashboard. Remember to revert this change before building for native.
To run on a device or simulator, first add the native platforms:
```shellscript theme={null}
npx cap add ios
npx cap add android
```
Then build, sync, and run:
```shellscript iOS theme={null}
ionic build && npx cap sync && npx cap run ios
```
```shellscript Android theme={null}
ionic build && npx cap sync && npx cap run android
```
You must add native platforms with `npx cap add` before you can run on them. This only needs to be done once per platform. After that, `npx cap sync` copies your built web assets and updates native plugins.
**Checkpoint**
You should now have a fully functional Auth0 login running in your Ionic app. When running on a device, tapping "Log in" opens the Auth0 Universal Login Page in the system browser, and after authenticating, you're redirected back to your app with the user's profile displayed.
***
## Advanced Usage
For Auth0 callbacks to work on devices, register your package ID as a custom URL scheme on each platform.
**iOS** — add to `ios/App/App/Info.plist`:
```xml ios/App/App/Info.plist theme={null}
CFBundleURLTypesCFBundleURLSchemesio.ionic.starter
```
**Android** — add an intent filter inside the main `` in `android/app/src/main/AndroidManifest.xml`:
```xml android/app/src/main/AndroidManifest.xml theme={null}
```
Replace `io.ionic.starter` with your actual `appId` from `capacitor.config.ts`.
To learn more, read [Defining a Custom URL Scheme](https://developer.apple.com/documentation/xcode/defining-a-custom-url-scheme-for-your-app) for iOS, or [Create Deep Links to App Content](https://developer.android.com/training/app-links/deep-linking) for Android.
Use Auth0's authentication state to protect specific routes in your Ionic application:
```jsx src/App.tsx theme={null}
import { useAuth0, withAuthenticationRequired } from '@auth0/auth0-react';
import { IonReactRouter } from '@ionic/react-router';
import { IonRouterOutlet } from '@ionic/react';
import { Route, Redirect } from 'react-router-dom';
import HomePage from './pages/Home';
import DashboardPage from './pages/Dashboard';
const ProtectedRoute = ({ component, ...args }: any) => {
const Component = withAuthenticationRequired(component, {
onRedirecting: () =>
Loading...
,
});
return } />;
};
const App: React.FC = () => {
// ... callback handler from previous step
return (
);
};
```
The `withAuthenticationRequired` HOC automatically redirects unauthenticated users to the Auth0 login page when they try to access a protected route.
Configure your Auth0Provider to include an API audience and use the `getAccessTokenSilently` method to get access tokens for your backend:
```jsx src/main.tsx theme={null}
```
Then make authenticated API calls from your components:
```jsx src/ApiCall.tsx theme={null}
import { useState } from 'react';
import { useAuth0 } from '@auth0/auth0-react';
import { IonButton, IonText } from '@ionic/react';
const ApiCall: React.FC = () => {
const { getAccessTokenSilently } = useAuth0();
const [result, setResult] = useState(null);
const callApi = async () => {
try {
const token = await getAccessTokenSilently();
const response = await fetch('https://your-api.example.com/protected', {
headers: {
Authorization: `Bearer ${token}`
}
});
const data = await response.json();
setResult(JSON.stringify(data, null, 2));
} catch (error) {
console.error('API call failed:', error);
}
};
return (
Call Protected API
{result && (
{result}
)}
);
};
export default ApiCall;
```
# Add Login to Your Ionic Vue with Capacitor Application
Source: https://auth0.com/docs/quickstart/native/ionic-vue
This guide demonstrates how to integrate Auth0 with an Ionic Vue & Capacitor application using the Auth0 Vue SDK.
If you use an AI coding assistant like Claude Code, Cursor, or GitHub Copilot, you can add Auth0 authentication automatically in minutes using [agent skills](https://agentskills.io/home).
First, install the Auth0 agent skills:
```bash theme={null}
npx skills add auth0/agent-skills --skill auth0
```
Then, ask your AI assistant:
```text theme={null}
Add Auth0 authentication to my Ionic Vue app
```
Your AI assistant will automatically create your Auth0 application, fetch credentials, install the Auth0 Vue SDK and Capacitor plugins, configure deep linking, and implement login/logout flows with native browser integration. Learn more about [Auth0 agent skills](/docs/quickstart/agent-skills).
## Get Started
This quickstart demonstrates how to add Auth0 authentication to an Ionic Vue application running on iOS and Android with Capacitor. You'll build a secure mobile app with login, logout, and user profile features using the Auth0 Vue SDK and Capacitor's native browser plugins.
Create a new Ionic Vue project with Capacitor
```shellscript theme={null}
npx ionic start auth0-ionic-vue blank --type=vue --capacitor
```
Open the project
```shellscript theme={null}
cd auth0-ionic-vue
```
Make sure you're using the `@ionic/cli` package (not the deprecated `ionic` package). If you see errors about `--npm-client` during project creation, update your CLI:
```shellscript theme={null}
npm uninstall -g ionic
npm i -g @ionic/cli
```
```shellscript theme={null}
npm install @auth0/auth0-vue @capacitor/browser @capacitor/app
```
**[`@capacitor/browser`](https://capacitorjs.com/docs/apis/browser)** opens the Auth0 Universal Login page in the device's system browser (SFSafariViewController on iOS, Chrome Custom Tabs on Android) for secure authentication.
**[`@capacitor/app`](https://capacitorjs.com/docs/apis/app)** listens for deep link events so your app can handle the OAuth callback when Auth0 redirects back after login.
Next up, you need to create a new app on your Auth0 tenant. Ionic Capacitor apps use the **Native** application type with custom URL scheme callbacks.
You have three options to set up your Auth0 app: use the Quick Setup tool (recommended), run a CLI command, or configure manually via the Dashboard:
Create an Auth0 **Native** application and get your credentials.
After creating your app, note the **Domain** and **Client ID** values for the next step.
You'll also need to configure callback and logout URLs in the Dashboard. See the URL configuration below.
Run the following commands in your project's root directory to create an Auth0 app:
```shellscript Mac theme={null}
# Install Auth0 CLI (if not already installed)
brew tap auth0/auth0-cli && brew install auth0
# Set up Auth0 app and generate .env file
auth0 qs setup --app --type native --framework ionic-vue --build-tool vite --name "My Ionic Vue App"
```
```powershell Windows theme={null}
# Install Auth0 CLI (if not already installed)
scoop bucket add auth0 https://github.com/auth0/scoop-auth0-cli.git
scoop install auth0
# Set up Auth0 app and generate .env file
auth0 qs setup --app --type native --framework ionic-vue --build-tool vite --name "My Ionic Vue App"
```
This command will:
1. Check if you're authenticated (and prompt for login if needed)
2. Create an Auth0 Native application
3. Generate a `.env` file with your Auth0 domain and client ID
1. Head to the [Auth0 Dashboard](https://manage.auth0.com/dashboard/)
2. Click on **Applications** > **Applications** > **Create Application**
3. Enter a name for your app (e.g., `Ionic Vue App`), select **Native** as the application type, and click **Create**
4. Switch to the **Settings** tab and note your **Domain** and **Client ID** values
Throughout this guide, `YOUR_PACKAGE_ID` is your application's package ID. This can be found and configured in the `appId` field in your `capacitor.config.ts` file. See [Capacitor's Config schema](https://capacitorjs.com/docs/config#schema) for more info.
Configure the following URLs on the **Settings** tab of your Application Details page:
**Allowed Callback URLs:**
```text theme={null}
YOUR_PACKAGE_ID://{yourDomain}/capacitor/YOUR_PACKAGE_ID/callback
```
**Allowed Logout URLs:**
```text theme={null}
YOUR_PACKAGE_ID://{yourDomain}/capacitor/YOUR_PACKAGE_ID/callback
```
**Allowed Origins:**
```text theme={null}
capacitor://localhost, http://localhost
```
**Allowed Callback URLs** are a critical security measure to ensure users are safely returned to your application after authentication. Without a matching URL, the login process will fail, and users will be blocked by an Auth0 error page instead of accessing your app.
**Allowed Logout URLs** are essential for providing a seamless user experience upon signing out. Without a matching URL, users will not be redirected back to your application after logout and will instead be left on a generic Auth0 page.
**Allowed Origins** must include `capacitor://localhost` (iOS) and `http://localhost` (Android) for native app requests to Auth0.
If you used **Quick Setup** or **CLI**, go to your app's **Settings** tab on the [Auth0 Dashboard](https://manage.auth0.com/#/applications) to configure the callback and logout URLs shown in the Dashboard tab above.
```typescript src/main.ts {5,6,8,9,14,15,16,17,18,19,20,21,22,23} lines theme={null}
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import { IonicVue } from '@ionic/vue'
import { createAuth0 } from '@auth0/auth0-vue'
import config from '../capacitor.config'
// Build the callback URL using your app's package ID
const redirect_uri = `${config.appId}://{yourDomain}/capacitor/${config.appId}/callback`
const app = createApp(App)
.use(IonicVue)
.use(router)
app.use(
createAuth0({
domain: '{yourDomain}',
clientId: '{yourClientId}',
useRefreshTokens: true,
useRefreshTokensFallback: false,
authorizationParams: {
redirect_uri,
},
})
)
router.isReady().then(() => {
app.mount('#app')
})
```
* **`useRefreshTokens: true`** — Mobile browsers block third-party cookies, so iframe-based silent auth doesn't work. Refresh tokens call the `/oauth/token` endpoint directly.
* **`useRefreshTokensFallback: false`** — Prevents the SDK from attempting the iframe-based fallback, which is unavailable on mobile.
* **`router.isReady().then(...)`** — Ensures Vue Router is fully initialized before the SDK processes the OAuth callback, preventing race conditions.
To persist authentication after closing and reopening the application, you may want to set `cacheLocation` to `localstorage`, but please be aware of [the risks of storing tokens in localstorage](https://auth0.com/docs/libraries/auth0-single-page-app-sdk#change-storage-options). Also, localstorage should be treated as **transient** in Capacitor apps as the data might be recovered unexpectedly. Please read the [guidance on storage in the Capacitor docs](https://capacitorjs.com/docs/guides/storage#why-cant-i-just-use-localstorage-or-indexeddb).
Create component files
```shellscript Mac/Linux theme={null}
mkdir -p src/components && touch src/components/LoginButton.vue && touch src/components/LogoutButton.vue && touch src/components/UserProfile.vue
```
```powershell Windows theme={null}
New-Item -ItemType Directory -Force -Path src/components
New-Item -ItemType File -Path src/components/LoginButton.vue
New-Item -ItemType File -Path src/components/LogoutButton.vue
New-Item -ItemType File -Path src/components/UserProfile.vue
```
Add the following code to the new components, and update the existing `App.vue` and `HomePage.vue`
```vue src/components/LoginButton.vue lines theme={null}
Log in
```
```vue src/components/LogoutButton.vue lines theme={null}
Log out
```
```vue src/components/UserProfile.vue expandable lines theme={null}
```
```vue src/App.vue expandable lines theme={null}
```
Test in the browser first:
```shellscript theme={null}
ionic serve
```
When running in the browser with `ionic serve`, the custom URL scheme redirect won't work because browsers cannot handle custom URL schemes. For browser testing, temporarily change `redirect_uri` to `http://localhost:8100` in `src/main.ts` and add `http://localhost:8100` to your Auth0 app's **Allowed Callback URLs** and **Allowed Logout URLs** in the Dashboard. Remember to revert this change before building for native.
To run on a device or simulator, first add the native platforms:
```shellscript theme={null}
npx cap add ios
npx cap add android
```
Then build, sync, and run:
```shellscript iOS theme={null}
ionic build && npx cap sync && npx cap run ios
```
```shellscript Android theme={null}
ionic build && npx cap sync && npx cap run android
```
You must add native platforms with `npx cap add` before you can run on them. This only needs to be done once per platform. Make sure you've registered the [custom URL scheme](#custom-url-scheme-setup) for your platform first.
**Checkpoint**
You should now have a fully functional Auth0 login experience in your Ionic Vue application with login, logout, and user profile information.
***
## Advanced Usage
Register your app's custom URL scheme so the OS can route the OAuth callback back to your app after authentication.
### iOS
Register your custom URL scheme in your `ios/App/App/Info.plist`:
```xml theme={null}
CFBundleURLTypesCFBundleURLSchemesYOUR_PACKAGE_ID
```
Replace `YOUR_PACKAGE_ID` with the `appId` from your `capacitor.config.ts`. To learn more, read [Defining a Custom URL Scheme](https://developer.apple.com/documentation/xcode/defining-a-custom-url-scheme-for-your-app).
### Android
Add an intent filter to your `android/app/src/main/AndroidManifest.xml` inside the main `` tag:
```xml theme={null}
```
To learn more, read [Create Deep Links to App Content](https://developer.android.com/training/app-links/deep-linking).
After modifying native project files, run `npx cap sync` to ensure your changes are applied.
Use the built-in `authGuard` from the Auth0 Vue SDK to protect routes that require authentication:
```typescript src/router/index.ts theme={null}
import { createRouter, createWebHistory } from '@ionic/vue-router'
import { authGuard } from '@auth0/auth0-vue'
import HomePage from '../views/HomePage.vue'
import ProfilePage from '../views/ProfilePage.vue'
const routes = [
{
path: '/',
name: 'Home',
component: HomePage,
},
{
path: '/profile',
name: 'Profile',
component: ProfilePage,
beforeEnter: authGuard,
},
]
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes,
})
export default router
```
The `authGuard` automatically redirects unauthenticated users to the Auth0 Universal Login page. After logging in, they are returned to the originally requested route.
Configure the `audience` parameter in your `createAuth0` configuration to request access tokens for your API:
```typescript src/main.ts theme={null}
app.use(
createAuth0({
domain: '{yourDomain}',
clientId: '{yourClientId}',
useRefreshTokens: true,
useRefreshTokensFallback: false,
authorizationParams: {
redirect_uri,
audience: 'YOUR_API_IDENTIFIER',
},
})
)
```
Then use `getAccessTokenSilently` in your components to retrieve tokens and make authenticated API calls:
```vue src/components/ApiCall.vue theme={null}
{{ loading ? 'Calling...' : 'Call Protected API' }}
{{ JSON.stringify(response, null, 2) }}
```
The `getAccessTokenSilently` method retrieves the token from the cache or automatically refreshes it using the refresh token when needed.
If you prefer the explicit `defineComponent` pattern over `
```
The `defineComponent` pattern requires explicitly registering child components and returning values from the `setup()` function. Both patterns are fully supported by the Auth0 Vue SDK.
### Callback URL mismatch error
**Solution:** Verify that the callback URL in your Auth0 Dashboard matches exactly with the URL constructed in your application. Ensure `YOUR_PACKAGE_ID` matches the `appId` field in your `capacitor.config.ts`.
### "PKCE not allowed" error
**Fix:**
1. Go to Auth0 Dashboard > Applications > Your Application
2. Change the **Application Type** to **Native**
3. Set **Token Endpoint Authentication Method** to `None`
4. Save changes and try again
### SSO not working on iOS
Capacitor's Browser plugin uses `SFSafariViewController`, which does not share cookies with Safari on iOS 11+. If you need SSO, use a compatible plugin that uses [ASWebAuthenticationSession](https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession).
### Login works but user stays unauthenticated after app restart
Enable `cacheLocation: 'localstorage'` in the `createAuth0` configuration to persist tokens across app restarts. Be aware of the [security implications](https://auth0.com/docs/libraries/auth0-single-page-app-sdk#change-storage-options). The SDK also supports [custom cache implementations](https://github.com/auth0/auth0-spa-js/blob/master/EXAMPLES.md#creating-a-custom-cache) for more secure storage.
### Browser doesn't close after login
Ensure you are calling `Browser.close()` inside the `appUrlOpen` event listener in your `App.vue` component. On Android, `Browser.close()` is a no-op, so the browser closes automatically.
### Login page opens in the device's default browser app
If the login page opens in Safari or Chrome instead of an in-app browser overlay, make sure you're passing the `openUrl` callback to `loginWithRedirect` and `logout`. Without it, the SDK defaults to `window.location.href`, which navigates the entire app away.
# Add Login to Your iOS or macOS Application using the Auth0.swift SDK
Source: https://auth0.com/docs/quickstart/native/ios-swift
If you use an AI coding assistant like Claude Code, Cursor, or GitHub Copilot, you can add Auth0 authentication automatically in minutes using [agent skills](https://agentskills.io/home).
**Install:**
```bash theme={null}
npx skills add auth0/agent-skills --skill auth0
```
**Then ask your AI assistant:**
```text theme={null}
Add Auth0 authentication to my iOS app
```
Your AI assistant will automatically create your Auth0 application, fetch credentials, add the Auth0.swift SDK dependency, configure Auth0.plist, set up callback URLs, and implement login/logout flows. [Full agent skills documentation →](/docs/quickstart/agent-skills)
## Get Started
Create a new iOS or macOS project for this quickstart.
**In Xcode:**
1. **File** → **New** → **Project** (or **⌘+Shift+N**)
2. Select either:
* **iOS** tab → **App** template
* **macOS** tab → **App** template
3. Configure your project:
* **Product Name**: `Auth0-Sample`
* **Interface**: SwiftUI
* **Language**: Swift
* **Use Core Data**: Unchecked
* **Include Tests**: Checked (recommended)
4. Choose a location and click **Create**
This creates a standard app with SwiftUI and Swift Package Manager support, perfect for Auth0 integration.
Add the Auth0 SDK to your project using your preferred package manager.
**In Xcode:**
1. **File** → **Add Package Dependencies...** (or **⌘+Shift+K**)
2. Enter the Auth0 SDK URL:
```
https://github.com/auth0/Auth0.swift
```
3. **Add Package** → Select your app target → **Add Package**
1. Create a `Podfile` in your project directory:
```ruby Podfile theme={null}
platform :ios, '14.0' # Or platform :osx, '11.0' for macOS
use_frameworks!
target 'YourApp' do
pod 'Auth0', '~> 3.0'
end
```
2. Install the dependencies:
```bash theme={null}
pod install
```
3. Open the generated `.xcworkspace` file (not `.xcodeproj`)
1. Create a `Cartfile` in your project directory:
```text Cartfile theme={null}
github "auth0/Auth0.swift" ~> 3.0
```
2. Run Carthage:
```bash theme={null}
carthage update --platform iOS --use-xcframeworks
```
For macOS, use `--platform macOS`
3. Drag the generated `Auth0.xcframework` from `Carthage/Build` into your Xcode project
4. In your target's **General** settings, add `Auth0.xcframework` to **Frameworks, Libraries, and Embedded Content**
Create a new Auth0 application and configure callback URLs.
1. Go to [Auth0 Dashboard](https://manage.auth0.com/dashboard/)
2. **Applications** > **Create Application** > Name it, select **Native** > **Create**
3. In the **Settings** tab, note your **Client ID** and **Domain**
4. Add the following URLs to **Allowed Callback URLs**:
```
https://{yourDomain}/ios/YOUR_BUNDLE_IDENTIFIER/callback,
YOUR_BUNDLE_IDENTIFIER://{yourDomain}/ios/YOUR_BUNDLE_IDENTIFIER/callback
```
```
https://{yourDomain}/macos/YOUR_BUNDLE_IDENTIFIER/callback,
YOUR_BUNDLE_IDENTIFIER://{yourDomain}/macos/YOUR_BUNDLE_IDENTIFIER/callback
```
5. Add the following URLs to **Allowed Logout URLs**:
```
https://{yourDomain}/ios/YOUR_BUNDLE_IDENTIFIER/callback,
YOUR_BUNDLE_IDENTIFIER://{yourDomain}/ios/YOUR_BUNDLE_IDENTIFIER/callback
```
```
https://{yourDomain}/macos/YOUR_BUNDLE_IDENTIFIER/callback,
YOUR_BUNDLE_IDENTIFIER://{yourDomain}/macos/YOUR_BUNDLE_IDENTIFIER/callback
```
6. Click **Save Changes**
Create `Auth0.plist` in your project directory:
```xml Auth0.plist theme={null}
ClientIdYOUR_AUTH0_CLIENT_IDDomain{yourDomain}
```
Never hardcode `clientId` or `domain` values directly in Swift source files — they will be committed to version control. Read them from environment variables or a build-time configuration file at runtime. For most apps, prefer `Auth0.plist` (the default approach in this quickstart).
Drag `Auth0.plist` into Xcode and ensure "Add to target" is checked.
Create `AuthenticationService.swift` to handle login, logout, and token storage.
**Use `CredentialsManager` for token storage.** The `CredentialsManager` class securely stores credentials in the Keychain and automatically refreshes expired access tokens. Always use it — do not store tokens in memory, `UserDefaults`, or `localStorage`.
1. Right-click your project → **New File...** → **Swift File**
2. Name it `AuthenticationService`
3. Replace contents with:
```swift AuthenticationService.swift expandable lines theme={null}
import Foundation
import Auth0
import Combine
@MainActor
class AuthenticationService: ObservableObject {
@Published var isAuthenticated = false
@Published var user: UserProfile?
@Published var isLoading = false
@Published var errorMessage: String?
private let credentialsManager = CredentialsManager(authentication: Auth0.authentication())
init() {
Task {
await checkAuthenticationStatus()
}
}
private func checkAuthenticationStatus() async {
isLoading = true
defer { isLoading = false }
guard let credentials = try? await credentialsManager.credentials() else {
isAuthenticated = false
return
}
isAuthenticated = true
// Get the user profile from the stored ID token
user = try? credentialsManager.userProfile()
}
func login() async {
isLoading = true
errorMessage = nil
defer { isLoading = false }
do {
// offline_access is included in the default scope as of v3, shown here for clarity
_ = try await Auth0
.webAuth()
.scope("openid profile email offline_access")
.useCredentialsManager(credentialsManager)
.start()
isAuthenticated = true
// Get the user profile from the stored ID token
user = try? credentialsManager.userProfile()
} catch {
errorMessage = "Login failed: \(error.localizedDescription)"
}
}
func logout() async {
isLoading = true
defer { isLoading = false }
do {
try await Auth0
.webAuth()
.useCredentialsManager(credentialsManager)
.logout()
isAuthenticated = false
user = nil
} catch {
errorMessage = "Logout failed: \(error.localizedDescription)"
}
}
}
```
To improve the user experience, you can minimize system alerts in the following ways:
1. Use Universal Links: This eliminates the 'Open in "AppName"?' prompt that appears during the redirect. Note: The ASWebAuthenticationSession permission alert will still appear.
2. Use Ephemeral Sessions: This eliminates all permission alerts. Note: This disables Single Sign-On (SSO) and shared cookies.
**Skip this step** to use the default behavior with a permission alert. You can configure this later.
1. Auth0 Dashboard → **Applications** → Your app → **Settings** → **Advanced Settings** → **Device Settings**
2. Add **Apple Team ID** and **bundle identifier** → **Save**
3. Xcode: Target → **Signing & Capabilities** → **+ Capability** → **Associated Domains**
4. Add: `webcredentials:{yourDomain}`
Requires: Paid Apple Developer account, iOS 17.4+/macOS 14.4+
Best for production apps.
Add `.useEphemeralSession()` to the login call in `AuthenticationService.swift`:
```swift theme={null}
// In the login() function
let credentials = try await Auth0
.webAuth()
.scope("openid profile email offline_access")
.useCredentialsManager(credentialsManager)
.useEphemeralSession()
.start()
```
When using ephemeral sessions, you don't need to call `logout()` on the Web Auth client. Just clear the credentials from your app - there's no shared cookie to remove.
Quick setup, no alerts, but users must log in every time (no SSO).
Press **⌘+R** in Xcode.
1. Tap "Log In" → Permission alert (if using default) → Tap "Continue"
2. Complete login in browser
3. See your profile!
**Checkpoint**
You now have a fully functional Auth0 login in your iOS or macOS app!
***
## Troubleshooting & Advanced
### Build errors: 'Auth0' module not found
**Solutions**:
1. **Swift Package Manager**: Check **Package Dependencies** → Verify `Auth0.swift` is listed
2. **CocoaPods**: Ensure you're opening the `.xcworkspace` file, not `.xcodeproj`
3. **Carthage**: Verify `Auth0.xcframework` is added to **Frameworks, Libraries, and Embedded Content**
4. Clean and rebuild: **⌘+Shift+K** then **⌘+R**
5. Restart Xcode if needed
### App crashes: 'Auth0.plist not found'
**Fix**:
1. Verify `Auth0.plist` is in your Xcode project navigator
2. Select the file → Inspector → Ensure your app target is checked
3. Confirm it has `ClientId` and `Domain` keys with your values
### Browser opens but never returns to app
**Fix**:
1. Check callback URLs in Auth0 Dashboard match your bundle identifier and platform exactly
2. For iOS: URLs should contain `/ios/`, for macOS: `/macos/`
3. Verify bundle identifier in Xcode matches Auth0 settings
4. Ensure no typos in URLs (common: missing colons, wrong domain format)
5. **Custom domain users**: Verify you're using your custom domain, not the Auth0 domain
### Permission alert appears every time
This is standard iOS/macOS security behavior when using custom URL schemes. See **Step 6** to eliminate this alert using Universal Links or Ephemeral Sessions.
If you're using a [custom domain](/docs/customize/custom-domains), use its value instead of your Auth0 domain everywhere.
**Example:** Use `login.example.com` instead of `tenant.auth0.com`
This is **required** for certain features to work properly:
* Update `Auth0.plist` with your custom domain
* Use custom domain in callback/logout URLs
* For Universal Links, use: `webcredentials:login.example.com`
### App Store Preparation
* Configure Universal Links to eliminate the permission alert
* Test on multiple platform versions and device sizes
* Implement proper error handling for network failures
* Add Privacy Usage descriptions if using Keychain with biometrics
* Follow App Store Review Guidelines for authentication flows
### Security Best Practices
* Never log sensitive authentication data in production
* Implement App Transport Security (ATS) compliance
* Use HTTPS for all network requests
* **Do NOT** pin Auth0 API certificates - [Auth0 does not recommend this practice](/docs/troubleshoot/product-lifecycle/past-migrations#avoid-pinning-or-fingerprinting-tls-certificates-for-auth0-endpoints)
### Performance Optimization
* All async operations properly use `@MainActor` for UI updates
* `@Published` properties use proper memory handling
* Credentials are cached securely in the Keychain for offline access
* User profile is retrieved from ID token (no additional network request)
### Enhanced Keychain Security with Biometrics
Require Face ID or Touch ID to access stored credentials:
```swift theme={null}
private let credentialsManager: CredentialsManager = {
var manager = CredentialsManager(authentication: Auth0.authentication())
manager.enableBiometrics(
withTitle: "Unlock with Face ID",
cancelTitle: "Cancel",
fallbackTitle: "Use Passcode"
)
return manager
}()
```
When enabled, users must authenticate with biometrics before the SDK can retrieve stored credentials.
### Automatic Token Refresh
The `CredentialsManager` automatically refreshes expired access tokens:
```swift theme={null}
// Get credentials - automatically refreshes if expired
func getAccessToken() async throws -> String {
let credentials = try await credentialsManager.credentials()
return credentials.accessToken
}
```
Use this pattern when making API calls that require an access token.
### Shared Credentials Across App Extensions
For widgets, app extensions, or background tasks that need access tokens:
```swift theme={null}
// Create a shared credentials manager with an app group
let credentialsManager = CredentialsManager(
authentication: Auth0.authentication(),
storeKey: "credentials",
storage: SimpleKeychain(accessGroup: "group.com.example.myapp")
)
```
**Requirements:**
1. Enable **App Groups** capability in Xcode for all targets
2. Use the same app group identifier across targets
3. Configure the shared `CredentialsManager` in each target
### Authentication Flow Options Comparison
| Feature | Universal Links | Ephemeral Session | Default (Alert) |
| - | - | - | - |
| Permission Alert | Reduced (no redirect prompt) | None | Shows all alerts |
| SSO Support | Yes | No | Yes |
| Apple Developer Account | Required | Not required | Not required |
| User Experience | Best | Good | Acceptable |
| Setup Complexity | Medium | Easy | Easy |
| Private Browsing Support | Yes | Yes | No |
**Recommendations:**
* **Production apps with SSO**: Universal Links (better UX, SSO support, requires Apple Developer account)
* **Production apps without SSO**: Ephemeral Sessions (no alerts, simpler setup)
* **Testing/Development**: Ephemeral Sessions (quick setup, cleanest UX)
* **Quick start/Prototyping**: Default with alerts (no setup, can migrate later)
# Add Native Facebook Login to Your iOS Application
Source: https://auth0.com/docs/quickstart/native/ios-swift-facebook-login
## Before You Start
Complete these prerequisites before following this quickstart:
1. **Set up Facebook Login SDK** - Install and configure the [Facebook Login SDK for iOS](https://developers.facebook.com/docs/facebook-login/). Create a Facebook app at [developers.facebook.com](https://developers.facebook.com). When done, your app should have Facebook Login working.
2. **Configure Auth0 for Facebook Native** - Configure your Auth0 application to use Facebook Native Sign In. See [Add Facebook Login to Native Apps](/docs/authenticate/identity-providers/social-identity-providers/facebook-native).
## Get Started
Update the Facebook Login Button in your `ViewController` to request the correct permissions.
Your app already supports Facebook Login, but to get a rich user profile you need to request `public_profile` and `email` permissions. You'll also add a delegate callback to kick off the Auth0 authentication flow.
```swift ViewController.swift lines theme={null}
import FacebookLogin
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let fbLoginButton = FBLoginButton()
// Request email and public_profile permissions
fbLoginButton.permissions = ["email", "public_profile"]
fbLoginButton.delegate = self
view.addSubview(fbLoginButton)
}
private func performLogin(accessToken: AccessToken) {
// Steps 2–4 will fill this in
}
}
extension ViewController: LoginButtonDelegate {
func loginButton(_ loginButton: FBLoginButton, didCompleteWith result: LoginManagerLoginResult?, error: (any Error)?) {
if let error = error {
// Handle Facebook login error
print(error)
return
}
if let result = result, let token = result.token {
performLogin(accessToken: token)
}
}
func loginButtonDidLogOut(_ loginButton: FBLoginButton) {
// Handle logout
}
func loginButtonWillLogin(_ loginButton: FBLoginButton) -> Bool {
return true
}
}
```
The `email` permission is optional — the user must consent to sharing it. The email returned from Facebook will be **flagged as non-verified** on the Auth0 user profile.
Add the Auth0.swift SDK to your project and configure your application credentials.
**Add Auth0.swift via Swift Package Manager:**
1. In Xcode, go to **File** → **Add Package Dependencies...**
2. Enter the package URL: `https://github.com/auth0/Auth0.swift`
3. Select the latest version and click **Add Package**
**Add your Auth0 credentials to `Auth0.plist`:**
Go to the **Applications** section of the [Auth0 Dashboard](https://manage.auth0.com/) and select the application where you enabled Facebook Native Sign In. Copy the **Domain** and **Client ID** values.
Create a new property list file named `Auth0.plist` in your project and add the following:
```xml Auth0.plist lines theme={null}
ClientIdYOUR_AUTH0_CLIENT_IDDomain{yourDomain}
```
Drag `Auth0.plist` into Xcode and ensure **Add to target** is checked for your app target.
The Auth0.swift SDK automatically reads credentials from `Auth0.plist`, so no additional initialization code is required.
After Facebook Login succeeds, fetch a **session access token** from the Facebook API. Auth0 requires this token to verify the user's identity on the backend.
Make a GET request to Facebook's `/oauth/access_token` endpoint using the `GraphRequest` class:
```swift ViewController.swift lines theme={null}
import FacebookCore
private func fetchSessionToken(accessToken: AccessToken, completion: @escaping (String?, Error?) -> Void) {
let request = GraphRequest(graphPath: "oauth/access_token")
request.parameters["grant_type"] = "fb_attenuate_token"
request.parameters["client_id"] = facebookAppId()
request.parameters["fb_exchange_token"] = accessToken.tokenString
request.start { _, response, error in
if let error = error {
completion(nil, error)
return
}
if let responseDict = response as? [String: Any],
let token = responseDict["access_token"] as? String {
completion(token, nil)
}
}
}
private func facebookAppId() -> String? {
return Bundle.main.infoDictionary?["FacebookAppID"] as? String
}
```
The required query parameters are:
* `grant_type`: `fb_attenuate_token`
* `fb_exchange_token`: the token string from the Facebook `AccessToken`
* `client_id`: your Facebook App ID (already in your `Info.plist` from the Facebook SDK setup)
Fetch the user's profile from Facebook. Auth0 uses this data to create or update the user's Auth0 profile.
```swift ViewController.swift lines theme={null}
import FacebookCore
private func fetchUserProfile(completion: @escaping ([String: Any]?, Error?) -> Void) {
let request = GraphRequest(graphPath: "me")
request.parameters["fields"] = "first_name,last_name,email"
request.start { _, result, error in
if let error = error {
completion(nil, error)
return
}
if let rawResponse = result as? [String: Any] {
completion(rawResponse, nil)
}
}
}
```
The `fields` parameter maps directly to the Facebook permissions you requested. Requesting `first_name`, `last_name`, and `email` is sufficient for Auth0 to create a complete user profile.
Use the session token and user profile from the previous steps to authenticate with Auth0 and receive Auth0 tokens.
Call `login(facebookSessionAccessToken:profile:audience:scope:)` on the Auth0 authentication client:
```swift ViewController.swift lines theme={null}
import Auth0
private func exchangeToken(sessionToken: String, userProfile: [String: Any], completion: @escaping (Credentials?, Error?) -> Void) {
Auth0.authentication()
.login(
facebookSessionAccessToken: sessionToken,
profile: userProfile,
audience: nil,
scope: "openid profile email offline_access"
)
.start { result in
switch result {
case .success(let credentials):
completion(credentials, nil)
case .failure(let error):
completion(nil, error)
}
}
}
```
Internally, Auth0.swift uses the token type `http://auth0.com/oauth/token-type/facebook-info-session-access-token` to route the request to the Facebook native connection.
Complete the `performLogin` method to chain all three steps: fetch session token → fetch user profile → exchange for Auth0 tokens.
```swift ViewController.swift lines theme={null}
private func performLogin(accessToken: AccessToken) {
fetchSessionToken(accessToken: accessToken) { [weak self] token, error in
guard let self = self else { return }
if let error = error {
print("Session token error:", error)
return
}
guard let token = token else { return }
self.fetchUserProfile { userProfile, error in
if let error = error {
print("Profile fetch error:", error)
return
}
guard let userProfile = userProfile else { return }
self.exchangeToken(sessionToken: token, userProfile: userProfile) { credentials, error in
if let error = error {
print("Token exchange error:", error)
return
}
if let credentials = credentials {
// Authenticated! Store credentials and update UI
print("Access token:", credentials.accessToken)
}
}
}
}
}
```
Keep constants (Facebook permissions, Auth0 scopes) at the top of your class to avoid magic strings. Consider using `async/await` to flatten the nested callbacks if you target iOS 15+.
**Checkpoint**
You should now be able to authenticate natively with Facebook. If the Facebook app is installed on the device, authentication is handled through the app directly — no browser required.
***
## Troubleshooting & Advanced
### Token exchange fails with authentication error
**Solutions:**
1. Verify your Auth0 application has **Facebook Native Sign In** enabled in the Dashboard
2. Check that `FacebookAppID` in `Info.plist` matches the App ID in the Facebook Developer Console
3. Ensure the `Auth0.plist` file is added to the correct target in Xcode
4. Confirm the Facebook access token hasn't expired before calling `performLogin`
### Session token request returns an error
**Fix:**
* Verify `FacebookAppID` is correctly set in `Info.plist`
* Ensure the `fb_exchange_token` is the raw token string (`accessToken.tokenString`)
* Check that your Facebook app is not in Development Mode if testing with non-admin users
### `AuthenticationError`: "Connection not found"
**Fix:**
1. Go to Auth0 Dashboard → **Authentication** → **Social**
2. Verify **Sign in with Facebook** is enabled
3. Confirm **Facebook Native Social Login** is turned on in the connection settings
4. Check the Auth0 application is associated with the Facebook connection
### User profile fields are missing
* Confirm `"email"` and `"public_profile"` are in the `fbLoginButton.permissions` array
* The user may have declined the `email` permission — handle a nil email gracefully
* Verify the same fields are in the `request.parameters["fields"]` call in `fetchUserProfile`
### `Auth0.plist` not found
* Ensure the file name is exactly `Auth0.plist` (case-sensitive)
* In Xcode, check the file's **Target Membership** — it must be included in your app target
### Security Best Practices
* **Secure token storage**: Use the `CredentialsManager` from Auth0.swift to store tokens securely in the iOS Keychain
* **Refresh tokens**: Request `offline_access` scope and use `CredentialsManager` to silently refresh expired tokens
* **Biometric protection**: Enable biometric authentication on `CredentialsManager` to protect stored credentials
### Facebook App Configuration
* Switch your Facebook app from **Development Mode** to **Live** before releasing to the App Store
* Ensure your app's Bundle ID is registered in the Facebook Developer Console
* Review Facebook's [Data Policy](https://developers.facebook.com/policy/) requirements for apps using the Login SDK
### App Store Submission
* Include Facebook Login in your app's privacy policy and App Store privacy nutrition label
* Handle cases where the user denies the `email` permission — your app should function without it
* Test on a real device before submitting; the Facebook SDK behaves differently on simulators
If you target iOS 15+, you can use async/await to write cleaner, non-nested code:
```swift ViewController.swift expandable lines theme={null}
@MainActor
private func performLogin(accessToken: AccessToken) async {
do {
let sessionToken = try await fetchSessionTokenAsync(accessToken: accessToken)
let userProfile = try await fetchUserProfileAsync()
let credentials = try await exchangeTokenAsync(sessionToken: sessionToken, userProfile: userProfile)
// Authenticated! Store credentials and update UI
print("Access token:", credentials.accessToken)
} catch {
print("Authentication failed:", error)
}
}
```
Wrap each callback-based method in a `withCheckedThrowingContinuation` to bridge to async/await.
***
## Next Steps
Add Google, Apple, and other social login providers
Protect against brute force and bot attacks
Customize authentication flows with serverless code
Explore the full Auth0.swift SDK documentation
# Add Login to Your Kotlin Multiplatform Application using the Auth0 Kotlin Multiplatform SDK
Source: https://auth0.com/docs/quickstart/native/kotlin-multiplatform
Add authentication to a Kotlin Multiplatform (Android + iOS) app using the Auth0 Kotlin Multiplatform SDK.
If you use an AI coding assistant like Claude Code, Cursor, or GitHub Copilot, you can add Auth0 authentication automatically in minutes using [agent skills](https://agentskills.io/home).
**Install:**
```bash theme={null}
npx skills add auth0/agent-skills --skill auth0
```
**Then ask your AI assistant:**
```text theme={null}
Add Auth0 authentication to my Kotlin Multiplatform app.
```
Your AI assistant automatically creates your Auth0 application, fetches credentials, adds the Auth0 Kotlin Multiplatform SDK dependency, configures the Android manifest placeholders and iOS URL scheme, and implements login/logout flows. [Read the full agent skills documentation](/docs/quickstart/agent-skills).
Use this quickstart with Kotlin Multiplatform 2.0+, with Android SDK 24+, (Android 7.0), and iOS 14+. The Auth0 Kotlin Multiplatform SDK is currently in 1.0.0-beta.0. Pin this version explicitly, as the API may change before the stable release. You need [Android Studio](https://developer.android.com/studio) (Ladybug or newer) and, for the iOS target, [Xcode 15+](https://developer.apple.com/xcode/) on macOS.
## Get Started
Use this quickstart to configure your Kotlin Multiplatform app for end users to log in and out through Auth0 [Universal Login](/docs/authenticate/login/auth0-universal-login), persist tokens securely, and display user profiles — all from shared Kotlin code running on both Android and iOS.
If you already have a Kotlin Multiplatform project, skip to the next step.
Create a new Kotlin Multiplatform project with a shared Compose UI using the [JetBrains Kotlin Multiplatform wizard](https://kmp.jetbrains.com/) (select **Android** and **iOS**, and share the UI with **Compose Multiplatform**), or the **Kotlin Multiplatform** plugin in Android Studio.
This produces the standard layout referenced throughout this guide:
```text theme={null}
your-app/
├── composeApp/
│ ├── build.gradle.kts
│ └── src/
│ ├── commonMain/kotlin/ ← shared code (Auth0 client, view model, UI)
│ ├── androidMain/ ← Android entry point + AndroidManifest.xml
│ └── iosMain/kotlin/ ← iOS entry point
├── iosApp/ ← Xcode project (Info.plist lives here)
└── settings.gradle.kts
```
This guide uses `com.example.app` as the application ID / bundle identifier. Replace this placeholder with your own since it becomes part of your Auth0 callback URLs.
Add the Auth0 Kotlin Multiplatform SDK to the `commonMain` source set of your shared module. The library is published to Maven Central, so no extra repository configuration is required.
**Update `composeApp/build.gradle.kts`:**
```kotlin composeApp/build.gradle.kts theme={null}
kotlin {
sourceSets {
commonMain.dependencies {
// Umbrella module — aggregates web auth, authentication, and credentials
implementation("com.auth0.kmp:auth0:1.0.0-beta.0")
}
}
}
```
The umbrella `auth0` artifact pulls in everything you need. For a smaller footprint, you can depend on the following individual modules instead: `auth0-core`, `auth0-webauth`, `auth0-authentication`, `auth0-credentials`.
Create a Native application in Auth0 and register the platform callback and logout URLs for both Android and iOS.
1. Navigate to the [Auth0 Dashboard](https://manage.auth0.com/dashboard/).
2. Select **Applications** > **Applications** > **Create Application**.
3. In the popup, enter a name for your app, select **Native** as the app type, and choose **Create**.
4. Switch to the Settings tab on the Application Details page and copy the Domain and Client ID. You need to add them to your code in a later step.
Still on the Settings tab, configure the following URLs. The callback format is scheme-specific per platform, so register one entry for Android and one for iOS:
**Allowed Callback URLs:**
```
com.example.app://{yourDomain}/android/com.example.app/callback, com.example.app://{yourDomain}/ios/com.example.app/callback
```
**Allowed Logout URLs:**
```
com.example.app://{yourDomain}/android/com.example.app/callback, com.example.app://{yourDomain}/ios/com.example.app/callback
```
Replace `{yourDomain}` with your actual Auth0 domain (e.g., `dev-abc123.us.auth0.com`) and `com.example.app` with your application ID / bundle identifier.
Allowed Callback URLs ensure end users are safely returned to your application after authentication. Without a matching URL, the login process will fail. Allowed Logout URLs ensure users are redirected back to your app after signing out.
The callback format embeds your package/bundle identifier: `SCHEME://YOUR_DOMAIN/android/APPLICATION_ID/callback` for Android and `SCHEME://YOUR_DOMAIN/ios/BUNDLE_ID/callback` for iOS. By default the scheme equals your application ID / bundle identifier.
**Important**: Ensure the package/bundle name in your callback URLs matches your `applicationId` (Android) and bundle identifier (iOS) exactly. If authentication fails, verify these values are identical.
The SDK ships a `RedirectActivity` (Android, merged automatically) and uses `ASWebAuthenticationSession` (iOS) to catch the callback. You only need to declare the URL scheme on each platform.
**Android**: Add the manifest placeholders to your Android build file. The SDK's `RedirectActivity` reads these values:
```kotlin composeApp/build.gradle.kts theme={null}
android {
defaultConfig {
manifestPlaceholders["auth0Scheme"] = "{yourScheme}" // default: your application ID
manifestPlaceholders["auth0Domain"] = "{yourDomain}"
}
}
```
Also ensure your `AndroidManifest.xml` requests the Internet permission:
```xml composeApp/src/androidMain/AndroidManifest.xml theme={null}
```
**iOS**: Register the URL scheme in `iosApp/iosApp/Info.plist` (or via Xcode → target → **Info** → **URL Types**):
```xml iosApp/iosApp/Info.plist theme={null}
CFBundleURLTypesCFBundleTypeRoleEditorCFBundleURLSchemescom.example.app
```
In your shared `commonMain` source set, create the `Auth0` client once and reuse it. It holds the transport shared by web auth, the [Authentication API](/docs/api/authentication), and the credentials manager.
**Create `composeApp/src/commonMain/kotlin/Auth0Config.kt`:**
```kotlin composeApp/src/commonMain/kotlin/Auth0Config.kt theme={null}
import com.auth0.kmp.Auth0
import com.auth0.kmp.core.Auth0Account
// Shared code — one account works for Android and iOS
val account = Auth0Account(
clientId = "YOUR_AUTH0_CLIENT_ID", // From Application Settings → Client ID
domain = "{yourDomain}", // From Application Settings → Domain
)
val auth0 = Auth0(account)
```
For production, avoid hard-coding credentials in source. The [sample app](https://github.com/auth0/auth0-kmp/tree/main/sample-app) reads `auth0.domain` and `auth0.clientId` from `local.properties` and exposes them via generated config. The Domain and Client ID both come from Application Settings in the Auth0 Dashboard. The domain must not include the `https://` scheme.
Every Auth0 Kotlin Multiplatform method is a coroutine `suspend` function that returns a `Result` — no exceptions are thrown for domain errors. Wrap the calls in a `ViewModel` so your Compose UI can observe the state.
**Create `composeApp/src/commonMain/kotlin/AuthViewModel.kt`:**
```kotlin composeApp/src/commonMain/kotlin/AuthViewModel.kt theme={null}
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.auth0.kmp.core.result.Result
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
sealed interface AuthState {
data object LoggedOut : AuthState
data object Loading : AuthState
data class LoggedIn(val accessToken: String) : AuthState
data class Error(val message: String) : AuthState
}
class AuthViewModel(val auth0: Auth0) : ViewModel() {
// Persists and auto-renews tokens (Keystore/DataStore on Android, Keychain on iOS)
private val credentialsManager = auth0.credentials()
private val _state = MutableStateFlow(AuthState.LoggedOut)
val state: StateFlow = _state.asStateFlow()
fun login() {
viewModelScope.launch {
_state.value = AuthState.Loading
// Opens Universal Login in the system browser
when (val result = auth0.webAuth.login()) {
is Result.Success -> {
credentialsManager.saveCredentials(result.data)
_state.value = AuthState.LoggedIn(result.data.accessToken)
}
is Result.Failure -> {
_state.value = AuthState.Error(result.error.toString())
}
}
}
}
fun logout() {
viewModelScope.launch {
// Clears the browser session, then the locally stored credentials
when (val result = auth0.webAuth.logout()) {
is Result.Success -> {
credentialsManager.clearCredentials()
_state.value = AuthState.LoggedOut
}
is Result.Failure -> {
_state.value = AuthState.Error(result.error.toString())
}
}
}
}
}
```
Wire the view model into a Compose screen shared across both platforms:
```kotlin composeApp/src/commonMain/kotlin/App.kt theme={null}
import androidx.compose.material3.Button
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
@Composable
fun App(viewModel: AuthViewModel = viewModel { AuthViewModel() }) {
MaterialTheme {
val state by viewModel.state.collectAsStateWithLifecycle()
when (val current = state) {
is AuthState.Loading -> CircularProgressIndicator()
is AuthState.LoggedIn -> Button(onClick = viewModel::logout) { Text("Log Out") }
is AuthState.Error -> Text("Something went wrong: ${current.message}")
AuthState.LoggedOut -> Button(onClick = viewModel::login) { Text("Log In") }
}
}
}
```
After login, call the Authentication API's `userInfo` with the access token to retrieve the authenticated user's profile.
```kotlin composeApp/src/commonMain/kotlin/AuthViewModel.kt theme={null}
import com.auth0.kmp.authentication.UserInfo
suspend fun fetchProfile(accessToken: String): UserInfo? {
return when (val result = auth0.authentication.userInfo(accessToken)) {
is Result.Success -> result.data // .name, .email, .picture, .customClaims, ...
is Result.Failure -> null
}
}
```
On app launch, you can skip the login screen if valid credentials already exist: `credentialsManager.hasValidCredentials()` returns `true` when a stored, non-expired session is available. Use `credentialsManager.getCredentials()` to retrieve a valid access token, and renew the access token with the [refresh token](/docs/secure/tokens/refresh-tokens) automatically when needed.
Build and launch on each target:
```shellscript Android theme={null}
./gradlew :composeApp:installDebug
```
```shellscript iOS theme={null}
# Open the Xcode project and run on a simulator or device
open iosApp/iosApp.xcodeproj
```
**Expected flow:**
1. App launches with a "Log In" button.
2. Tap "Log In" → the system browser opens the Auth0 Universal Login page → complete login.
3. Control returns to the app automatically and the button switches to "Log Out".
4. Success!
**Checkpoint**
You now have a Compose Multiplatform app with Auth0 login, logout, secure token storage, and user profile retrieval — sharing all authentication logic between Android and iOS.
***
## Troubleshooting & Advanced
**Cause:** The callback URL the SDK generates isn't listed in your Auth0 application, or the scheme/package don't match.
**Fix:** Confirm Allowed Callback URLs in Application Settings exactly matches the platform format — `SCHEME://YOUR_DOMAIN/android/APPLICATION_ID/callback` for Android and `SCHEME://YOUR_DOMAIN/ios/BUNDLE_ID/callback` for iOS. The `SCHEME` (default: your application ID) and package/bundle must be identical to your project's values. URLs are case-sensitive and the scheme must be lowercase.
**Cause:** The callback scheme isn't declared on the platform, so the OS can't route the redirect back to your app.
**Fix:** On Android, verify `manifestPlaceholders["auth0Scheme"]` and `["auth0Domain"]` are set in `composeApp/build.gradle.kts` and run a clean build. On iOS, verify the `CFBundleURLSchemes` entry in `Info.plist` matches your bundle identifier.
**Cause:** The device can't reach your Auth0 tenant, or a request times out.
**Fix:** Confirm `domain` in `Auth0Account` is your tenant domain without the `https://` scheme (e.g., `your-tenant.us.auth0.com`). On a physical device, ensure it has network access. You can raise the timeouts via the `NetworkingConfiguration` passed to `Auth0Account`.
**Cause:** No refresh token is issued, so expired credentials aren't renewed.
**Fix:** Universal Login requests the `offline_access` scope by default (which returns a refresh token). If you override `scope` in `LoginOptions`, include `offline_access`, and enable **Refresh Token Rotation** for the application in the Auth0 Dashboard.
**Cause:** The `auth0Domain` / `auth0Scheme` manifest placeholders are missing, so the SDK's merged `RedirectActivity` has no value to bind to.
**Fix:** Ensure both placeholders are defined in the `defaultConfig` block of `composeApp/build.gradle.kts`. If you use multiple build flavors, define them in each flavor.
Check for stored credentials before showing the login screen so returning users skip Universal Login:
```kotlin theme={null}
if (credentialsManager.hasValidCredentials()) {
val credentials = credentialsManager.getCredentials() // auto-renews if expired
// route to your authenticated screen
}
```
Request an audience so Auth0 issues an access token for your API:
```kotlin theme={null}
import com.auth0.kmp.webauth.LoginOptions
auth0.webAuth.login(
LoginOptions(
audience = "https://your-api.example.com", // From API Settings → Identifier
scope = "openid profile email offline_access",
),
)
```
Log the user out of the upstream identity provider as well as Auth0:
```kotlin theme={null}
import com.auth0.kmp.webauth.LogoutOptions
auth0.webAuth.logout(LogoutOptions(federated = true))
```
## Next steps
* Explore the full [Auth0 Kotlin Multiplatform SDK](https://github.com/auth0/auth0-kmp) and its `EXAMPLES.md` for organizations, DPoP, passkeys, and custom storage.
* Run the complete [Android + iOS sample app](https://github.com/auth0/auth0-kmp/tree/main/sample-app).
* Learn more about [Auth0 Universal Login](/docs/authenticate/login/auth0-universal-login) and [refresh tokens](/docs/secure/tokens/refresh-tokens).
# Add login to your .NET MAUI application
Source: https://auth0.com/docs/quickstart/native/maui
This guide demonstrates how to integrate Auth0 with a .NET MAUI application using the Auth0.OidcClient.MAUI SDK.
If you use an AI coding assistant like Claude Code, Cursor, or GitHub Copilot, you can add Auth0 authentication automatically in minutes using [agent skills](https://agentskills.io/home).
**Install:**
```bash theme={null}
npx skills add auth0/agent-skills --skill auth0
```
**Then ask your AI assistant:**
```text theme={null}
Add Auth0 authentication to my .NET MAUI app
```
Your AI assistant will automatically create your Auth0 application, fetch credentials, install the Auth0 OidcClient MAUI SDK, configure callback URLs, and implement login/logout flows. [Full agent skills documentation →](/docs/quickstart/agent-skills)
This guide demonstrates how to integrate Auth0 with a .NET MAUI application using the [Auth0.OidcClient.MAUI SDK](https://github.com/auth0/auth0-oidc-client-net). By the end, your app will support login, logout, and displaying user profile information across **Android**, **iOS**, **macOS**, and **Windows** from a single codebase.
This guide uses `Auth0.OidcClient.MAUI` version **1.x**.
## Prerequisites
* **.NET 8 or .NET 9 SDK** installed ([download](https://dotnet.microsoft.com/download))
* **MAUI workload** installed
* An **Auth0 account** ([sign up for free](https://auth0.com/signup))
* **Visual Studio 2022** (17.8+), **JetBrains Rider**, or **VS Code** with the .NET MAUI extension
Verify your environment:
```shellscript theme={null}
dotnet --version # Should be 8.x or 9.x
dotnet workload list # Should include maui
```
If the MAUI workload is missing, install it:
```shellscript theme={null}
dotnet workload install maui
```
## Get started
Set up your Auth0 application so you have the credentials your MAUI app needs.
1. Go to **[Auth0 Dashboard](https://manage.auth0.com/dashboard/) > Applications > Applications**
2. Select **Create Application**
3. Enter a name for your app (for example, "My MAUI App"), select **Native** as the application type, and select **Create**
4. Go to the **Settings** tab on the Application Details page
5. Note the **Domain** and **Client ID** values — you need these later
On the **Settings** tab, scroll to **Application URIs** and configure the following URLs. .NET MAUI apps use a custom URI scheme (for example, `myapp://callback`) rather than an HTTP URL.
**Allowed Callback URLs:**
```text theme={null}
myapp://callback
```
**Allowed Logout URLs:**
```text theme={null}
myapp://callback
```
Choose a scheme that is unique to your app. A reversed domain name works well, for example `com.mycompany.myapp://callback`.
Select **Save Changes**.
You have a Native application in Auth0 with your **Domain** and **Client ID** noted, and the callback and logout URLs configured.
If you already have a .NET MAUI project, skip to Step 3. Otherwise, create one using the .NET CLI:
```shellscript theme={null}
dotnet new maui -n MyMauiApp
cd MyMauiApp
```
Add the `Auth0.OidcClient.MAUI` NuGet package to your project:
```shellscript theme={null}
dotnet add package Auth0.OidcClient.MAUI
```
Run `dotnet restore` to confirm the package installed without errors.
.NET MAUI apps must register a callback handler on each platform so the system browser can redirect back to your app after authentication. Follow the instructions for each platform you are targeting.
Create a new file at `Platforms/Android/WebAuthenticatorActivity.cs`:
```csharp Platforms/Android/WebAuthenticatorActivity.cs lines theme={null}
using Android.App;
using Android.Content;
using Android.Content.PM;
namespace MyMauiApp.Platforms.Android;
[Activity(NoHistory = true, LaunchMode = LaunchMode.SingleTop, Exported = true)]
[IntentFilter(new[] { Intent.ActionView },
Categories = new[] { Intent.CategoryDefault, Intent.CategoryBrowsable },
DataScheme = CALLBACK_SCHEME)]
public class WebAuthenticatorActivity : Microsoft.Maui.Authentication.WebAuthenticatorCallbackActivity
{
const string CALLBACK_SCHEME = "myapp";
}
```
Replace `myapp` with the URI scheme you configured in Step 1.
The `CALLBACK_SCHEME` value must exactly match the scheme in your `RedirectUri` and the **Allowed Callback URLs** in Auth0.
The Auth0 callback flow on Windows relies on URI protocol activation, which requires your app to be **packaged** (MSIX). The default .NET MAUI template creates a packaged app, so no changes are needed if you used `dotnet new maui` or the Visual Studio MAUI template.
If your `.csproj` contains `None`, your app is **unpackaged** and protocol activation will not work. Remove that line or set it to `MSIX` to use a packaged app. To learn more, see the [.NET MAUI Windows packaging documentation](https://learn.microsoft.com/en-us/dotnet/maui/windows/deployment-overview).
Two changes are required: registering the URI protocol and handling protocol activation.
**1. Register the protocol** in `Platforms/Windows/Package.appxmanifest`. Add the `` block inside the existing `` element:
```xml Platforms/Windows/Package.appxmanifest lines theme={null}
```
**2. Handle activation** in `Platforms/Windows/App.xaml.cs`. Add the `CheckRedirectionActivation` call as the **first line** in the constructor:
```csharp Platforms/Windows/App.xaml.cs lines theme={null}
public App()
{
if (Auth0.OidcClient.Platforms.Windows.Activator.Default.CheckRedirectionActivation())
return;
this.InitializeComponent();
}
```
No platform-specific configuration is required. The SDK uses `ASWebAuthenticationSession` via MAUI's `WebAuthenticator` automatically.
You need to create/modify three files: a ViewModel with the login/logout logic, a XAML page for the UI, and a code-behind file to wire them together.
Create the ViewModel at `ViewModels/MainPageViewModel.cs`:
```csharp ViewModels/MainPageViewModel.cs lines theme={null}
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows.Input;
using Auth0.OidcClient;
namespace MyMauiApp.ViewModels;
public class MainPageViewModel : INotifyPropertyChanged
{
private readonly Auth0Client _client;
private string _name;
private string _email;
private bool _isAuthenticated;
public event PropertyChangedEventHandler PropertyChanged;
public string Name
{
get => _name;
set { _name = value; OnPropertyChanged(); }
}
public string Email
{
get => _email;
set { _email = value; OnPropertyChanged(); }
}
public bool IsAuthenticated
{
get => _isAuthenticated;
set
{
_isAuthenticated = value;
OnPropertyChanged();
OnPropertyChanged(nameof(IsNotAuthenticated));
}
}
public bool IsNotAuthenticated => !IsAuthenticated;
public ICommand LoginCommand { get; }
public ICommand LogoutCommand { get; }
public MainPageViewModel(Auth0Client client)
{
_client = client;
LoginCommand = new Command(async () => await LoginAsync());
LogoutCommand = new Command(async () => await LogoutAsync());
}
private async Task LoginAsync()
{
var loginResult = await _client.LoginAsync();
if (loginResult.IsError)
{
if (loginResult.Error == "UserCancel")
return; // User closed the browser — not an error
await Shell.Current.DisplayAlert("Login failed", loginResult.Error, "OK");
return;
}
// Read user profile claims from the ID token
Name = loginResult.User.FindFirst(c => c.Type == "name")?.Value;
Email = loginResult.User.FindFirst(c => c.Type == "email")?.Value;
IsAuthenticated = true;
}
private async Task LogoutAsync()
{
await _client.LogoutAsync();
Name = null;
Email = null;
IsAuthenticated = false;
}
private void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
```
Wire up the UI in `MainPage.xaml`:
```xml MainPage.xaml lines theme={null}
```
Set the BindingContext in `MainPage.xaml.cs`:
```csharp MainPage.xaml.cs lines theme={null}
namespace MyMauiApp;
public partial class MainPage : ContentPage
{
public MainPage(MainPageViewModel viewModel)
{
InitializeComponent();
BindingContext = viewModel;
}
}
```
Your project now has a ViewModel with login and logout commands, a data-bound XAML page, and wired-up code-behind.
Now register the `Auth0Client`, the ViewModel, and the page with dependency injection in `MauiProgram.cs`. This wires everything together so the Auth0 client is injected into the ViewModel, and the ViewModel is injected into the page:
```csharp MauiProgram.cs lines theme={null}
using Auth0.OidcClient;
using MyMauiApp.ViewModels;
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp()
.ConfigureFonts(fonts =>
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
});
// Configure the Auth0 client with your credentials from Step 1
builder.Services.AddSingleton(new Auth0Client(new Auth0ClientOptions
{
Domain = "{yourDomain}",
ClientId = "{yourClientId}",
RedirectUri = "myapp://callback",
PostLogoutRedirectUri = "myapp://callback"
}));
// Register the page and ViewModel created in Step 5
builder.Services.AddTransient();
builder.Services.AddTransient();
return builder.Build();
}
}
```
Replace `{yourDomain}` and `{yourClientId}` with the values from your Auth0 application settings (Step 1).
`RedirectUri` and `PostLogoutRedirectUri` are **required** for MAUI apps. Use the same callback URL you entered in the Auth0 Dashboard.
Build and run your .NET MAUI application
**Expected flow:**
1. App launches and shows the **Log In** button
2. Tap **Log In** → system browser opens with Auth0 Universal Login
3. Complete authentication (sign up or log in)
4. Browser redirects back to your app
5. The app displays your name and email with a **Log Out** button
You now have a fully functional Auth0 login experience in your .NET MAUI application.
***
## Troubleshooting
**Symptom**: The browser shows "Callback URL mismatch. The provided redirect\_uri is not in the list of allowed callback URLs."
**Fix:**
1. Confirm the **Client ID** in your code matches the application you configured in the Auth0 Dashboard
2. Clear the **Allowed Callback URLs** field and retype `myapp://callback` manually — copy-paste often introduces invisible trailing spaces or newlines
3. Ensure the match is exact: no trailing slash, lowercase only, no whitespace
4. Select **Save Changes** in the Dashboard and verify the value persisted
5. Check the browser address bar for the `redirect_uri` query parameter to see what your app is actually sending
**Symptom**: Browser opens for login but never redirects back to the app.
**Fix:**
1. Verify `DataScheme` in `WebAuthenticatorActivity.cs` matches your `RedirectUri` scheme
2. Ensure the Activity has `Exported = true`
3. Confirm the **Allowed Callback URLs** in Auth0 Dashboard match exactly
**Symptom**: Browser opens but a second instance of the app opens instead of resuming.
**Fix:** Ensure `Auth0.OidcClient.Platforms.Windows.Activator.Default.CheckRedirectionActivation()` is called as the **very first line** of the `App` constructor in `Platforms/Windows/App.xaml.cs`, and that the protocol name in `Package.appxmanifest` matches your callback URI scheme.
**Symptom**: After login, the browser shows an error or nothing happens — the app never receives the callback.
**Fix:** Your app must be a **packaged** (MSIX) application. Check your `.csproj` file for a `` element:
* If it is set to `None`, protocol activation is not available. Remove the line or change it to `MSIX`.
* If the element is absent, your app is already packaged by default — verify that `Package.appxmanifest` contains the `` extension from Step 4.
**Symptom**: `name`, `email`, or `picture` claims are absent from `loginResult.User`.
**Fix:** Verify that `openid profile email` are included in `Auth0ClientOptions.Scope`. If you have customized the scope, ensure `openid` is always present.
***
## Next steps
You now have a working Auth0 integration in your .NET MAUI app. Explore these topics to extend your implementation:
The Auth0 MAUI SDK supports refresh tokens for silently renewing sessions without re-prompting the user.
### Enable refresh tokens
Add `offline_access` to the `Scope` property:
```csharp expandable lines theme={null}
builder.Services.AddSingleton(new Auth0Client(new Auth0ClientOptions
{
Domain = "{yourDomain}",
ClientId = "{yourClientId}",
RedirectUri = "myapp://callback",
PostLogoutRedirectUri = "myapp://callback",
Scope = "openid profile email offline_access"
}));
```
### Use refresh tokens
After login, store the refresh token and use it to silently renew the session:
```csharp expandable lines theme={null}
// After login
var refreshToken = loginResult.RefreshToken;
// Later, renew the session
var refreshResult = await _client.RefreshTokenAsync(refreshToken);
if (!refreshResult.IsError)
{
var newAccessToken = refreshResult.AccessToken;
var newIdToken = refreshResult.IdentityToken;
}
```
If `RefreshToken` is `null` after login, ensure **Allow Offline Access** is enabled in your API settings in the Auth0 Dashboard (when using an `audience` parameter).
To get an access token scoped to your API, set the `Scope` and pass an `audience` parameter to `LoginAsync()`:
```csharp expandable lines theme={null}
var loginResult = await _client.LoginAsync(new
{
audience = "https://myapi.example.com"
});
// The access token is now scoped to your API
var accessToken = loginResult.AccessToken;
var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Authorization =
new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", accessToken);
var response = await httpClient.GetAsync("https://myapi.example.com/posts");
```
Authenticate users within a specific Auth0 Organization:
```csharp expandable lines theme={null}
var loginResult = await _client.LoginAsync(new
{
organization = "org_abc123"
});
```
To learn more, see [Organizations](/docs/manage-users/organizations).
Use `MaxAge` to force re-authentication after a specified time:
```csharp expandable lines theme={null}
new Auth0ClientOptions
{
Domain = "{yourDomain}",
ClientId = "{yourClientId}",
RedirectUri = "myapp://callback",
PostLogoutRedirectUri = "myapp://callback",
MaxAge = TimeSpan.FromMinutes(30)
}
```
Tailor the Auth0 login page to match your brand, including colors, logos, and text.
To learn more, see [Customize Universal Login](/docs/customize/universal-login-pages).
***
## Additional resources
Source code, samples, and API reference
Security best practices for tokens
How native apps authenticate securely
Get help from the Auth0 community
# Add Login to Your .NET Android & iOS Application
Source: https://auth0.com/docs/quickstart/native/net-android-ios/index
If you use an AI coding assistant like Claude Code, Cursor, or GitHub Copilot, you can add Auth0 authentication automatically in minutes using [agent skills](https://agentskills.io/home).
**Install:**
```bash theme={null}
npx skills add auth0/agent-skills --skill auth0
```
**Then ask your AI assistant:**
```text theme={null}
Add Auth0 authentication to my .NET Android & iOS app
```
Your AI assistant will automatically create your Auth0 application, fetch credentials, install the Auth0 OidcClient SDK, configure platform-specific settings, and implement login/logout flows. [Full agent skills documentation →](/docs/quickstart/agent-skills)
## Get Started
Create a new .NET MAUI or .NET Android/iOS project for this quickstart.
**In Visual Studio 2022 or later:**
1. **File** → **New** → **Project**
2. Select **.NET MAUI App** template
3. Configure your project:
* **Project name**: `Auth0MauiSample`
* **Location**: Choose your preferred location
* **Framework**: **.NET 8.0 or later**
4. Click **Create**
**In Visual Studio 2022 or later:**
1. **File** → **New** → **Project**
2. Select **Android App (.NET)** template
3. Configure your project:
* **Project name**: `Auth0AndroidSample`
* **Framework**: **.NET 8.0 or later**
4. Click **Create**
**In Visual Studio 2022 (Mac) or Visual Studio for Mac:**
1. **File** → **New** → **Project**
2. Select **iOS App (.NET)** template
3. Configure your project:
* **Project name**: `Auth0iOSSample`
* **Framework**: **.NET 8.0 or later**
4. Click **Create**
This quickstart focuses on .NET Android and iOS, which are the next generation of Xamarin.Android and Xamarin.iOS. If you're still using Xamarin, you can follow this guide as the integration is identical and the SDKs are compatible.
Add the Auth0 OIDC Client SDK to your project.
Open the Package Manager Console (**View** → **Other Windows** → **Package Manager Console**) and install the appropriate package:
**For .NET Android:**
```bash Package Manager Console theme={null}
Install-Package Auth0.OidcClient.AndroidX
```
**For .NET iOS:**
```bash Package Manager Console theme={null}
Install-Package Auth0.OidcClient.iOS
```
**For .NET MAUI (both platforms):**
```bash Package Manager Console theme={null}
Install-Package Auth0.OidcClient.MAUI
```
1. In the **Solution Pad**, Ctrl+click (or right-click) on the **Packages** folder
2. Select **Add Packages...**
3. Search for:
* `Auth0.OidcClient.AndroidX` for Android
* `Auth0.OidcClient.iOS` for iOS
* `Auth0.OidcClient.MAUI` for MAUI projects
4. Select the package and click **Add Package**
Run the following command in your project directory:
**For .NET Android:**
```bash Terminal theme={null}
dotnet add package Auth0.OidcClient.AndroidX
```
**For .NET iOS:**
```bash Terminal theme={null}
dotnet add package Auth0.OidcClient.iOS
```
**For .NET MAUI:**
```bash Terminal theme={null}
dotnet add package Auth0.OidcClient.MAUI
```
The Auth0 OIDC Client SDK handles all the OAuth 2.0 and OIDC protocol details, providing a simple API for authentication.
Create a new application in your Auth0 tenant and configure it for mobile.
1. Head to the [Auth0 Dashboard](https://manage.auth0.com/dashboard/)
2. Click on **Applications** → **Applications** → **Create Application**
3. Enter a name for your app, select **Native** as the app type, and click **Create**
4. Switch to the **Settings** tab on the Application Details page
5. Note your **Domain** and **Client ID** - you'll need these in the next step
**Configure Callback URLs:**
On the **Settings** tab, add the following URLs:
**Allowed Callback URLs:**
```
YOUR_ANDROID_PACKAGE_NAME://{yourDomain}/android/YOUR_ANDROID_PACKAGE_NAME/callback
```
Replace:
* `YOUR_ANDROID_PACKAGE_NAME` with your app's package name (e.g., `com.mycompany.myapp`)
* `{yourDomain}` with your Auth0 domain (e.g., `dev-abc123.us.auth0.com`)
Example: `com.mycompany.myapp://dev-abc123.us.auth0.com/android/com.mycompany.myapp/callback`
```
YOUR_BUNDLE_IDENTIFIER://{yourDomain}/ios/YOUR_BUNDLE_IDENTIFIER/callback
```
Replace:
* `YOUR_BUNDLE_IDENTIFIER` with your app's bundle identifier (e.g., `com.mycompany.myapp`)
* `{yourDomain}` with your Auth0 domain (e.g., `dev-abc123.us.auth0.com`)
Example: `com.mycompany.myapp://dev-abc123.us.auth0.com/ios/com.mycompany.myapp/callback`
**Allowed Logout URLs:**
Use the same URLs as your callback URLs.
Ensure that callback and logout URLs are in **lowercase**. Mismatched URLs will cause authentication to fail.
**Allowed Callback URLs** are essential for security - they ensure users are safely returned to your application after authentication. Without a matching URL, the login process will fail.
**Allowed Logout URLs** provide a seamless experience when users sign out, redirecting them back to your app instead of leaving them on an Auth0 page.
Create an `Auth0Client` instance to communicate with Auth0.
```cs MainActivity.cs lines theme={null}
using Auth0.OidcClient;
using Android.App;
using Android.Content;
[Activity(Label = "Auth0Sample", MainLauncher = true, Icon = "@drawable/icon",
LaunchMode = LaunchMode.SingleTask)]
[IntentFilter(
new[] { Intent.ActionView },
Categories = new[] { Intent.CategoryDefault, Intent.CategoryBrowsable },
DataScheme = "YOUR_ANDROID_PACKAGE_NAME",
DataHost = "{yourDomain}",
DataPathPrefix = "/android/YOUR_ANDROID_PACKAGE_NAME/callback")]
public class MainActivity : Activity
{
private Auth0Client auth0Client;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Initialize Auth0 client
auth0Client = new Auth0Client(new Auth0ClientOptions
{
Domain = "{yourDomain}",
ClientId = "{yourClientId}"
}, this);
}
protected override async void OnNewIntent(Intent intent)
{
base.OnNewIntent(intent);
Auth0.OidcClient.ActivityMediator.Instance.Send(intent.DataString);
}
}
```
Replace `YOUR_ANDROID_PACKAGE_NAME`, `{yourDomain}`, and `{yourClientId}` with your actual values. Ensure all text in `DataScheme`, `DataHost`, and `DataPathPrefix` is **lowercase**.
The `IntentFilter` registers your app to handle the callback URL. The `LaunchMode.SingleTask` ensures Android doesn't create a new activity instance when the callback is invoked.
First, register the URL scheme in your `Info.plist`:
```xml Info.plist lines theme={null}
CFBundleURLTypesCFBundleTypeRoleNoneCFBundleURLNameAuth0CFBundleURLSchemesYOUR_BUNDLE_IDENTIFIER
```
Then, set up your `AppDelegate.cs`:
```cs AppDelegate.cs lines theme={null}
using Auth0.OidcClient;
using Foundation;
using UIKit;
[Register("AppDelegate")]
public class AppDelegate : UIApplicationDelegate
{
private Auth0Client auth0Client;
public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
{
// Initialize Auth0 client
auth0Client = new Auth0Client(new Auth0ClientOptions
{
Domain = "{yourDomain}",
ClientId = "{yourClientId}"
});
return true;
}
public override bool OpenUrl(UIApplication application, NSUrl url,
string sourceApplication, NSObject annotation)
{
ActivityMediator.Instance.Send(url.AbsoluteString);
return true;
}
}
```
Replace `YOUR_BUNDLE_IDENTIFIER`, `{yourDomain}`, and `{yourClientId}` with your actual values.
Store your Auth0 domain and client ID in a configuration file or app settings instead of hardcoding them for better maintainability.
Add methods to handle user authentication.
**Implement Login:**
```cs Authentication.cs lines theme={null}
public async Task LoginAsync()
{
var loginResult = await auth0Client.LoginAsync();
if (!loginResult.IsError)
{
// Authentication successful
var accessToken = loginResult.AccessToken;
var idToken = loginResult.IdentityToken;
var user = loginResult.User;
// Store credentials and update UI
Console.WriteLine($"Logged in as: {user.FindFirst("name")?.Value}");
}
else
{
// Handle authentication error
Console.WriteLine($"Login error: {loginResult.Error}");
}
}
```
**Implement Logout:**
```cs Authentication.cs lines theme={null}
public async Task LogoutAsync()
{
var logoutResult = await auth0Client.LogoutAsync();
if (logoutResult == BrowserResultType.Success)
{
// Clear stored credentials
// Update UI to logged-out state
Console.WriteLine("Logged out successfully");
}
}
```
The `LoginAsync()` method launches the system browser (or Chrome Custom Tabs on Android) to display Auth0's Universal Login page. After authentication, the user is redirected back to your app via the callback URL.
Add these methods to your MainActivity (Android) or a ViewController (iOS) and call them when users tap Login/Logout buttons.
Build and run your application.
**For Android:**
1. Select an Android emulator or connected device from the device dropdown
2. Press **F5** or click the **Run** button
3. The app will build, deploy, and launch
**For iOS (requires Mac build host):**
1. Connect to your Mac build host
2. Select an iOS simulator or device from the device dropdown
3. Press **F5** or click the **Run** button
1. Select your target platform (Android/iOS) from the device dropdown
2. Select an emulator/simulator or connected device
3. Press **⌘+Return** or click the **Run** button
4. The app will build and launch
**For Android:**
```bash Terminal theme={null}
dotnet build -f net8.0-android
dotnet run -f net8.0-android
```
**For iOS:**
```bash Terminal theme={null}
dotnet build -f net8.0-ios
dotnet run -f net8.0-ios
```
**Expected flow:**
1. App launches with Login button
2. Tap **Log In** → Browser/Chrome Custom Tab opens → Complete authentication
3. Redirects back to your app automatically
4. User is authenticated successfully
On first run, iOS may prompt you to confirm opening the browser for authentication. This is normal and expected behavior.
**Checkpoint**
You now have a fully functional Auth0 login experience in your .NET Android or iOS application. The app uses the system browser for secure authentication and automatically handles the callback flow.
***
## Access User Information
After successful authentication, you can access user information from the login result.
### Authentication Result
The `LoginAsync()` method returns a `LoginResult` object containing:
```cs UserInfo.cs lines theme={null}
var loginResult = await auth0Client.LoginAsync();
if (!loginResult.IsError)
{
// Access tokens
var accessToken = loginResult.AccessToken;
var idToken = loginResult.IdentityToken;
var refreshToken = loginResult.RefreshToken;
// Access user claims
var user = loginResult.User;
var name = user.FindFirst("name")?.Value;
var email = user.FindFirst("email")?.Value;
var picture = user.FindFirst("picture")?.Value;
Console.WriteLine($"Name: {name}");
Console.WriteLine($"Email: {email}");
}
```
### Iterate Through All Claims
To see all available user information:
```cs UserClaims.cs lines theme={null}
if (!loginResult.IsError)
{
foreach (var claim in loginResult.User.Claims)
{
Console.WriteLine($"{claim.Type}: {claim.Value}");
}
}
```
The exact claims returned depend on the scopes requested. For more information, see [Using Scopes](https://auth0.github.io/auth0-oidc-client-net/documentation/advanced-scenarios/scopes.html) in the Auth0 OIDC Client documentation.
### Request Custom Scopes
To request additional user information, specify scopes when creating the Auth0Client:
```cs CustomScopes.cs lines theme={null}
var auth0Client = new Auth0Client(new Auth0ClientOptions
{
Domain = "{yourDomain}",
ClientId = "{yourClientId}",
Scope = "openid profile email offline_access read:posts"
});
```
***
## Troubleshooting & Advanced
### Browser doesn't redirect back to app
**Solutions:**
1. Verify callback URLs in Auth0 Dashboard exactly match your app's package name/bundle identifier
2. Ensure callback URLs are in **lowercase**
3. Check that `DataScheme`, `DataHost`, and `DataPathPrefix` (Android) or URL scheme (iOS) match your configuration
4. Clean and rebuild your project
### Authentication fails with "Invalid Callback URL" error
**Fix:**
* Double-check that your callback URL in the Auth0 Dashboard matches the format:
* Android: `packagename://yourdomain/android/packagename/callback`
* iOS: `bundleidentifier://yourdomain/ios/bundleidentifier/callback`
* Ensure the URL is in lowercase
* Verify the Domain in your code matches the Domain in the Auth0 Dashboard
### LoginAsync() hangs or never completes
**Solutions:**
* Ensure the Intent filter (Android) or URL scheme (iOS) is properly configured
* Check that `OnNewIntent()` (Android) or `OpenUrl()` (iOS) calls the `ActivityMediator`
* Verify your app can open the system browser
* Check network connectivity
### Error: "Default App must use Token Endpoint Authentication Method 'None'"
**Fix:**
1. Go to your Auth0 Application Settings in the Dashboard
2. Scroll to **Application Properties**
3. Set **Application Type** to **Native**
4. Set **Token Endpoint Authentication Method** to **None**
5. Click **Save Changes**
### iOS: Browser doesn't open
**Solutions:**
* Verify `Info.plist` contains the correct URL scheme configuration
* Check that `OpenUrl()` is implemented in `AppDelegate`
* Ensure iOS deployment target is compatible with your Auth0 SDK version
### Security Best Practices
* **Secure Token Storage**: Use platform-specific secure storage (Android Keystore, iOS Keychain) to store tokens
* **Token Refresh**: Implement refresh token handling to maintain user sessions
* **Certificate Pinning**: Consider certificate pinning for additional API security
* **ProGuard/Code Obfuscation**: Add appropriate rules if using code obfuscation on Android
### App Store Requirements
* **Privacy Policy**: Ensure your app has a privacy policy that describes Auth0 usage
* **User Data Handling**: Follow platform guidelines for handling user authentication data
* **Deep Linking**: Test callback URL handling thoroughly across different scenarios
* **Network Requirements**: Handle offline scenarios gracefully
### Performance Optimization
* **Cache Auth0Client**: Create a single instance and reuse it throughout your app
* **Lazy Loading**: Initialize Auth0Client only when needed
* **Background Refresh**: Implement background token refresh for long-running sessions
### Custom Scopes and Audience
Request specific scopes and set an audience for your API:
```cs AdvancedAuth.cs expandable lines theme={null}
var auth0Client = new Auth0Client(new Auth0ClientOptions
{
Domain = "{yourDomain}",
ClientId = "{yourClientId}",
Scope = "openid profile email offline_access read:posts write:posts",
Audience = "https://myapi.example.com"
});
var loginResult = await auth0Client.LoginAsync();
```
### Additional Parameters
Pass additional parameters to the authorization request:
```cs ExtraParams.cs expandable lines theme={null}
var extraParameters = new Dictionary
{
{ "prompt", "login" },
{ "ui_locales", "es" },
{ "custom_param", "value" }
};
var loginResult = await auth0Client.LoginAsync(extraParameters);
```
### Refresh Tokens
Use refresh tokens to get new access tokens without user interaction:
```cs RefreshToken.cs expandable lines theme={null}
var refreshResult = await auth0Client.RefreshTokenAsync(loginResult.RefreshToken);
if (!refreshResult.IsError)
{
var newAccessToken = refreshResult.AccessToken;
var newIdToken = refreshResult.IdentityToken;
// Store new tokens
}
```
To receive a refresh token, include the `offline_access` scope in your authentication request.
### Platform-Specific Browser Configuration
**Android - Use Chrome Custom Tabs with custom colors:**
```cs AndroidBrowser.cs expandable lines theme={null}
var auth0Client = new Auth0Client(new Auth0ClientOptions
{
Domain = "{yourDomain}",
ClientId = "{yourClientId}",
Browser = new AndroidBrowser
{
ToolbarColor = Android.Graphics.Color.ParseColor("#FF6B35")
}
}, this);
```
**iOS - Use SFSafariViewController with custom presentation:**
```cs iOSBrowser.cs expandable lines theme={null}
var auth0Client = new Auth0Client(new Auth0ClientOptions
{
Domain = "{yourDomain}",
ClientId = "{yourClientId}",
Browser = new ASWebAuthenticationSessionBrowser
{
PrefersEphemeralWebBrowserSession = false
}
});
```
***
## Next Steps
Add social login providers like Google, Facebook, and GitHub
Add an extra layer of security with MFA
Learn how to protect against brute force and bot attacks
Customize the Universal Login page to match your brand
# Add Login to Your React Native Application
Source: https://auth0.com/docs/quickstart/native/react-native
This guide demonstrates how to integrate Auth0 with any React Native app using the Auth0 React Native SDK.
This Quickstart is for the React Native framework. To integrate Auth0 into your Expo application, refer to the [Expo Quickstart](https://auth0.com/docs/quickstart/native/react-native-expo/interactive).
If you use an AI coding assistant like Claude Code, Cursor, or GitHub Copilot, you can add Auth0 authentication automatically in minutes using [agent skills](https://agentskills.io/home).
**Install:**
```bash theme={null}
npx skills add auth0/agent-skills --skill auth0
```
**Then ask your AI assistant:**
```text theme={null}
Add Auth0 authentication to my React Native app
```
Your AI assistant will automatically create your Auth0 application, fetch credentials, install `react-native-auth0`, configure native dependencies, and set up your authentication flow. [Full agent skills documentation →](/docs/quickstart/agent-skills)
## Get Started
Create a new React Native project for this quickstart.
**In your terminal:**
```bash theme={null}
npx @react-native-community/cli init Auth0ReactNativeSample
cd Auth0ReactNativeSample
```
Configure your project with:
* **Name**: `Auth0ReactNativeSample`
* **Package name**: `com.auth0.samples.reactnative`
This creates a React Native app with the latest stable version. The Auth0 SDK requires React Native 0.78.0+ and React 19.0.0+.
Add the Auth0 React Native SDK to your project.
```bash theme={null}
npm install react-native-auth0
```
For iOS, install the native dependencies:
```bash theme={null}
cd ios && pod install && cd ..
```
The SDK auto-links on both platforms. The `pod install` step installs the required iOS native modules (Auth0.swift, JWTDecode, SimpleKeychain).
Create and configure an Auth0 application to work with your React Native app.
1. Head to the [Auth0 Dashboard](https://manage.auth0.com/dashboard/)
2. Click on **Applications** > **Applications** > **Create Application**
3. In the popup, enter a name for your app (e.g., `Auth0 React Native Sample`), select `Native` as the app type and click **Create**
4. Switch to the **Settings** tab on the Application Details page
5. Note your **Domain** and **Client ID** values
**Allowed Callback URLs:**
```
org.reactjs.native.example.auth0reactnativesample.auth0://{yourDomain}/ios/org.reactjs.native.example.auth0reactnativesample/callback,
com.auth0reactnativesample.auth0://{yourDomain}/android/com.auth0reactnativesample/callback
```
**Allowed Logout URLs:**
```
org.reactjs.native.example.auth0reactnativesample.auth0://{yourDomain}/ios/org.reactjs.native.example.auth0reactnativesample/callback,
com.auth0reactnativesample.auth0://{yourDomain}/android/com.auth0reactnativesample/callback
```
Replace `{yourDomain}` with your actual Auth0 domain (e.g., `dev-abc123.us.auth0.com`).
**Allowed Callback URLs** are a critical security measure to ensure users are safely returned to your application after authentication. Without a matching URL, the login process will fail, and users will be blocked by an Auth0 error page instead of accessing your app.
**Allowed Logout URLs** are essential for providing a seamless user experience upon signing out. Without a matching URL, users will not be redirected back to your application after logout and will instead be left on a generic Auth0 page.
The URL scheme includes `.auth0` after your bundle identifier to ensure the callback is routed to your specific app. For this quickstart, the bundle identifier is `org.reactjs.native.example.auth0reactnativesample`.
**Important**: The callback URL scheme must include `.auth0` after your bundle identifier (e.g., `org.reactjs.native.example.auth0reactnativesample.auth0://`). This is required for the SDK to properly handle the authentication callback.
Configure both iOS and Android to handle the authentication callback.
**Android Configuration:**
Open `android/app/build.gradle` and add the manifest placeholders inside `defaultConfig`:
```groovy android/app/build.gradle lines theme={null}
android {
defaultConfig {
applicationId "com.auth0reactnativesample"
// ... other config
// Add Auth0 manifest placeholders
manifestPlaceholders = [
auth0Domain: "{yourDomain}",
auth0Scheme: "${applicationId}.auth0"
]
}
}
```
Replace `{yourDomain}` with your Auth0 domain (e.g., `dev-abc123.us.auth0.com`).
**iOS Configuration:**
Open `ios/Auth0ReactNativeSample/AppDelegate.mm` and add the URL handling method:
```objc ios/Auth0ReactNativeSample/AppDelegate.mm lines theme={null}
#import
// Add this method inside the @implementation block
- (BOOL)application:(UIApplication *)app
openURL:(NSURL *)url
options:(NSDictionary *)options
{
return [RCTLinkingManager application:app openURL:url options:options];
}
```
Open `ios/Auth0ReactNativeSample/AppDelegate.swift` and add the URL handling method:
```swift ios/Auth0ReactNativeSample/AppDelegate.swift lines theme={null}
import React
// Add this method inside the AppDelegate class
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
return RCTLinkingManager.application(app, open: url, options: options)
}
```
Open `ios/Auth0ReactNativeSample/Info.plist` and add the URL scheme. Add this before the closing `` tag:
```xml ios/Auth0ReactNativeSample/Info.plist lines theme={null}
CFBundleURLTypesCFBundleTypeRoleNoneCFBundleURLNameauth0CFBundleURLSchemes$(PRODUCT_BUNDLE_IDENTIFIER).auth0
```
The URL scheme uses your bundle identifier with `.auth0` appended. This ensures the callback is routed to your specific app after authentication completes in the browser.
Setup your main app component based on your chosen implementation approach.
Replace the contents of `App.tsx` and wrap your application with the `Auth0Provider` component:
```tsx App.tsx lines theme={null}
import React from 'react';
import {Auth0Provider} from 'react-native-auth0';
import {SafeAreaView, StyleSheet} from 'react-native';
import MainScreen from './src/MainScreen';
const App = () => {
return (
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
},
});
export default App;
```
Replace `{yourDomain}` with your Auth0 domain and `{yourClientId}` with your Client ID from the Auth0 Dashboard.
The `Auth0Provider` initializes the SDK and provides authentication context to all child components via the `useAuth0` hook.
Replace the contents of `App.tsx` with a simple container for your class-based component:
```tsx App.tsx lines theme={null}
import React from 'react';
import {SafeAreaView, StyleSheet} from 'react-native';
import MainScreen from './src/MainScreen';
const App = () => {
return (
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
},
});
export default App;
```
The class-based approach doesn't require the `Auth0Provider` since it uses the `Auth0` class instance directly. The Auth0 configuration will be in the MainScreen component.
Create a screen component that handles login and logout. You can choose between a hooks-based approach (recommended) or a class-based approach.
Create `src/MainScreen.tsx` using the `useAuth0` hook:
```tsx src/MainScreen.tsx lines theme={null}
import React from 'react';
import {
View,
Text,
Button,
StyleSheet,
ActivityIndicator,
Image,
} from 'react-native';
import {useAuth0} from 'react-native-auth0';
const MainScreen = () => {
const {authorize, clearSession, user, isLoading} = useAuth0();
const login = async () => {
try {
await authorize({scope: 'openid profile email'});
} catch (e) {
console.error(e);
}
};
const logout = async () => {
try {
await clearSession();
} catch (e) {
console.error(e);
}
};
if (isLoading) {
return (
Loading...
);
}
return (
Auth0 React Native
{user ? (
{user.picture && (
)}
Welcome, {user.name}!{user.email}
) : (
Tap the button below to log in
)}
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
padding: 20,
},
title: {
fontSize: 28,
fontWeight: 'bold',
marginBottom: 20,
color: '#333',
},
subtitle: {
fontSize: 16,
color: '#666',
marginBottom: 30,
textAlign: 'center',
},
loadingText: {
marginTop: 10,
fontSize: 16,
color: '#666',
},
profileContainer: {
alignItems: 'center',
},
avatar: {
width: 100,
height: 100,
borderRadius: 50,
marginBottom: 20,
},
welcomeText: {
fontSize: 22,
fontWeight: '600',
marginBottom: 8,
color: '#333',
},
emailText: {
fontSize: 16,
color: '#666',
marginBottom: 30,
},
loginContainer: {
alignItems: 'center',
},
buttonContainer: {
width: 200,
marginTop: 10,
},
});
export default MainScreen;
```
Create `src/MainScreen.tsx` using the `Auth0` class directly:
```tsx src/MainScreen.tsx lines theme={null}
import React, {Component} from 'react';
import {
View,
Text,
Button,
StyleSheet,
ActivityIndicator,
Image,
} from 'react-native';
import Auth0, {Credentials} from 'react-native-auth0';
const auth0 = new Auth0({
domain: '{yourDomain}',
clientId: '{yourClientId}',
});
interface User {
name?: string;
email?: string;
picture?: string;
}
interface MainScreenState {
user: User | null;
isLoading: boolean;
}
class MainScreen extends Component<{}, MainScreenState> {
constructor(props: {}) {
super(props);
this.state = {
user: null,
isLoading: true,
};
}
async componentDidMount() {
await this.checkAuthStatus();
}
checkAuthStatus = async () => {
try {
const hasValidCredentials = await auth0.credentialsManager.hasValidCredentials();
if (hasValidCredentials) {
const credentials = await auth0.credentialsManager.getCredentials();
const userInfo = await auth0.auth.userInfo({token: credentials.accessToken});
this.setState({user: userInfo, isLoading: false});
} else {
this.setState({isLoading: false});
}
} catch (e) {
console.error(e);
this.setState({isLoading: false});
}
};
login = async () => {
try {
const credentials: Credentials = await auth0.webAuth.authorize({
scope: 'openid profile email',
});
await auth0.credentialsManager.saveCredentials(credentials);
const userInfo = await auth0.auth.userInfo({token: credentials.accessToken});
this.setState({user: userInfo});
} catch (e) {
console.error(e);
}
};
logout = async () => {
try {
await auth0.webAuth.clearSession();
await auth0.credentialsManager.clearCredentials();
this.setState({user: null});
} catch (e) {
console.error(e);
}
};
render() {
const {user, isLoading} = this.state;
if (isLoading) {
return (
Loading...
);
}
return (
Auth0 React Native
{user ? (
{user.picture && (
)}
Welcome, {user.name}!{user.email}
) : (
Tap the button below to log in
)}
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
padding: 20,
},
title: {
fontSize: 28,
fontWeight: 'bold',
marginBottom: 20,
color: '#333',
},
subtitle: {
fontSize: 16,
color: '#666',
marginBottom: 30,
textAlign: 'center',
},
loadingText: {
marginTop: 10,
fontSize: 16,
color: '#666',
},
profileContainer: {
alignItems: 'center',
},
avatar: {
width: 100,
height: 100,
borderRadius: 50,
marginBottom: 20,
},
welcomeText: {
fontSize: 22,
fontWeight: '600',
marginBottom: 8,
color: '#333',
},
emailText: {
fontSize: 16,
color: '#666',
marginBottom: 30,
},
loginContainer: {
alignItems: 'center',
},
buttonContainer: {
width: 200,
marginTop: 10,
},
});
export default MainScreen;
```
Replace `{yourDomain}` with your Auth0 domain and `{yourClientId}` with your Client ID from the Auth0 Dashboard.
The `authorize()` method (hooks) or `auth0.webAuth.authorize()` (class) opens Auth0's Universal Login in a secure browser (ASWebAuthenticationSession on iOS, Chrome Custom Tabs on Android). The `clearSession()` method logs the user out and clears both the browser session and stored credentials.
Build and run your React Native application on a device or emulator.
**For iOS (requires macOS):**
```bash theme={null}
npx react-native run-ios
```
**For Android:**
```bash theme={null}
npx react-native run-android
```
**Expected flow:**
1. App launches showing "Log In" button
2. Tap **Log In** → Browser opens with Auth0 Universal Login
3. Complete login (sign up or sign in)
4. Browser closes → Returns to app automatically
5. User profile displays with name, email, and avatar
iOS Simulator requires a valid Apple Developer account for ASWebAuthenticationSession. For testing on simulator without an account, use a physical device or Android emulator instead.
**Checkpoint**
You should now have a fully functional Auth0 login experience running on your device or emulator. The app uses secure browser authentication and automatically manages credentials.
***
## Troubleshooting & Advanced
### "Callback URL mismatch" error
**Solution:**
1. Verify the exact URL (including `.auth0` suffix) is in **Allowed Callback URLs** in your Auth0 Dashboard
2. Ensure both iOS and Android URLs are added
3. Check that `{yourDomain}` is replaced with your actual Auth0 domain
### App doesn't return after login (iOS)
**Fix:**
1. Check `Info.plist` has the `CFBundleURLSchemes` entry with `$(PRODUCT_BUNDLE_IDENTIFIER).auth0`
2. Verify `AppDelegate.mm` includes the URL handling method
3. Ensure the URL scheme matches your bundle identifier
### Android build fails
**Fix:**
1. Add `auth0Domain` and `auth0Scheme` manifest placeholders to `build.gradle`
2. Sync project with Gradle files
3. Clean build: `./gradlew clean`
### "PKCE not allowed" error
**Fix:**
1. Go to Auth0 Dashboard → Applications → Your Application
2. Change application type to **Native**
3. Save changes and try again
### Pod install fails (iOS)
**Fix:**
1. Update CocoaPods: `sudo gem install cocoapods`
2. Update pod repo: `pod install --repo-update`
3. If issues persist, delete `Podfile.lock` and `ios/Pods` folder, then run `pod install` again
### User cancelled error
Handle gracefully in your login function:
```tsx expandable theme={null}
const login = async () => {
try {
await authorize({scope: 'openid profile email'});
} catch (e) {
if (e.message === 'a0.session.user_cancelled') {
// User closed login screen - handle gracefully
console.log('Login cancelled by user');
} else {
console.error('Login failed:', e);
}
}
};
```
### iOS Alert Dialog
On iOS, users see a permission dialog: *"App Name" Wants to Use "auth0.com" to Sign In*. This is expected behavior from `ASWebAuthenticationSession`. Users must tap **Continue** to proceed.
To customize this behavior, you can use ephemeral sessions (disables SSO):
```tsx theme={null}
await authorize({scope: 'openid profile email'}, {ephemeralSession: true});
```
Use the `getCredentials()` method to retrieve tokens for API calls:
```tsx expandable lines theme={null}
import {useAuth0} from 'react-native-auth0';
const MyComponent = () => {
const {getCredentials} = useAuth0();
const callApi = async () => {
try {
const credentials = await getCredentials();
const response = await fetch('https://your-api.com/endpoint', {
headers: {
Authorization: `Bearer ${credentials.accessToken}`,
},
});
// Handle response
} catch (e) {
console.error('Failed to get credentials', e);
}
};
};
```
Include the `offline_access` scope during login to receive a refresh token: `authorize({scope: 'openid profile email offline_access'})`. This enables automatic token renewal.
Use `hasValidCredentials()` to check if the user is already logged in:
```tsx expandable lines theme={null}
import {useAuth0} from 'react-native-auth0';
import {useEffect} from 'react';
const App = () => {
const {hasValidCredentials, getCredentials} = useAuth0();
useEffect(() => {
const checkAuth = async () => {
const isLoggedIn = await hasValidCredentials();
if (isLoggedIn) {
const credentials = await getCredentials();
// User is authenticated, load their data
}
};
checkAuth();
}, []);
};
```
### Before deploying to production
**Use HTTPS callback URLs** for enhanced security:
```text theme={null}
https://{yourDomain}/ios/{bundleId}/callback
https://{yourDomain}/android/{packageName}/callback
```
**Configure Android App Links** in Auth0 Dashboard:
* Settings → Advanced Settings → Device Settings
* Add your app's SHA-256 fingerprint
**Configure iOS Universal Links:**
* Add Associated Domains capability in Xcode
* Add `webcredentials:{yourDomain}` to Associated Domains
**Enable biometric authentication** for sensitive apps using `localAuthenticationOptions` in `Auth0Provider`
**Review security settings** in Auth0 Dashboard:
* Enable **OIDC Conformant** in Advanced Settings
* Configure **Token Expiration** appropriately
* Set up **Brute Force Protection**
* Test on multiple devices and OS versions
* Implement proper error handling for network failures
* [Sample Application](https://github.com/auth0-samples/auth0-react-native-sample)
* [Migration Guide (v4 to v5)](https://github.com/auth0/react-native-auth0/blob/master/MIGRATION_GUIDE.md)
# Add Login to Your Expo Application
Source: https://auth0.com/docs/quickstart/native/react-native-expo
This guide demonstrates how to integrate Auth0 with any Expo app using the Auth0 React Native SDK.
This Quickstart is for Expo applications. To integrate Auth0 into your React Native application, refer to the [React Native Quickstart](https://auth0.com/docs/quickstart/native/react-native/interactive).
If you use an AI coding assistant like Claude Code, Cursor, or GitHub Copilot, you can add Auth0 authentication automatically in minutes using [agent skills](https://agentskills.io/home).
**Install:**
```bash theme={null}
npx skills add auth0/agent-skills --skill auth0
```
**Then ask your AI assistant:**
```text theme={null}
Add Auth0 authentication to my Expo app
```
Your AI assistant will automatically create your Auth0 application, fetch credentials, install the react-native-auth0 SDK, configure the Expo plugin, and implement login/logout flows. [Full agent skills documentation →](/docs/quickstart/agent-skills)
## Get Started
Create a new Expo project for this quickstart.
**In your terminal:**
```bash theme={null}
npx create-expo-app Auth0ExpoSample --template blank
cd Auth0ExpoSample
```
This creates a minimal Expo app with the latest SDK, ready for native module integration. The `--template blank` flag provides a clean starting point without additional boilerplate.
This SDK is **NOT compatible with Expo Go** because it requires custom native code. You must use `npx expo run:ios` or `npx expo run:android` to create a development build.
Add the Auth0 React Native SDK to your project.
```bash theme={null}
npx expo install react-native-auth0
```
Using `npx expo install` ensures version compatibility with your Expo SDK version. The SDK auto-configures through the Expo plugin system.
Configure the Auth0 plugin to handle native iOS and Android configuration automatically.
Update your `app.json` to include the Auth0 plugin:
```json app.json lines theme={null}
{
"expo": {
"name": "Auth0ExpoSample",
"slug": "auth0-expo-sample",
"version": "1.0.0",
"ios": {
"bundleIdentifier": "com.auth0.samples.expo",
"supportsTablet": true
},
"android": {
"package": "com.auth0.samples.expo",
"adaptiveIcon": {
"foregroundImage": "./assets/images/adaptive-icon.png",
"backgroundColor": "#ffffff"
}
},
"plugins": [
[
"react-native-auth0",
{
"domain": "{yourDomain}",
"customScheme": "auth0sample"
}
]
]
}
}
```
Replace `{yourDomain}` with your Auth0 domain (you'll get this in the next step).
**Important**: You must define `bundleIdentifier` for iOS and `package` for Android in your `app.json`. These identifiers are required for the Auth0 SDK to configure the native projects properly. If you don't specify a custom scheme, the SDK will use the bundle identifier as the URL scheme.
The `customScheme` must be lowercase with no special characters. This value is used to construct callback URLs and must be passed to `authorize()` and `clearSession()` methods.
Create and configure an Auth0 application to work with your Expo app.
1. Head to the [Auth0 Dashboard](https://manage.auth0.com/dashboard/)
2. Click on **Applications** > **Applications** > **Create Application**
3. In the popup, enter a name for your app (e.g., `Auth0 Expo Sample`), select `Native` as the app type and click **Create**
4. Switch to the **Settings** tab on the Application Details page
5. Note your **Domain** and **Client ID** values
6. Update the `domain` value in your `app.json` plugin configuration with your Auth0 domain
**Allowed Callback URLs:**
```
auth0sample://{yourDomain}/ios/com.auth0.samples.expo/callback,
auth0sample://{yourDomain}/android/com.auth0.samples.expo/callback
```
**Allowed Logout URLs:**
```
auth0sample://{yourDomain}/ios/com.auth0.samples.expo/callback,
auth0sample://{yourDomain}/android/com.auth0.samples.expo/callback
```
Replace `{yourDomain}` with your actual Auth0 domain (e.g., `dev-abc123.us.auth0.com`).
**Allowed Callback URLs** are a critical security measure to ensure users are safely returned to your application after authentication. Without a matching URL, the login process will fail, and users will be blocked by an Auth0 error page instead of accessing your app.
**Allowed Logout URLs** are essential for providing a seamless user experience upon signing out. Without a matching URL, users will not be redirected back to your application after logout and will instead be left on a generic Auth0 page.
The callback URL format is: `{customScheme}://{yourDomain}/{platform}/{bundleIdentifier or packageName}/callback`. The URL scheme uses the `customScheme` from your `app.json`, but the path always contains the `bundleIdentifier` (iOS) or `package` (Android) — not the custom scheme. If you don't specify a `customScheme`, the SDK defaults to `{bundleIdentifier}.auth0` / `{packageName}.auth0` as the URL scheme.
**Important**: Ensure the `customScheme` in your callback URLs matches exactly with the value in your `app.json` plugin configuration, and that the path contains your actual `bundleIdentifier` (iOS) or `package` (Android). Mismatched values will cause authentication to fail.
Setup your main app component based on your chosen implementation approach.
Replace the contents of `App.js` and wrap your application with the `Auth0Provider` component:
```jsx App.js lines theme={null}
import React from 'react';
import {Auth0Provider, useAuth0} from 'react-native-auth0';
import {
StyleSheet,
Text,
View,
Button,
Image,
ActivityIndicator,
} from 'react-native';
function HomeScreen() {
const {authorize, clearSession, user, isLoading} = useAuth0();
const handleLogin = async () => {
try {
await authorize({customScheme: 'auth0sample', scope: 'openid profile email'});
} catch (e) {
console.error('Login error:', e);
}
};
const handleLogout = async () => {
try {
await clearSession({customScheme: 'auth0sample'});
} catch (e) {
console.error('Logout error:', e);
}
};
if (isLoading) {
return (
Loading...
);
}
return (
Auth0 Expo Sample
{user ? (
{user.picture && (
)}
Welcome, {user.name}!{user.email}
) : (
Tap the button below to log in
)}
);
}
export default function App() {
return (
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
padding: 20,
backgroundColor: '#fff',
},
title: {
fontSize: 28,
fontWeight: 'bold',
marginBottom: 20,
color: '#333',
},
subtitle: {
fontSize: 16,
color: '#666',
marginBottom: 30,
textAlign: 'center',
},
loadingText: {
marginTop: 10,
fontSize: 16,
color: '#666',
},
profileContainer: {
alignItems: 'center',
},
avatar: {
width: 100,
height: 100,
borderRadius: 50,
marginBottom: 20,
},
welcomeText: {
fontSize: 22,
fontWeight: '600',
marginBottom: 8,
color: '#333',
},
emailText: {
fontSize: 16,
color: '#666',
marginBottom: 30,
},
loginContainer: {
alignItems: 'center',
},
buttonContainer: {
width: 200,
marginTop: 10,
},
});
```
Replace `{yourDomain}` with your Auth0 domain and `{yourClientId}` with your Client ID from the Auth0 Dashboard.
The `Auth0Provider` initializes the SDK and provides authentication context to all child components via the `useAuth0` hook. The `customScheme` parameter must match the value in your `app.json` plugin configuration.
Replace the contents of `App.js` with a class-based component:
```jsx App.js lines theme={null}
import React, {Component} from 'react';
import {
View,
Text,
Button,
StyleSheet,
ActivityIndicator,
Image,
} from 'react-native';
import Auth0, {Credentials} from 'react-native-auth0';
const auth0 = new Auth0({
domain: '{yourDomain}',
clientId: '{yourClientId}',
});
interface User {
name?: string;
email?: string;
picture?: string;
}
interface AppState {
user: User | null;
isLoading: boolean;
}
class App extends Component<{}, AppState> {
constructor(props: {}) {
super(props);
this.state = {
user: null,
isLoading: true,
};
}
async componentDidMount() {
await this.checkAuthStatus();
}
checkAuthStatus = async () => {
try {
const hasValidCredentials = await auth0.credentialsManager.hasValidCredentials();
if (hasValidCredentials) {
const credentials = await auth0.credentialsManager.getCredentials();
const userInfo = await auth0.auth.userInfo({token: credentials.accessToken});
this.setState({user: userInfo, isLoading: false});
} else {
this.setState({isLoading: false});
}
} catch (e) {
console.error(e);
this.setState({isLoading: false});
}
};
login = async () => {
try {
const credentials: Credentials = await auth0.webAuth.authorize({
scope: 'openid profile email',
}, {customScheme: 'auth0sample'});
await auth0.credentialsManager.saveCredentials(credentials);
const userInfo = await auth0.auth.userInfo({token: credentials.accessToken});
this.setState({user: userInfo});
} catch (e) {
console.error(e);
}
};
logout = async () => {
try {
await auth0.webAuth.clearSession({}, {customScheme: 'auth0sample'});
await auth0.credentialsManager.clearCredentials();
this.setState({user: null});
} catch (e) {
console.error(e);
}
};
render() {
const {user, isLoading} = this.state;
if (isLoading) {
return (
Loading...
);
}
return (
Auth0 Expo Sample
{user ? (
{user.picture && (
)}
Welcome, {user.name}!{user.email}
) : (
Tap the button below to log in
)}
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
padding: 20,
backgroundColor: '#fff',
},
title: {
fontSize: 28,
fontWeight: 'bold',
marginBottom: 20,
color: '#333',
},
subtitle: {
fontSize: 16,
color: '#666',
marginBottom: 30,
textAlign: 'center',
},
loadingText: {
marginTop: 10,
fontSize: 16,
color: '#666',
},
profileContainer: {
alignItems: 'center',
},
avatar: {
width: 100,
height: 100,
borderRadius: 50,
marginBottom: 20,
},
welcomeText: {
fontSize: 22,
fontWeight: '600',
marginBottom: 8,
color: '#333',
},
emailText: {
fontSize: 16,
color: '#666',
marginBottom: 30,
},
loginContainer: {
alignItems: 'center',
},
buttonContainer: {
width: 200,
marginTop: 10,
},
});
export default App;
```
Replace `{yourDomain}` with your Auth0 domain and `{yourClientId}` with your Client ID from the Auth0 Dashboard.
The class-based approach doesn't require the `Auth0Provider` since it uses the `Auth0` class instance directly. The `customScheme` option must be passed as the second parameter to `authorize()` and `clearSession()`.
The `authorize()` method opens Auth0's Universal Login in a secure browser (ASWebAuthenticationSession on iOS, Chrome Custom Tabs on Android). The `clearSession()` method logs the user out and clears both the browser session and stored credentials. The `customScheme` parameter must match the value in your `app.json` plugin configuration.
Build and run your Expo application on a device or emulator.
**First, generate the native iOS and Android projects:**
```bash theme={null}
npx expo prebuild
```
**Then run on your target platform:**
**For iOS:**
```bash theme={null}
npx expo run:ios
```
**For Android:**
```bash theme={null}
npx expo run:android
```
**Expected flow:**
1. App launches showing "Log In" button
2. Tap **Log In** → Browser opens with Auth0 Universal Login
3. Complete login (sign up or sign in)
4. Browser closes → Returns to app automatically
5. User profile displays with name, email, and avatar
If you make changes to the plugin configuration in `app.json`, run `npx expo prebuild --clean` to regenerate the native projects with the updated configuration.
iOS Simulator requires a valid Apple Developer account for ASWebAuthenticationSession. For testing on simulator without an account, use a physical device or Android emulator instead.
**Checkpoint**
You should now have a fully functional Auth0 login experience running on your device or emulator. The app uses secure browser authentication and automatically manages credentials in the device's secure storage.
***
## Troubleshooting & Advanced
### "Invariant Violation: Native module cannot be null"
This error occurs when attempting to use the SDK with Expo Go.
**Solution:**
The Auth0 SDK requires custom native code that isn't available in Expo Go. Use a development build instead:
```bash theme={null}
npx expo run:ios
# or
npx expo run:android
```
### Callback URL mismatch error
**Solution:**
Verify all three of these match exactly:
1. `customScheme` in `app.json` plugin configuration
2. `customScheme` parameter passed to `authorize()` and `clearSession()`
3. Callback URLs in Auth0 Dashboard (Applications → Your App → Settings → Application URIs)
### "PKCE not allowed" error
**Fix:**
1. Go to Auth0 Dashboard → Applications → Your Application
2. Change application type to **Native**
3. Save changes and try again
### Prebuild fails or plugin not applied
**Fix:**
```bash theme={null}
# Clean and regenerate native projects
npx expo prebuild --clean
```
### iOS build fails with Pod errors
**Fix:**
```bash theme={null}
cd ios
pod install --repo-update
cd ..
npx expo run:ios
```
### User cancelled error
Handle gracefully in your login function:
```jsx expandable theme={null}
const handleLogin = async () => {
try {
await authorize({customScheme: 'auth0sample', scope: 'openid profile email'});
} catch (e) {
if (e.message === 'a0.session.user_cancelled') {
// User closed login screen - handle gracefully
console.log('Login cancelled by user');
} else {
console.error('Login failed:', e);
}
}
};
```
### iOS Alert Dialog
On iOS, users see a permission dialog: *"App Name" Wants to Use "auth0.com" to Sign In*. This is expected behavior from `ASWebAuthenticationSession`. Users must tap **Continue** to proceed.
To customize this behavior, you can use ephemeral sessions (disables SSO):
```jsx theme={null}
await authorize({customScheme: 'auth0sample', scope: 'openid profile email'}, {ephemeralSession: true});
```
Use the `getCredentials()` method to retrieve tokens for API calls:
```jsx expandable lines theme={null}
import {useAuth0} from 'react-native-auth0';
const MyComponent = () => {
const {getCredentials} = useAuth0();
const callApi = async () => {
try {
const credentials = await getCredentials();
const response = await fetch('https://your-api.com/endpoint', {
headers: {
Authorization: `Bearer ${credentials.accessToken}`,
},
});
// Handle response
} catch (e) {
console.error('Failed to get credentials', e);
}
};
};
```
Include the `offline_access` scope during login to receive a refresh token: `authorize({customScheme: 'auth0sample', scope: 'openid profile email offline_access'})`. This enables automatic token renewal.
Use `hasValidCredentials()` to check if the user is already logged in:
```jsx expandable lines theme={null}
import {useAuth0} from 'react-native-auth0';
import {useEffect} from 'react';
const App = () => {
const {hasValidCredentials, getCredentials} = useAuth0();
useEffect(() => {
const checkAuth = async () => {
const isLoggedIn = await hasValidCredentials();
if (isLoggedIn) {
const credentials = await getCredentials();
// User is authenticated, load their data
}
};
checkAuth();
}, []);
};
```
For production builds, use EAS Build instead of local development builds.
**Install EAS CLI:**
```bash theme={null}
npm install -g eas-cli
```
**Create `eas.json` in your project root:**
```json eas.json lines theme={null}
{
"cli": {
"version": ">= 3.0.0"
},
"build": {
"development": {
"developmentClient": true,
"distribution": "internal"
},
"preview": {
"distribution": "internal"
},
"production": {}
}
}
```
**Build for production:**
```bash theme={null}
# Build for both platforms
eas build --platform all
# Or build for specific platform
eas build --platform ios
eas build --platform android
```
### Before deploying to production
**Use HTTPS callback URLs** for enhanced security:
```text theme={null}
https://{yourDomain}/ios/{bundleId}/callback
https://{yourDomain}/android/{packageName}/callback
```
**Configure Android App Links** in Auth0 Dashboard:
* Settings → Advanced Settings → Device Settings
* Add your app's SHA-256 fingerprint
**Configure iOS Universal Links:**
* Add Associated Domains capability in Xcode
* Add `webcredentials:{yourDomain}` to Associated Domains
**Review security settings** in Auth0 Dashboard:
* Enable **OIDC Conformant** in Advanced Settings
* Configure **Token Expiration** appropriately
* Set up **Brute Force Protection**
* Test on multiple devices and OS versions
* Implement proper error handling for network failures
For production apps, consider using HTTPS callback URLs with Universal Links (iOS) and App Links (Android) instead of custom schemes for enhanced security.
* [Sample Application](https://github.com/auth0-samples/auth0-react-native-sample/tree/master/00-Login-Expo)
* [Migration Guide (v4 to v5)](https://github.com/auth0/react-native-auth0/blob/master/MIGRATION_GUIDE.md)
# Add login to your UWP application
Source: https://auth0.com/docs/quickstart/native/windows-uwp-csharp
Integrate Auth0 with your Universal Windows Platform application using the Auth0.OidcClient.UWP SDK
# Add login to your UWP application
This guide demonstrates how to integrate Auth0 with a Universal Windows Platform (UWP) application using the Auth0.OidcClient.UWP SDK. By the end, your app will support login, logout, and displaying user profile information.
This guide uses `Auth0.OidcClient.UWP` version 1.x.
***
## Prerequisites
You'll need the following before you start:
* **Visual Studio 2019 (16.11+) or Visual Studio 2022** with the "Universal Windows Platform Development" workload installed
* **Windows 10 SDK 10.0.16299** or later (installed with the UWP workload)
* **An Auth0 account** ([sign up for free](https://auth0.com/signup))
***
## Get Started
You need to set up an Auth0 application in your Auth0 Dashboard so your UWP app can connect.
1. Navigate to the [Auth0 Dashboard](https://manage.auth0.com/) and log in
2. Go to **Applications > Applications** in the left sidebar
3. Select **Create Application**
4. Enter a name for your application (for example, "My UWP App")
5. Select **Native** as the application type
6. Select **Create**
7. Go to the **Settings** tab on the Application Details page
8. Note your **Domain** and **Client ID** at the top of the page—you'll need these in your code
Note the Domain and Client ID values — you need these later
Next, configure your callback URL:
1. On the Settings tab, scroll down to **Application URIs**
2. In the **Allowed Callback URLs** field, enter: `https://{yourDomain}/mobile`
* Example: `https://mycompany.auth0.com/mobile`
3. In the **Allowed Logout URLs** field, enter the same URL: `https://{yourDomain}/mobile`
4. Select **Save Changes**
The callback URL pattern `https://{yourDomain}/mobile` is Auth0's standard for native applications. Your UWP app will automatically handle the redirect - no custom configuration needed.
If you already have a UWP project, skip to Step 3.
1. Open Visual Studio
2. Select **File > New > Project**
3. Search for "UWP" and select **Blank App (Universal Windows)**
4. Name your project (for example, "Auth0Sample")
5. Select **Next**
6. For "Minimum version," select **Windows 10 (version 1909)** or later
7. For "Target version," select the latest available (currently Windows 11)
8. Select **Create**
Visual Studio creates your UWP project with a basic `MainPage.xaml` and `MainPage.xaml.cs`.
Add the Auth0.OidcClient.UWP NuGet package to your project.
**Using Package Manager UI (Recommended):**
1. Right-click your project in Solution Explorer
2. Select **Manage NuGet Packages**
3. Go to the **Browse** tab
4. Search for "Auth0.OidcClient.UWP"
5. Select the latest version and click **Install**
6. Accept any dependency prompts
**Or using Package Manager Console:**
```powershell theme={null}
Install-Package Auth0.OidcClient.UWP
```
**Or using dotnet CLI:**
```bash theme={null}
dotnet add package Auth0.OidcClient.UWP
```
Verify the installation completed without errors. If you see error messages, check your internet connection and try again.
Now you'll add login and logout buttons to your app. Update your `MainPage.xaml` and `MainPage.xaml.cs`.
First, update `MainPage.xaml`:
```xaml theme={null}
```
Now update `MainPage.xaml.cs`:
```csharp theme={null}
using Auth0.OidcClient;
using System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
namespace Auth0Sample
{
public sealed partial class MainPage : Page
{
private Auth0Client _auth0Client;
public MainPage()
{
InitializeComponent();
InitializeAuth0();
}
private void InitializeAuth0()
{
_auth0Client = new Auth0Client(new Auth0ClientOptions
{
Domain = "{yourDomain}",
ClientId = "{yourClientId}",
RedirectUri = "https://{yourDomain}/mobile",
PostLogoutRedirectUri = "https://{yourDomain}/mobile"
});
}
private async void LoginButton_Click(object sender, RoutedEventArgs e)
{
try
{
var loginResult = await _auth0Client.LoginAsync();
if (loginResult.IsError)
{
if (loginResult.Error == "UserCancel")
{
UserInfoText.Text = "Login cancelled";
return;
}
UserInfoText.Text = $"Login failed: {loginResult.Error}";
return;
}
var userEmail = loginResult.User.FindFirst("email")?.Value ?? "Unknown";
var userName = loginResult.User.FindFirst("name")?.Value ?? "User";
UserInfoText.Text = $"Welcome, {userName}!\nEmail: {userEmail}";
LoginButton.Visibility = Visibility.Collapsed;
LogoutButton.Visibility = Visibility.Visible;
}
catch (Exception ex)
{
UserInfoText.Text = $"Error: {ex.Message}";
}
}
private async void LogoutButton_Click(object sender, RoutedEventArgs e)
{
try
{
await _auth0Client.LogoutAsync();
UserInfoText.Text = "You have been logged out";
LoginButton.Visibility = Visibility.Visible;
LogoutButton.Visibility = Visibility.Collapsed;
}
catch (Exception ex)
{
UserInfoText.Text = $"Logout error: {ex.Message}";
}
}
}
}
```
Replace the placeholders in the code:
* `{yourDomain}` - Your Auth0 domain (e.g., `mycompany.auth0.com`)
* `{yourClientId}` - Your Auth0 application Client ID
* `Auth0Sample` - Your actual project name (match your UWP project name)
Press **F5** or select **Debug > Start Debugging** to launch your app.
**Expected behavior:**
1. Your UWP app launches and shows a "Login" button
2. You tap **Login** → A browser window opens showing the Auth0 login page
3. Enter your Auth0 credentials (or create a test account)
4. After login, the browser closes automatically
5. Your app shows your name and email
6. The button changes to "Logout"
7. You tap **Logout** → The browser opens briefly, then closes
8. The button changes back to "Login"
If the login page doesn't appear, verify your Domain and ClientId are correct, your Allowed Callback URL in Auth0 Dashboard matches `https://{yourDomain}/mobile`, and your internet connection is working.
**Checkpoint**
You now have a fully functional Auth0 login experience in your UWP application.
***
## Troubleshooting
**Problem:** Network connectivity issue or invalid configuration.
**Solution:**
1. Check your internet connection
2. Verify your Domain is exactly correct (e.g., `mycompany.auth0.com`)
3. Verify your ClientId is exactly correct (no spaces or typos)
4. Make sure you're running on Windows 10 (Fall Creators Update) or later
**Problem:** The redirect URL in your Auth0 application doesn't match the one in your code.
**Solution:**
1. Go to Auth0 Dashboard > Applications > Your App > Settings
2. Scroll to "Application URIs"
3. Check that "Allowed Callback URLs" contains: `https://{yourDomain}/mobile`
4. Verify this matches the `RedirectUri` in your code exactly
5. Click **Save Changes** if you made any edits
**Problem:** Missing using statements or incorrect namespace references.
**Solution:**
1. Make sure you have `using Auth0.OidcClient;` at the top of MainPage.xaml.cs
2. Rebuild the solution (Build > Rebuild Solution)
**Problem:** Your refresh token expired or the cached credentials are invalid.
**Solution:**
1. Tap **Logout** to clear cached tokens
2. Tap **Login** again and re-authenticate
3. If the problem persists, go to Auth0 Dashboard and clear your app's refresh tokens
**Problem:** The `profile` scope wasn't requested, so user claims aren't available.
**Solution:**
1. Update your Auth0ClientOptions to request the profile scope:
```csharp theme={null}
var options = new Auth0ClientOptions
{
Domain = "{yourDomain}",
ClientId = "{yourClientId}",
Scope = "openid profile email" // Add this line
};
```
2. Log out and log in again to get the updated scopes
***
## Next Steps
You now have a working Auth0 integration in your UWP application. Explore these topics to extend your implementation:
Use your access token to authenticate requests to a backend API
Maintain user sessions across app restarts
Support multi-tenant, B2B applications
Match Auth0's login page to your brand
Control user permissions based on roles
***
## Additional Resources
SDK source code and documentation on GitHub
Learn how OpenID Connect works with Auth0
Security best practices for access tokens
# Add Login to Your WPF or WinForms Application
Source: https://auth0.com/docs/quickstart/native/wpf-winforms
Add Auth0 login, logout, and user profile to a WPF or WinForms application using the Auth0 OIDC Client for .NET
If you use an AI coding assistant like Claude Code, Cursor, or GitHub Copilot, you can add Auth0 authentication automatically in minutes using [agent skills](https://agentskills.io/home).
**Install:**
```bash theme={null}
npx skills add auth0/agent-skills --skill auth0
```
**Then ask your AI assistant:**
```text theme={null}
Add Auth0 authentication to my WPF or WinForms app
```
Your AI assistant will automatically create your Auth0 application, fetch credentials, install the Auth0 OidcClient SDK, configure callback URLs, and implement login/logout flows. [Full agent skills documentation →](/docs/quickstart/agent-skills)
**Prerequisites:** Before you begin, ensure you have the following:
* **[.NET 8.0 SDK](https://dotnet.microsoft.com/download/dotnet/8.0)** or higher (or .NET Framework 4.6.2 for legacy projects)
* **[Visual Studio 2022](https://visualstudio.microsoft.com/)** or VS Code with the C# Dev Kit
**.NET Version Compatibility:** This quickstart works with **.NET 8.0**, **.NET 9.0**, and **.NET Framework 4.6.2**.
## Get Started
This quickstart demonstrates how to add Auth0 authentication to a WPF or WinForms desktop application. You'll configure Auth0, install the SDK, and add login, logout, and user profile display using the Auth0 OIDC Client for [WPF](https://www.nuget.org/packages/Auth0.OidcClient.WPF/) and [WinForms](https://www.nuget.org/packages/Auth0.OidcClient.WinForms/).
If you already have a WPF or WinForms project, skip to the next step.
Create a new project and open its directory:
```bash theme={null}
dotnet new wpf -n MyApp
cd MyApp
```
```bash theme={null}
dotnet new winforms -n MyApp
cd MyApp
```
1. Open Visual Studio 2022 and click **Create a new project**
2. Search for **WPF Application** or **Windows Forms App**
3. Select the C# template and click **Next**
4. Enter a project name and choose a location, then click **Next**
5. Select **.NET 8.0** (or higher) as the target framework and click **Create**
To use Auth0 services, you need to have an application set up in the Auth0 Dashboard. The Auth0 application is where you configure how authentication works for your project.
### Configure an application
Go to [Auth0 Dashboard](https://manage.auth0.com) → **Applications** → **Applications** and create a new application:
1. Click **Create Application**
2. Enter a name for your application
3. Select **Native** as the application type
4. Click **Create**
From the **Settings** tab, note your **Domain** and **Client ID** — you'll need these to initialize the SDK.
### Configure Callback URLs
A callback URL is a URL in your application where Auth0 redirects users after they have authenticated. If not set, users will not be returned to your application after they log in.
In your Application Settings, add the following to **Allowed Callback URLs**:
```
https://{yourDomain}/mobile
```
### Configure Logout URLs
A logout URL is a URL in your application where Auth0 redirects users after they have logged out. If not set, users will not be able to log out from your application and will receive an error.
In your Application Settings, add the following to **Allowed Logout URLs**:
```
https://{yourDomain}/mobile
```
Auth0 provides separate NuGet packages for WPF and WinForms. Install the one that matches your project type.
Open the **Package Manager Console** (Tools → NuGet Package Manager → Package Manager Console) and run:
```powershell theme={null}
# WPF
Install-Package Auth0.OidcClient.WPF
# WinForms
Install-Package Auth0.OidcClient.WinForms
```
```bash theme={null}
# WPF
dotnet add package Auth0.OidcClient.WPF
# WinForms
dotnet add package Auth0.OidcClient.WinForms
```
To integrate Auth0 into your application, instantiate an `Auth0Client` with your Auth0 **Domain** and **Client ID**. Add a private field and initialize it inside the existing constructor in your main window or form.
Open `MainWindow.xaml.cs` and update it as follows:
```csharp MainWindow.xaml.cs lines theme={null}
using Auth0.OidcClient;
// In case you have chosen a different name for your application,
// ensure to update the namespace accordingly.
namespace MyApp;
public partial class MainWindow : Window
{
private Auth0Client _client;
public MainWindow()
{
InitializeComponent();
_client = new Auth0Client(new Auth0ClientOptions
{
Domain = "{yourDomain}",
ClientId = "{yourClientId}"
});
}
}
```
Open `Form1.cs` (or your main form file) and update it as follows:
```csharp Form1.cs lines theme={null}
using Auth0.OidcClient;
// In case you have chosen a different name for your application,
// ensure to update the namespace accordingly.
namespace MyApp;
public partial class Form1 : Form
{
private Auth0Client _client;
public Form1()
{
InitializeComponent();
_client = new Auth0Client(new Auth0ClientOptions
{
Domain = "{yourDomain}",
ClientId = "{yourClientId}"
});
}
}
```
Use the SDK's `LoginAsync()` method to log users in. When called, it opens a popup window with the Auth0 Universal Login page. After successful authentication, Auth0 redirects to the callback URL, and the SDK returns a `LoginResult`.
First, add a login button to your UI:
Open `MainWindow.xaml` and add a `Button` inside the ``:
```xml MainWindow.xaml lines theme={null}
```
Then add the click handler in `MainWindow.xaml.cs`:
```csharp MainWindow.xaml.cs lines theme={null}
private async void LoginButton_Click(object sender, RoutedEventArgs e)
{
var loginResult = await _client.LoginAsync();
if (loginResult.IsError == false)
{
var user = loginResult.User;
var name = user.FindFirst(c => c.Type == "name")?.Value;
var email = user.FindFirst(c => c.Type == "email")?.Value;
var picture = user.FindFirst(c => c.Type == "picture")?.Value;
}
}
```
Open `Form1.cs` and add the login button programmatically in the constructor, then add the click handler:
```csharp Form1.cs lines theme={null}
using Auth0.OidcClient;
namespace MyApp;
public partial class Form1 : Form
{
private Auth0Client _client;
private Button loginButton;
public Form1()
{
InitializeComponent();
_client = new Auth0Client(new Auth0ClientOptions
{
Domain = "{yourDomain}",
ClientId = "{yourClientId}"
});
loginButton = new Button
{
Text = "Log In",
Width = 120,
Height = 40,
Left = (ClientSize.Width - 120) / 2,
Top = (ClientSize.Height - 40) / 2
};
loginButton.Click += loginButton_Click;
Controls.Add(loginButton);
}
private async void loginButton_Click(object sender, EventArgs e)
{
var loginResult = await _client.LoginAsync();
if (loginResult.IsError == false)
{
var user = loginResult.User;
var name = user.FindFirst(c => c.Type == "name")?.Value;
var email = user.FindFirst(c => c.Type == "email")?.Value;
var picture = user.FindFirst(c => c.Type == "picture")?.Value;
}
}
}
```
If there is no error, you can access `LoginResult.User`, `LoginResult.IdentityToken`, `LoginResult.AccessToken`, and `LoginResult.RefreshToken` on the result.
Use the SDK's `LogoutAsync()` method to log users out. This opens a popup window, redirects to Auth0's logout endpoint to clear the session, then redirects back to the logout URL you configured.
First, add a logout button to your UI:
Open `MainWindow.xaml` and add a logout `Button` next to the login button:
```xml MainWindow.xaml lines theme={null}
```
Then add the click handler in `MainWindow.xaml.cs`:
```csharp MainWindow.xaml.cs lines theme={null}
private async void LogoutButton_Click(object sender, RoutedEventArgs e)
{
await _client.LogoutAsync();
}
```
Open `Form1.cs` and add the logout button in the constructor, then add its click handler:
```csharp Form1.cs lines theme={null}
private Button logoutButton;
public Form1()
{
// ... existing constructor code ...
logoutButton = new Button
{
Text = "Log Out",
Width = 120,
Height = 40,
Left = (ClientSize.Width - 120) / 2,
Top = (ClientSize.Height - 40) / 2 + 50
};
logoutButton.Click += logoutButton_Click;
Controls.Add(logoutButton);
}
private async void logoutButton_Click(object sender, EventArgs e)
{
await _client.LogoutAsync();
}
```
The `LoginResult.User` property is a [ClaimsPrincipal](https://learn.microsoft.com/en-us/dotnet/api/system.security.claims.claimsprincipal) containing the authenticated user's profile. Query the claims to display user information in your application.
```csharp lines theme={null}
if (loginResult.IsError == false)
{
Debug.WriteLine($"name: {loginResult.User.FindFirst(c => c.Type == "name")?.Value}");
Debug.WriteLine($"email: {loginResult.User.FindFirst(c => c.Type == "email")?.Value}");
}
```
To see all claims returned in the ID token:
```csharp lines theme={null}
if (loginResult.IsError == false)
{
foreach (var claim in loginResult.User.Claims)
{
Debug.WriteLine($"{claim.Type} = {claim.Value}");
}
}
```
**Checkpoint**
You should now have a working Auth0-integrated WPF or WinForms application. Run your application and verify that:
* Clicking the login button opens the Auth0 Universal Login page in a popup window.
* You can log in or sign up.
* After authentication, you can access user information from `LoginResult.User`.
* Clicking the logout button clears the session and redirects to your logout URL.
***
## Advanced Usage
Check `LoginResult.IsError` before accessing tokens or user properties. The `Error` and `ErrorDescription` properties contain details when authentication fails.
```csharp lines theme={null}
var loginResult = await _client.LoginAsync();
if (loginResult.IsError)
{
Debug.WriteLine($"An error occurred during login: {loginResult.Error}");
// loginResult.ErrorDescription contains the full error message
return;
}
// Safe to access tokens and user here
Debug.WriteLine($"id_token: {loginResult.IdentityToken}");
Debug.WriteLine($"access_token: {loginResult.AccessToken}");
```
If the user closes the login popup without authenticating, `LoginAsync()` returns a result with `BrowserResultType.UserCancel`. This is expected behavior — do not treat it as an error.
To get a new access token without requiring the user to log in again, use `RefreshTokenAsync()` with the refresh token from the initial `LoginResult`.
```csharp lines theme={null}
// Request offline_access scope to receive a refresh token
_client = new Auth0Client(new Auth0ClientOptions
{
Domain = "{yourDomain}",
ClientId = "{yourClientId}",
Scope = "openid profile email offline_access"
});
// Store refresh token from initial login
var refreshToken = loginResult.RefreshToken;
// Exchange for new tokens later
var refreshResult = await _client.RefreshTokenAsync(refreshToken);
if (refreshResult.IsError == false)
{
var newAccessToken = refreshResult.AccessToken;
}
```
Refresh tokens require the `offline_access` scope and must be enabled in your Auth0 Application Settings under **Refresh Token Rotation**.
***
## Additional Resources
Source code, release notes, and issue tracker for the Auth0 OIDC Client for .NET
Learn about user profile claims and the /userinfo endpoint
Get help from the Auth0 community
***
## Common Issues
**Problem:** The WebView2 popup window opens and shows the login page, but after entering credentials nothing happens.
**Solution:** The Microsoft Edge WebView2 Runtime is not installed on the machine. Install it from the [Microsoft WebView2 download page](https://developer.microsoft.com/en-us/microsoft-edge/webview2/). WebView2 ships with Windows 11 and recent Windows 10 builds, but must be separately installed on older systems.
**Problem:** After logging in, Auth0 returns a `callback URL mismatch` error.
**Solution:** The redirect URI used by the SDK does not match any value in your **Allowed Callback URLs** in the Auth0 Dashboard. Add `https://{yourDomain}/mobile` to Allowed Callback URLs in your Application Settings. The SDK uses this URL by default.
**Problem:** After logging out, Auth0 returns an error about an unrecognized logout URL.
**Solution:** Add `https://{yourDomain}/mobile` to **Allowed Logout URLs** in your Application Settings.
**Problem:** `LoginResult.IsError` is `true` but there is no clear indication of the cause.
**Solution:** Check `LoginResult.Error` and `LoginResult.ErrorDescription` for details:
```csharp lines theme={null}
if (loginResult.IsError)
{
Debug.WriteLine($"Error: {loginResult.Error}");
Debug.WriteLine($"Description: {loginResult.ErrorDescription}");
}
```
Common causes:
* The application type in the Auth0 Dashboard is not set to **Native**
* **OIDC Conformant** is not enabled under Advanced Settings → OAuth
* The **JSON Web Token Signature Algorithm** is not set to **RS256**
**Problem:** `LoginResult.RefreshToken` is `null`.
**Solution:** The `offline_access` scope is required to receive a refresh token. Add it to the `Scope` option:
```csharp lines theme={null}
_client = new Auth0Client(new Auth0ClientOptions
{
Domain = "{yourDomain}",
ClientId = "{yourClientId}",
Scope = "openid profile email offline_access"
});
```
Also ensure **Refresh Token Rotation** is enabled in your Application Settings in the Auth0 Dashboard.
# Add Login to Your Angular Application
Source: https://auth0.com/docs/quickstart/spa/angular
This guide demonstrates how to integrate Auth0, add authentication, and display user profile information in any Angular application using the Auth0 Angular SDK.
If you use an AI coding assistant like Claude Code, Cursor, or GitHub Copilot, you can add Auth0 authentication automatically in minutes using [agent skills](https://agentskills.io/home).
**Install:**
```bash theme={null}
npx skills add auth0/agent-skills --skill auth0
```
**Then ask your AI assistant:**
```text theme={null}
Add Auth0 authentication to my Angular app
```
Your AI assistant will automatically create your Auth0 application, fetch credentials, install `@auth0/auth0-angular`, create route guards and HTTP interceptors, and configure your environment. [Full agent skills documentation →](/docs/quickstart/agent-skills)
**Prerequisites:** Before you begin, ensure you have the following installed:
* **[Node.js](https://nodejs.org/en/download)** 20 LTS or newer
* **[npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm)** 10+ or **[yarn](https://classic.yarnpkg.com/lang/en/docs/install/)** 1.22+ or **[pnpm](https://pnpm.io/installation)** 8+
* **[jq](https://jqlang.org/)** - Required for Auth0 CLI setup
Verify installation: `node --version && npm --version`
**Angular Version Compatibility:** This quickstart works with **Angular 19 through 21** using the Angular CLI. The `@auth0/auth0-angular` SDK supports Angular 13 and newer.
## Get Started
This quickstart demonstrates how to add Auth0 authentication to an Angular application. You'll build a secure single-page app with login and logout functionality using Angular's dependency injection system and the Auth0 Angular SDK.
Create a new Angular project for this Quickstart
```shellscript theme={null}
npx @angular/cli@latest new auth0-angular --routing=true --style=css
```
Open the project
```shellscript theme={null}
cd auth0-angular
```
```shellscript theme={null}
npm install @auth0/auth0-angular && npm install
```
Next up, you need to create a new app on your Auth0 tenant and add the environment variables to your project.
You have three options to set up your Auth0 app: use the Quick Setup tool (recommended), run a CLI command, or configure manually via the Dashboard:
Create an Auth0 App and copy the pre-filled `.env` file with the right configuration values.
Run the following shell command on your project's root directory to create an Auth0 app and generate an environment file:
```shellscript Mac theme={null}
# Install Auth0 CLI (if not already installed)
brew tap auth0/auth0-cli && brew install auth0
# Set up Auth0 app and generate environment file
auth0 qs setup --app --type spa --framework angular --name "My Angular App" --port 4200
```
```powershell Windows theme={null}
# Install Auth0 CLI (if not already installed)
scoop bucket add auth0 https://github.com/auth0/scoop-auth0-cli.git
scoop install auth0
# Set up Auth0 app and generate environment file
auth0 qs setup --app --type spa --framework angular --name "My Angular App" --port 4200
```
This command will:
1. Check if you're authenticated (and prompt for login if needed)
2. Create an Auth0 Single Page Application configured for `http://localhost:4200`
3. Generate `src/environments/environment.ts` with your Auth0 domain and client ID
Before you start, create an environment file on your project
```typescript src/environments/environment.ts theme={null}
export const environment = {
production: false,
auth0: {
domain: 'YOUR_AUTH0_APP_DOMAIN',
clientId: 'YOUR_AUTH0_APP_CLIENT_ID'
}
};
```
1. Head to the [Auth0 Dashboard](https://manage.auth0.com/dashboard/)
2. Click on **Applications** > **Applications** > **Create Application**
3. In the popup, enter a name for your app, select `Single Page Web Application` as the app type and click **Create**
4. Switch to the **Settings** tab on the Application Details page
5. Replace `YOUR_AUTH0_APP_DOMAIN` and `YOUR_AUTH0_APP_CLIENT_ID` in the `src/environments/environment.ts` file with the **Domain** and **Client ID** values from the dashboard
Finally, on the **Settings** tab of your Application Details page, configure the following URLs:
**Allowed Callback URLs:**
```
http://localhost:4200
```
**Allowed Logout URLs:**
```
http://localhost:4200
```
**Allowed Web Origins:**
```
http://localhost:4200
```
**Allowed Callback URLs** are a critical security measure to ensure users are safely returned to your application after authentication. Without a matching URL, the login process will fail, and users will be blocked by an Auth0 error page instead of accessing your app.
**Allowed Logout URLs** are essential for providing a seamless user experience upon signing out. Without a matching URL, users will not be redirected back to your application after logout and will instead be left on a generic Auth0 page.
**Allowed Web Origins** is critical for silent authentication. Without it, users will be logged out when they refresh the page or return to your app later.
With your environment file in place from the previous step, add `provideAuth0` to the providers array in your `app.config.ts`:
```typescript src/app/app.config.ts {3,4,5,11-17} lines theme={null}
import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
import { provideRouter } from '@angular/router';
import { provideAuth0 } from '@auth0/auth0-angular';
import { environment } from '../environments/environment';
import { routes } from './app.routes';
export const appConfig: ApplicationConfig = {
providers: [
provideZoneChangeDetection({ eventCoalescing: true }),
provideRouter(routes),
provideAuth0({
domain: environment.auth0.domain,
clientId: environment.auth0.clientId,
authorizationParams: {
redirect_uri: window.location.origin
}
})
]
};
```
If you set up your Auth0 app manually via the dashboard, create `src/environments/environment.ts` with your domain and client ID from the dashboard.
Angular 20+ projects also include `provideBrowserGlobalErrorListeners()` in this file — keep it in the array alongside `provideAuth0`. No changes to `main.ts` are needed.
Use the Angular CLI to scaffold the component files:
```shellscript theme={null}
ng generate component components/login-button --inline-template --inline-style --skip-tests && \
ng generate component components/logout-button --inline-template --inline-style --skip-tests && \
ng generate component components/profile --inline-template --inline-style --skip-tests
```
Add the following code to each component:
```typescript src/app/components/login-button.component.ts expandable lines theme={null}
import { Component, inject } from '@angular/core';
import { AuthService } from '@auth0/auth0-angular';
@Component({
selector: 'app-login-button',
standalone: true,
template: `
`
})
export class LoginButtonComponent {
private auth = inject(AuthService);
loginWithRedirect(): void {
this.auth.loginWithRedirect();
}
}
```
```typescript src/app/components/logout-button.component.ts expandable lines theme={null}
import { Component, inject } from '@angular/core';
import { AuthService } from '@auth0/auth0-angular';
@Component({
selector: 'app-logout-button',
standalone: true,
template: `
`
})
export class LogoutButtonComponent {
private auth = inject(AuthService);
logout(): void {
this.auth.logout({
logoutParams: {
returnTo: window.location.origin
}
});
}
}
```
```typescript src/app/components/profile.component.ts expandable lines theme={null}
import { Component, inject } from '@angular/core';
import { AuthService } from '@auth0/auth0-angular';
import { CommonModule } from '@angular/common';
@Component({
selector: 'app-profile',
standalone: true,
imports: [CommonModule],
template: `
@if (auth.isLoading$ | async) {
`;
// Auto-hide success and info messages after 5 seconds
if (type === 'success' || type === 'info') {
setTimeout(() => {
statusDiv.innerHTML = '';
}, 5000);
}
}
showRPCResult(title, data) {
const resultsDiv = document.getElementById('rpc-results');
const resultHtml = `
${title}
${JSON.stringify(data, null, 2)}
`;
resultsDiv.innerHTML = resultHtml;
this.showStatus('✅ RPC call completed successfully', 'success');
}
}
// Initialize the application
const app = new CapnWebAuth0Client();
app.init().catch(error => {
// Initialize app when DOM is loaded
document.addEventListener('DOMContentLoaded', initializeApp);
Step 7: Test and Run the Application
7.1: Start the development server:
npm run start
7.2: Open http://localhost:3000 in your browser
7.3: Test the complete authentication flow:
- Click "Login" to authenticate with Auth0
- View your profile information (email will be displayed from Auth0)
- Update your bio and save
- Refresh the page - you should remain logged in (thanks to refresh tokens)
- Test logout functionality
- Test RPC calls (Get Profile, Update Profile, Get Public Data)
- Verify WebSocket connection status
- Test logout functionality
SECURITY REQUIREMENTS & BEST PRACTICES
- ✅ NEVER accept unauthenticated RPC calls for protected methods
- ✅ ALWAYS validate JWT signatures using JWKS from Auth0
- ✅ Implement comprehensive error handling for expired/invalid tokens
- ✅ Use environment variables for all sensitive configuration
- ✅ Validate all user inputs before processing
- ✅ Log security events and authentication attempts
- ✅ Use secure WebSocket connections (WSS) in production
- ✅ Implement proper CORS policies
- ✅ Add request rate limiting for production use
- ✅ Sanitize all data before storage or transmission
TROUBLESHOOTING TIPS
- Check browser console for JavaScript errors
- Verify .env file contains correct Auth0 configuration
- Ensure Auth0 application settings match your local URLs
- Confirm API scopes are properly configured in Auth0 dashboard
- Test WebSocket connectivity separately if RPC calls fail
- Validate JWT tokens using jwt.io for debugging
```
## Get Started
This quickstart demonstrates how to add Auth0 authentication to a Cap'n Web application. You'll build a modern RPC-based web application with secure login functionality using Cap'n Web's JavaScript framework and the Auth0 SPA SDK.
Create a new Cap'n Web project and set up the basic structure:
```shellscript theme={null}
mkdir capnweb-auth0-app && cd capnweb-auth0-app
```
Initialize the project and configure it for ES modules:
```shellscript theme={null}
npm init -y && npm pkg set type="module"
```
Create the project folder structure:
```shellscript theme={null}
mkdir -p client server && touch server/index.js client/index.html client/app.js .env.example .env
```
Install Cap'n Web and core dependencies:
```shellscript theme={null}
npm install capnweb ws dotenv
```
Install the Auth0 SDKs for authentication and token verification:
```shellscript theme={null}
npm install @auth0/auth0-spa-js @auth0/auth0-api-js
```
**@auth0/auth0-spa-js** is used on the client side to handle user authentication, login flows, and token management in the browser.
**@auth0/auth0-api-js** is used on the server side to verify access tokens and validate JWT signatures using Auth0's JWKS.
Set up the start script in package.json:
```shellscript theme={null}
npm pkg set scripts.start="node server/index.js"
```
Next up, you need to create a new app on your Auth0 tenant and add the environment variables to your project.
You can choose to do this automatically by running a CLI command or do it manually via the Dashboard:
Run the following shell command on your project's root directory to create an Auth0 app and generate a `.env` file:
```shellscript Mac theme={null}
AUTH0_APP_NAME="My Cap'n Web App" && AUTH0_API_NAME="Cap'n Web API" && AUTH0_API_IDENTIFIER="https://capnweb-api.$(date +%s).com" && brew tap auth0/auth0-cli && brew install auth0 && auth0 login --no-input && auth0 apis create --name "${AUTH0_API_NAME}" --identifier "${AUTH0_API_IDENTIFIER}" --scopes "read:profile,write:profile" --json > auth0-api-details.json && auth0 apps create -n "${AUTH0_APP_NAME}" -t spa -c http://localhost:3000 -l http://localhost:3000 -o http://localhost:3000 --json > auth0-app-details.json && CLIENT_ID=$(jq -r '.client_id' auth0-app-details.json) && DOMAIN=$(auth0 tenants list --json | jq -r '.[] | select(.active == true) | .name') && echo "AUTH0_DOMAIN=${DOMAIN}" > .env && echo "AUTH0_CLIENT_ID=${CLIENT_ID}" >> .env && echo "AUTH0_AUDIENCE=${AUTH0_API_IDENTIFIER}" >> .env && echo "PORT=3000" >> .env && echo "NODE_ENV=development" >> .env && rm auth0-app-details.json auth0-api-details.json && echo ".env file created with your Auth0 details:" && cat .env
```
```shellscript Windows theme={null}
$AppName = "My Cap'n Web App"; $ApiName = "Cap'n Web API"; $ApiIdentifier = "https://capnweb-api.$((Get-Date).Ticks).com"; winget install Auth0.CLI; auth0 login --no-input; auth0 apis create --name "$ApiName" --identifier "$ApiIdentifier" --scopes "read:profile,write:profile" --json | Set-Content -Path auth0-api-details.json; auth0 apps create -n "$AppName" -t spa -c http://localhost:3000 -l http://localhost:3000 -o http://localhost:3000 --json | Set-Content -Path auth0-app-details.json; $ClientId = (Get-Content -Raw auth0-app-details.json | ConvertFrom-Json).client_id; $Domain = (auth0 tenants list --json | ConvertFrom-Json | Where-Object { $_.active -eq $true }).name; Set-Content -Path .env -Value "AUTH0_DOMAIN=$Domain"; Add-Content -Path .env -Value "AUTH0_CLIENT_ID=$ClientId"; Add-Content -Path .env -Value "AUTH0_AUDIENCE=$ApiIdentifier"; Add-Content -Path .env -Value "PORT=3000"; Add-Content -Path .env -Value "NODE_ENV=development"; Remove-Item auth0-app-details.json, auth0-api-details.json; Write-Output ".env file created with your Auth0 details:"; Get-Content .env
```
Before you start, create a `.env` file on your project's root directory
```shellscript .env theme={null}
AUTH0_DOMAIN=YOUR_AUTH0_APP_DOMAIN
AUTH0_CLIENT_ID=YOUR_AUTH0_APP_CLIENT_ID
AUTH0_AUDIENCE=https://capnweb-api.yourproject.com
PORT=3000
NODE_ENV=development
```
1. Head to the [Auth0 Dashboard](https://manage.auth0.com/dashboard/)
2. Click on **Applications** > **Applications** > **Create Application**
3. In the popup, enter a name for your app, select `Single Page Web Application` as the app type and click **Create**
4. Switch to the **Settings** tab on the Application Details page
5. Replace `YOUR_AUTH0_APP_DOMAIN` and `YOUR_AUTH0_APP_CLIENT_ID` on the `.env` file with the **Domain** and **Client ID** values from the dashboard
Finally, on the **Settings** tab of your Application Details page, configure the following URLs:
**Allowed Callback URLs:**
```
http://localhost:3000
```
**Allowed Logout URLs:**
```
http://localhost:3000
```
**Allowed Web Origins:**
```
http://localhost:3000
```
**Allowed Callback URLs** are a critical security measure to ensure users are safely returned to your application after authentication. Without a matching URL, the login process will fail, and users will be blocked by an Auth0 error page instead of accessing your app.
**Allowed Logout URLs** are essential for providing a seamless user experience upon signing out. Without a matching URL, users will not be redirected back to your application after logout and will instead be left on a generic Auth0 page.
**Allowed Web Origins** is critical for silent authentication. Without it, users will be logged out when they refresh the page or return to your app later.
**Required: Create an Auth0 API**
You must create an Auth0 API for token validation to work:
1. In the Auth0 Dashboard, go to **APIs** > **Create API**
2. Set these values:
* **Name**: `Cap'n Web API`
* **Identifier**: `https://capnweb-api.yourproject.com` (use your own unique identifier)
* **Signing Algorithm**: `RS256` (default)
3. Click **Create**
4. In the **Scopes** tab, add these scopes:
* `read:profile` - Read user profile data
* `write:profile` - Update user profile data
5. Update your `.env` file with the API identifier as `AUTH0_AUDIENCE`
Without creating an Auth0 API, you'll get an "access\_denied" error during login. The API identifier must match your `AUTH0_AUDIENCE` environment variable exactly.
Create the Cap'n Web server with Auth0 integration:
```javascript server/index.js expandable lines theme={null}
import { RpcTarget, newWebSocketRpcSession } from 'capnweb';
import { WebSocketServer } from 'ws';
import { ApiClient } from '@auth0/auth0-api-js';
import http from 'http';
import { readFileSync } from 'fs';
import { dirname, join } from 'path';
import { fileURLToPath } from 'url';
import dotenv from 'dotenv';
dotenv.config();
const __dirname = dirname(fileURLToPath(import.meta.url));
const userProfiles = new Map();
// Auth0 configuration
const AUTH0_DOMAIN = process.env.AUTH0_DOMAIN;
const AUTH0_CLIENT_ID = process.env.AUTH0_CLIENT_ID;
const AUTH0_AUDIENCE = process.env.AUTH0_AUDIENCE;
const PORT = process.env.PORT || 3000;
if (!AUTH0_DOMAIN || !AUTH0_CLIENT_ID || !AUTH0_AUDIENCE) {
console.error('❌ Missing required Auth0 environment variables');
if (!AUTH0_DOMAIN) console.error(' - AUTH0_DOMAIN is required');
if (!AUTH0_CLIENT_ID) console.error(' - AUTH0_CLIENT_ID is required');
if (!AUTH0_AUDIENCE) console.error(' - AUTH0_AUDIENCE is required');
process.exit(1);
}
// Initialize Auth0 API client for token verification
const auth0ApiClient = new ApiClient({
domain: AUTH0_DOMAIN,
audience: AUTH0_AUDIENCE
});
async function verifyToken(token) {
try {
const payload = await auth0ApiClient.verifyAccessToken({
accessToken: token
});
return payload;
} catch (error) {
throw new Error(`Token verification failed: ${error.message}`);
}
}
// Profile Service - Cap'n Web RPC Target
class ProfileService extends RpcTarget {
async getProfile(accessToken) {
const decoded = await verifyToken(accessToken);
const userId = decoded.sub;
const profile = userProfiles.get(userId) || { bio: '' };
return {
id: userId,
email: decoded.email || 'Unknown User',
bio: profile.bio
};
}
async updateProfile(accessToken, bio) {
const decoded = await verifyToken(accessToken);
const userId = decoded.sub;
userProfiles.set(userId, { bio });
return { success: true, message: 'Profile updated successfully' };
}
}
// Create HTTP server
const server = http.createServer(async (req, res) => {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
if (req.method === 'OPTIONS') {
res.writeHead(200);
res.end();
return;
}
if (req.url === '/api/config') {
const config = {
auth0: {
domain: AUTH0_DOMAIN,
clientId: AUTH0_CLIENT_ID,
audience: AUTH0_AUDIENCE
}
};
res.setHeader('Content-Type', 'application/json');
res.writeHead(200);
res.end(JSON.stringify(config));
return;
}
// Handle root path and Auth0 callback
if (req.url === '/' || req.url === '/index.html' || req.url.startsWith('/?code=') || req.url.startsWith('/?error=')) {
const html = readFileSync(join(__dirname, '../client/index.html'), 'utf8');
res.setHeader('Content-Type', 'text/html');
res.writeHead(200);
res.end(html);
return;
}
if (req.url === '/app.js') {
const js = readFileSync(join(__dirname, '../client/app.js'), 'utf8');
res.setHeader('Content-Type', 'application/javascript');
res.writeHead(200);
res.end(js);
return;
}
// Serve Auth0 SPA JS SDK from node_modules
if (req.url === '/@auth0/auth0-spa-js') {
const modulePath = join(__dirname, '../node_modules/@auth0/auth0-spa-js/dist/auth0-spa-js.production.esm.js');
const js = readFileSync(modulePath, 'utf8');
res.setHeader('Content-Type', 'application/javascript');
res.writeHead(200);
res.end(js);
return;
}
// Serve capnweb from node_modules
if (req.url === '/capnweb') {
const modulePath = join(__dirname, '../node_modules/capnweb/dist/index.js');
const js = readFileSync(modulePath, 'utf8');
res.setHeader('Content-Type', 'application/javascript');
res.writeHead(200);
res.end(js);
return;
}
res.writeHead(404);
res.end('Not found');
});
// WebSocket server for Cap'n Web RPC
const wss = new WebSocketServer({ server });
wss.on('connection', (ws, req) => {
// Only handle RPC connections on /api path
if (req.url === '/api') {
console.log('🔗 New Cap\'n Web RPC connection');
// Create a new ProfileService instance for this connection
const profileService = new ProfileService();
// Use capnweb's newWebSocketRpcSession to handle the connection
newWebSocketRpcSession(ws, profileService);
}
});
// Start server
server.listen(PORT, () => {
console.log(`🚀 Cap'n Web Auth0 Server Started`);
console.log(`📍 Server running on http://localhost:${PORT}`);
console.log(`🔐 Auth0 Domain: ${AUTH0_DOMAIN}`);
console.log(`🆔 Client ID: ${AUTH0_CLIENT_ID.substring(0, 8)}...`);
console.log(`🎯 API Audience: ${AUTH0_AUDIENCE}`);
});
```
Create the frontend HTML and JavaScript files:
```html client/index.html expandable lines theme={null}
Cap'n Web + Auth0 Demo
Cap'n Web + Auth0 Profile Demo
Initializing...
🔐 Welcome!
This demo shows Auth0 authentication with Cap'n Web RPC for real-time profile management.
👤 Profile Management
Email:Loading...
```
```javascript client/app.js expandable lines theme={null}
import { createAuth0Client } from '@auth0/auth0-spa-js';
import { newWebSocketRpcSession } from 'capnweb';
// Auth0 Configuration
let auth0Client = null;
let profileApi = null;
// Auth0 Configuration - Loaded dynamically from server
let AUTH0_CONFIG = null;
// Load Auth0 config from server
async function loadConfig() {
const response = await fetch('/api/config');
const config = await response.json();
AUTH0_CONFIG = {
domain: config.auth0.domain,
clientId: config.auth0.clientId,
authorizationParams: {
redirect_uri: window.location.origin,
audience: config.auth0.audience,
scope: 'openid profile email'
},
useRefreshTokens: true,
cacheLocation: 'localstorage'
};
return AUTH0_CONFIG;
}
// Initialize the application
async function initializeApp() {
try {
showStatus('Loading configuration...', 'info');
const config = await loadConfig();
showStatus('Initializing Auth0 client...', 'info');
auth0Client = await createAuth0Client(config);
const query = window.location.search;
if (query.includes('code=') && query.includes('state=')) {
showStatus('Processing login...', 'info');
await auth0Client.handleRedirectCallback();
window.history.replaceState({}, document.title, window.location.pathname);
}
const isAuthenticated = await auth0Client.isAuthenticated();
if (isAuthenticated) {
showStatus('Connecting to Cap\'n Web RPC...', 'info');
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
profileApi = newWebSocketRpcSession(`${protocol}//${window.location.host}/api`);
await showProfileSection();
} else {
showAuthSection();
}
setupEventListeners();
} catch (error) {
console.error('Initialization error:', error);
showStatus(`Failed to initialize: ${error.message}`, 'error');
}
}
// Authentication functions
async function login() {
try {
showStatus('Redirecting to Auth0...', 'info');
await auth0Client.loginWithRedirect();
} catch (error) {
showStatus(`Login failed: ${error.message}`, 'error');
}
}
async function logout() {
try {
if (profileApi) {
profileApi[Symbol.dispose]();
}
await auth0Client.logout({
logoutParams: { returnTo: window.location.origin }
});
} catch (error) {
showStatus(`Logout failed: ${error.message}`, 'error');
}
}
async function getAccessToken() {
try {
return await auth0Client.getTokenSilently({
authorizationParams: {
audience: AUTH0_CONFIG.authorizationParams.audience
}
});
} catch (error) {
if (error.error === 'consent_required' || error.error === 'interaction_required') {
await auth0Client.loginWithRedirect({
authorizationParams: {
audience: AUTH0_CONFIG.authorizationParams.audience,
scope: 'openid profile email',
prompt: 'consent'
}
});
}
throw error;
}
}
// Profile management functions
async function fetchProfile() {
try {
showStatus('Fetching profile...', 'info');
const token = await getAccessToken();
const user = await auth0Client.getUser();
const profile = await profileApi.getProfile(token);
document.getElementById('userEmail').textContent = user.email || profile.email || 'No email available';
document.getElementById('bioTextarea').value = profile.bio || '';
showStatus('Profile loaded successfully!', 'success');
} catch (error) {
showStatus(`Failed to fetch profile: ${error.message}`, 'error');
}
}
async function saveProfile() {
try {
showStatus('Saving profile...', 'info');
const token = await getAccessToken();
const bio = document.getElementById('bioTextarea').value;
const result = await profileApi.updateProfile(token, bio);
showStatus(result.message || 'Profile saved successfully!', 'success');
} catch (error) {
showStatus(`Failed to save profile: ${error.message}`, 'error');
}
}
// UI helper functions
function showAuthSection() {
document.getElementById('authSection').style.display = 'block';
document.getElementById('profileSection').style.display = 'none';
showStatus('Ready to login', 'info');
}
async function showProfileSection() {
document.getElementById('authSection').style.display = 'none';
document.getElementById('profileSection').style.display = 'block';
await fetchProfile();
}
function showStatus(message, type) {
const statusEl = document.getElementById('status');
statusEl.textContent = message;
statusEl.className = `status ${type}`;
}
// Event listeners
function setupEventListeners() {
document.getElementById('loginBtn').addEventListener('click', login);
document.getElementById('logoutBtn').addEventListener('click', logout);
document.getElementById('fetchBtn').addEventListener('click', fetchProfile);
document.getElementById('saveBtn').addEventListener('click', saveProfile);
}
// Initialize app when DOM is loaded
document.addEventListener('DOMContentLoaded', initializeApp);
```
```shellscript theme={null}
npm run start
```
**Checkpoint**
You should now have a fully functional Auth0 login page running on your [localhost](http://localhost:3000/)
***
## Advanced Usage
Enhance security by adding additional validation and rate limiting to your RPC methods:
```javascript server/profile-service.js theme={null}
import rateLimit from 'express-rate-limit';
class ProfileService extends RpcTarget {
constructor() {
super();
this.rateLimiter = new Map(); // Simple in-memory rate limiting
}
async validateAndRateLimit(userId) {
const now = Date.now();
const userLimit = this.rateLimiter.get(userId) || { count: 0, resetTime: now + 60000 };
if (now > userLimit.resetTime) {
userLimit.count = 0;
userLimit.resetTime = now + 60000;
}
if (userLimit.count >= 10) {
throw new Error('Rate limit exceeded. Try again later.');
}
userLimit.count++;
this.rateLimiter.set(userId, userLimit);
}
async getProfile(accessToken) {
const decoded = await verifyToken(accessToken);
await this.validateAndRateLimit(decoded.sub);
const userId = decoded.sub;
const profile = userProfiles.get(userId) || { bio: '' };
return {
id: userId,
email: decoded.email || 'Unknown User',
bio: profile.bio,
lastUpdated: profile.lastUpdated || null
};
}
}
```
Implement proper WebSocket connection handling with automatic reconnection:
```javascript client/connection-manager.js theme={null}
import { newWebSocketRpcSession } from 'capnweb';
class RpcConnectionManager {
constructor(wsUrl, options = {}) {
this.wsUrl = wsUrl;
this.api = null;
this.reconnectAttempts = 0;
this.maxReconnectAttempts = options.maxReconnectAttempts || 5;
this.reconnectDelay = options.reconnectDelay || 1000;
this.isConnecting = false;
this.onReconnect = options.onReconnect || (() => {});
}
async connect() {
if (this.isConnecting) return this.api;
this.isConnecting = true;
try {
// Dispose existing connection if any
if (this.api) {
this.api[Symbol.dispose]();
}
// Create new WebSocket RPC session
this.api = newWebSocketRpcSession(this.wsUrl);
this.reconnectAttempts = 0;
this.isConnecting = false;
console.log('✅ RPC connection established');
this.onReconnect(this.api);
return this.api;
} catch (error) {
this.isConnecting = false;
if (this.reconnectAttempts < this.maxReconnectAttempts) {
this.reconnectAttempts++;
console.log(`🔄 Reconnection attempt ${this.reconnectAttempts}/${this.maxReconnectAttempts}`);
await new Promise(resolve =>
setTimeout(resolve, this.reconnectDelay * this.reconnectAttempts)
);
return this.connect();
} else {
throw new Error('Max reconnection attempts reached');
}
}
}
disconnect() {
if (this.api) {
this.api[Symbol.dispose]();
this.api = null;
}
this.reconnectAttempts = 0;
}
getApi() {
return this.api;
}
}
// Usage in app.js
const connectionManager = new RpcConnectionManager(
`${protocol}//${host}/api`,
{
maxReconnectAttempts: 5,
reconnectDelay: 1000,
onReconnect: async (api) => {
// Refresh UI or reload data after reconnection
await displayProfile(api);
}
}
);
// Connect when authenticated
if (isAuthenticated) {
await connectionManager.connect();
profileApi = connectionManager.getApi();
}
```
Replace in-memory storage with a database for production use:
```javascript server/database.js theme={null}
import { Pool } from 'pg';
const pool = new Pool({
connectionString: process.env.DATABASE_URL || 'postgresql://localhost/capnweb_auth0'
});
// Initialize database schema
async function initializeDatabase() {
await pool.query(`
CREATE TABLE IF NOT EXISTS user_profiles (
user_id VARCHAR(255) PRIMARY KEY,
bio TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
`);
}
class DatabaseProfileService extends RpcTarget {
async getProfile(accessToken) {
const decoded = await verifyToken(accessToken);
const result = await pool.query(
'SELECT bio, updated_at FROM user_profiles WHERE user_id = $1',
[decoded.sub]
);
return {
id: decoded.sub,
email: decoded.email,
bio: result.rows[0]?.bio || '',
lastUpdated: result.rows[0]?.updated_at || null
};
}
async updateProfile(accessToken, bio) {
const decoded = await verifyToken(accessToken);
await pool.query(`
INSERT INTO user_profiles (user_id, bio, updated_at)
VALUES ($1, $2, CURRENT_TIMESTAMP)
ON CONFLICT (user_id)
DO UPDATE SET bio = $2, updated_at = CURRENT_TIMESTAMP
`, [decoded.sub, bio]);
return { success: true, message: 'Profile updated successfully' };
}
}
export { initializeDatabase, DatabaseProfileService };
```
# Add Login to Your Flutter Web Application
Source: https://auth0.com/docs/quickstart/spa/flutter
This guide demonstrates how to integrate Auth0 with a Flutter Web application using the Auth0 Flutter SDK.
If you use an AI coding assistant like Claude Code, Cursor, or GitHub Copilot, you can add Auth0 authentication automatically in minutes using [agent skills](https://agentskills.io/home).
**Install:**
```bash theme={null}
npx skills add auth0/agent-skills --skill auth0
```
**Then ask your AI assistant:**
```text theme={null}
Add Auth0 authentication to my Flutter web app
```
Your AI assistant will automatically create your Auth0 application, fetch credentials, add the auth0\_flutter SDK dependency, configure web/index.html, set up callback URLs, and implement login/logout flows. [Full agent skills documentation →](/quickstart/agent-skills)
**Prerequisites:** Before you begin, ensure you have the following installed:
* **[Flutter](https://flutter.dev/)** 3.0 or newer configured for web
* **[Dart](https://dart.dev/)** 2.17 or newer
* Familiarity with the [Flutter CLI](https://docs.flutter.dev/reference/flutter-cli)
Verify installation: `flutter --version`
If you don't have a Flutter web app, create one: `flutter create --platforms=web my_app`
## Get Started
This quickstart demonstrates how to add Auth0 authentication to a Flutter Web application. You'll build a secure single-page app with login, logout, and user profile features using the Auth0 Flutter SDK.
Create a new Flutter Web application for this quickstart:
```shellscript theme={null}
flutter create --platforms=web auth0_flutter_web
```
Open the project:
```shellscript theme={null}
cd auth0_flutter_web
```
Add the Auth0 Flutter SDK to your project using the Flutter CLI:
```shellscript theme={null}
flutter pub add auth0_flutter
```
The SDK requires the Auth0 SPA JS library to be loaded in your web application. Add the following `