SPA + API: Solution Overview
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. 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.
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.
What is an Access Token?
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.
For more information on Auth0 Access Tokens refer to Access Token.
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.
What are Scopes?
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.
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.
OAuth Roles
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.
Using different grants types (or flows), these participants will interact to grant to the client apps limited access to the APIs you are building. As a result, the client app will obtain an Access Token that can be used to call the API on behalf of the user.
Because SPAs are public clients and cannot securely store a Client Secret since the source code is available to the browser, you will want to use the Authorization Code Flow with Proof Key for Code Exchange (PKCE) with your SPA.
With this flow, the calling application requests an Access Token over HTTPS with a transformative value—a Code Verifier (or another type of client secret)—that can be verified by the authorization server.
Implicit Flow
The original specifications for OAuth2 introduced the Implicit Flow, a way for SPAs without a backend to obtain Access Tokens and call APIs directly from the browser. However, mitigation strategies are necessary to use the Implicit Flow because tokens are returned in the URL directly from the authorization endpoint as opposed to the token endpoint.
We recommend using the Authorization Code Flow with PKCE rather than Implicit Flow; however, if you are unable to update to the recommended flow, you should implement necessary mitigations to combat the risks.
To learn more, read our blog post: OAuth2 Implicit Grant and SPA.
The Auth0 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 which will read the Roles, Groups, and Permissions assigned to a user and add this information to the User profile 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.