Authorization (B2C)
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
associated with a user and a Rule 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 anid
oraccess
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
oraccess
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 a Rule 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) - or if the user doesn’t have the right claim(s) contained in their app_metadata
. For an application using OpenID Connect (OIDC), this would prevent the allocation of the ID Token used to authorize access. Similarly, for an API, allocation of any OAuth2 Access Token (used when calling the API), could be prevented as described in this example.
Best Practice
In the main, we have found that OIDC 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 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, Auth0 allows you to add custom 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.
For API level integration, Auth0 supports both custom claims as well as scope 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.
Best Practice
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 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), 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.
ID Token claims
Using Rule extensibility, Auth0 allows you to easily add custom claims to an ID Token based on, for example, a user’s 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 Rule is streamlined, the Rule engine is flexible and allows you to write custom code that may have negative effects. Therefore it’s important to follow our rules best practice guidance anytime you use this extensibility feature.
Best Practice
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
. 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 guidance too.
ID Token scopes
OIDC 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. 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 endpoint.
API integration
In this scenario your Auth0 tenant can provide an OAuth2 Access Token, typically expressed as a JWT, 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.
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 - 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, 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 or through the Auth0 Management API, it's important to review the different application scenarios and API layouts to determine the best architecture for your system.
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 and is a large part of what providing support for third party applications 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. 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 as part of any resource service definition.
Alternatively, you may have data relating to a user for which additional functionality is provided 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 can be defined.
Access Token claims
As is the case with ID Tokens, you can add custom claims to Access Tokens using Auth0 Rule 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.
Best Practice
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
. 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 guidance too.
Access Token scopes
OAuth2 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 in the Auth0 Dashboard or through the Auth0 Management API). Scopes can also be manipulated via Auth0 extensibility (e.g. via a Rule, as in this example). 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. 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.
Best Practice
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. We therefore recommend that you use scopes for their intended purpose (i.e. delegating permission to an application) and use custom claims for your role-based or other access control scenarios.
Role Based Access Control (RBAC)
Auth0 has out-of-box support for Role Based 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 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 a rule or custom DB script in your Auth0 tenant)
best practice
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 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.