Last updated on September 6th, 2023
Last week, I set out to create an application based on microservices architecture, primarily for learning purposes. My initial focus was to secure the application, which led me to learn how to build a Spring authorization server from scratch. While I had previously implemented resource servers, building an authorization server was challenging. It requires me to brush up on the Oauth2 flow and Spring components before jumping to the Spring Authorization Server framework. In this part, I’ll share a brief overview of OAuth2 and JWT concepts before the implementation using the Spring Authorization Server Framework.
OAuth2
OAuth (short for “Open Authorization”[1][2]) is an open standard for access delegation, commonly used as a way for internet users to grant websites or applications access to their information on other websites but without giving them the passwords.[3][4] This mechanism is used by companies such as Amazon, Google, Facebook, Microsoft, and Twitter to permit users to share information about their accounts with third-party applications or websites.
Source : https://en.wikipedia.org/wiki/OAuth
Basically, OAuth is an authorization framework that allows a user (resource owner) to grant a third-party application (client) limited access to their data (resources) that are hosted on another service (resource server), without the need to share the user’s credentials. The advantage of OAuth is that it allows users to grant access to their resources without exposing their credentials, and isolates the responsibility for credential management in one component of the system.
Let’s take a look at its components.
OAuth Components
- The resource server – The server that holds the user’s resources. The resource server validates the access token provided by the client application and returns the requested resources if the token is valid.
- The user (resource owner) – The person who owns resources exposed by the resource server. The user has the authority to grant access to their resources.
- The client – The application that accesses the protected user’s resources on their behalf. The client uses a client ID and a client secret to identify itself. The client needs its own credentials to identify itself when making a request.
- The authorization server – The server that authorizes the client to access the user’s resources exposed by the resource server.
Authorization server implementation
As mentioned above, the role of the authorization server is to authenticate the user and provide a token to the client. The client uses this token to access resources exposed by the resource server on behalf of the user. The OAuth 2 framework defines multiple flows for obtaining a token that can be called grants.
From Oauth2.1, the password grant type is removed, so we’ll figure out two grants as client credential and authorization code grant type.
Using client credential grant type
This grant type is for server-to-server communication, where there is no user directly involved. The client itself is the resource owner in this case.
Source: Spring Security in action
Here’s a brief overview of the OAuth 2.1 Client Credentials Grant:
- The client application sends a request to the authorization server’s token endpoint with information such as its client_id, client_secret, grant_type, and scope.
- The authorization server validates the client’s credentials and, if valid, returns an access token.
- The client application uses the access token to access protected resources from the resource server.
Using the authorization code grant type
In OAuth 2.1, PKCE (Proof Key for Code Exchange) is mandatory for this flow to enhance security and mitigate the risk of authorization code interception attacks.
Source: Spring Security in action
Here’s a brief overview of the OAuth 2.1 Authorization Code Grant:
- The client application directs the user to the authorization server’s authorization endpoint with client_id, redirect_uri, scope, response_type.
- The user logs in and, if they grant consent, the authorization server sends an authorization code back to the redirect_uri specified by the client application.
- The client application exchanges the authorization code for an access token and a refresh token by sending a request to the authorization server’s token endpoint, with additional PKCE information (code_verifier).
- The authorization server validates the authorization code and the code_verifier before returning the access and refresh tokens.
- The client application uses the access token to request the protected resources from the Resource Server.
- The Resource Server validates the access token and, if valid, returns the requested resources to the client application.
JWT
We’ve mentioned access tokens in the context of OAuth. Basically, the Access tokens contain credentials that allow clients to access protected resources on behalf of the resource owner. While OAuth 2.0 does not mandate any specific format for accessing tokens, JSON Web Token has become a popular choice because of its advantages.
Basically, JWT is an open standard used to share information between the client application and a server. They contain JSON objects which have the information that needs to be shared. Each JWT is also signed using cryptography to ensure that the JSON contents (also known as JWT claims) cannot be altered by any malicious parties.
The advantages of using JWTs include statelessness, and eliminating the need for the server to maintain session data or user information. JWTs avoid sharing credentials in all requests and we can inactive it without affecting the user’s credentials. JWTs store user authorities are required by the client to send in requests. They can replace a server-side session, offering better flexibility for horizontal scaling.
JWT Components
A token consists of 3 parts: header, body, signature
- The header: include metadata related to the token.
- The body: Include details needed later for authorization.
- The signatures: are generated using a cryptographic algorithm that uses as input the header and the body. The cryptographic algorithm implies the need for a key which is like a password.
Source: Spring Security in action
In the context of OAuth2, we can use cryptographic signatures in order for to resource server can validate tokens issued by the authorization server. It allows the resource server to validate them without needing to call the authorization server directly.
- Symmetric key: Use the same key for signing the token as well as for verifying the signature
- Asymmetric key pair: Use one key to sign the token but a different one to verify the signature.
Using symmetric key
Both the authorization server and the resource server know and use the same key: the authorization server signs the token with the key and the resource server validates the signature using the same key.
Source: Spring Security in action
Using symmetric keys for signing tokens has the advantage of being simpler than other approaches and it’s faster
Using asymmetric keys
A public and private key pair is used for signing (encrypt) and verifying (decrypt) the tokens. The private key is used to sign the tokens, while the public key is used to verify them.
Source: Spring Security in action
The advantage of using asymmetric keys is that you can safely expose the public key without compromising the integrity of your JWT tokens.
To validate tokens with asymmetric keys, the resource server needs to:
- Have access to the public key from the authorization server. This can be provided as a file, through an API, or using a well-known public key URL.
- Use a JWT library to parse and validate the tokens, ensuring that the signature is correct and the token has not expired.
Using Symmetric | Using Asymmetric | |
---|---|---|
Advantages | • Faster in performance compared to asymmetric cryptography. • Requires less computational power and resources. | • Simplified key distribution and management, as only public keys need to be shared. • Allows secure communication between multiple parties without the need for pre-shared secret keys. • Digital signatures can be used to verify the integrity and authenticity of data and messages |
Disadvantages | • Secure key distribution and management can be challenging. • Not suitable for large-scale systems where multiple parties need to securely communicate with each other, as each pair of communicating parties needs a unique secret key. • Compromised secret keys can lead to unauthorized access to encrypted data and communication. | • Slower in performance compared to symmetric cryptography. • Requires more computational power and resources. |
Next steps
That’s all for a brief overview of my review of OAuth2 and JWT. In the next post, I will share the practical application of these concepts by demonstrating the implementation via the Spring Authorization Server. Stay tuned for insights into how these ideas come to life in real-world scenarios.