Docs

Authorization

It’s important to start by distinguishing between Authentication, Authorization, and Access Control. Your Auth0 tenant (your Authorization Server) is typically responsible for Authentication and some or all of Authorization. Access Control however must be the responsibility of the Application or API itself, because access control is almost always contextual:

  • Authentication: the process of determining if a principal - a user or application - is who/what they say they are.
  • Authorization: the proceess of determining what is allowed, based on the principal, the consent they provide, what permissions they have been given, and/or the set of contextually specific access criteria. Broadly speaking, authorization in Auth0 breaks down into the following categories:
    • Consent: what can be done on the behalf of a user principal (subject) or, in the case of an application principal authenticating via Client Credentials grant, what an administrative authority has authorized an application to do.

    • Access Control: the access that is permitted. In general this can be thought of as breaking down into three sub-categories of granularity:

      • Coarse grained Access Control. This 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 defined in the context the Authorization Server (e.g. via use of app_metadata associated with a user, and a Rule defined in your Auth0 tenant). Coarse grained access control is effectively "identity as the new perimeter".

      • Medium grained Access Control. This 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 (i.e. as app_metadata on a user in your Auth0 tenant), and the enforcement process is performed in the Application or API itself. In this scenario, the data is typically communicated as one or more custom claims in an id or access token.

      • Fine grained Access Control. Again, this 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. However both the data required to enforce this, and the enforcement process, is 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 wthout 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 medium or fine-grained permissions?

Auth0 provides multi-grained authorization by restricting access to applications or APIs based on certain conditions. In a coarse-grained authorization scenario, a Rule can be built 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 same way that OIDC is the most commonly used industry-standard protocol for authentication in customer facing applications, we find that OAuth2 is the most commonly used industry-standard protocol for authorization.

Auth0 also can provide the authorization information needed so that the application or API can apply medium or fine-grained access control. 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 enforce access control. In this case you will need to decide what information you require for your application to make access control decisions.

When deciding what data to include in OIDC tokens, 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, 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 control decisions, and then your API will need to enforce that access control by validating the contents of the Access Token.

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 provide fine-grained access security. 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 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 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.

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.

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 specifc 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.

Though the Client Credentials Exchange Hook in Auth0 can be used to add custom claims, it's important to consider the purpose for which a token was requested and to avoid extending use of the token beyond its intended purpose. Doing otherwise can result in the creation of unintended attack vectors for attackers to exploit.

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

Keep reading