Authentication Unlocked: A Beginner’s Journey through OAuth 2.0, OIDC, JWT and Digital Signatures Part:2
"Cracking the Code: A Beginner’s Guide to OAuth 2.0, OIDC, JWT, and Digital Signatures (Part 2)"
In the previous part of this series, we delved into the world of digital signatures, particularly within JWTs (JSON Web Tokens) and OIDC (OpenID Connect). We explored how digital signatures ensure the authenticity and integrity of tokens, much like verifying a letter from a friend hasn’t been tampered with. Now, building on that foundation, it makes sense to step back and understand OAuth 2.0 — the framework that underpins both OIDC and JWTs in the context of modern authentication systems.
For those of you working with cloud platforms like Azure, this will be especially relevant. We’ll use Azure-specific examples to illustrate how OAuth 2.0 functions in real-world scenarios.
Why Start with OAuth 2.0?
Imagine you’re at a concert, and you have a ticket that grants you access to certain areas but not others. OAuth 2.0 works similarly in the digital realm — it’s all about granting limited access to resources without sharing your credentials. Understanding OAuth 2.0 is crucial because it lays the groundwork for grasping how OIDC and JWTs operate, especially when dealing with authentication and authorization in cloud services like Azure.
Understanding OAuth 2.0
OAuth 2.0 is a system that lets applications (clients) access certain parts of a user’s account on a web service without needing the user’s password. Instead of sharing login credentials, the user grants the application permission to act on their behalf for specific tasks.
Key Components:
Resource Owner: The user who authorizes an application to access their account.
Client: The application requesting access to the resources.
Authorization Server: The server that authenticates the resource owner and issues access tokens (e.g., Azure AD, now Microsoft Entra ID).
Resource Server: The server hosting the protected resources (e.g., Microsoft Graph API).
OAuth 2.0 Grant Types
OAuth 2.0 defines several grant types for different use cases. Let’s focus on the most common ones ( this is not a complete list just to be clear ), especially in the context of Azure:
Authorization Code Grant (Recommended for Web Apps)
Implicit Grant (Less Secure, Deprecated)
Client Credentials Grant (For Service Accounts)
Resource Owner Password Credentials Grant (Not Recommended)
For our purposes, we’ll dive into the Authorization Code Grant, as it’s the most secure and widely used flow for web applications.
Step-by-Step: Authorization Code Grant Flow with Azure
Let’s break down how the Authorization Code Grant works, using Azure as our Authorization Server.
1. User Attempts to Access Protected Content
The user navigates to your web application and tries to access a protected resource or feature.
2. Application Redirects User to Azure AD
Your application redirects the user to the Azure AD authorization endpoint:
GET https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize?
client_id={client_id}&
response_type=code&
redirect_uri={redirect_uri}&
response_mode=query&
scope=openid%20profile%20email&
state={state}
tenant: Your Azure AD tenant ID or domain.
client_id: The application’s client ID registered in Azure AD.
redirect_uri: The URI Azure AD will redirect to after authentication.
scope: Permissions the application is requesting (e.g.,
openid
,profile
,email
).state: A value used to maintain state between the request and callback (prevents CSRF attacks).
3. User Authenticates with Azure AD
The user is prompted to sign in with their Azure AD credentials.
4. User Consents to Permissions
If required, the user consents to the permissions the application is requesting.
5. Azure AD Sends Authorization Code
After successful authentication and consent, Azure AD redirects the user back to your application’s redirect_uri
with an authorization code:
GET {redirect_uri}?code={authorization_code}&state={state}
6. Application Exchanges Authorization Code for Access Token
Your application sends a POST request to Azure AD’s token endpoint to exchange the authorization code for an access token:
POST https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&
client_id={client_id}&
scope=openid%20profile%20email&
code={authorization_code}&
redirect_uri={redirect_uri}&
client_secret={client_secret}
7. Azure AD Returns Access Token (and ID Token)
Azure AD responds with an access token and an ID token (since we requested openid
scope):
{
"token_type": "Bearer",
"expires_in": 3599,
"access_token": "{access_token}",
"id_token": "{id_token}",
"refresh_token": "{refresh_token}",
"scope": "openid profile email"
}
access_token: Used to access protected resources.
id_token: A JWT that contains user identity information.
refresh_token: Used to obtain new tokens without re-authenticating.
8. Application Uses Access Token to Access Resources
Your application can now use the access token to call APIs (like Microsoft Graph) on behalf of the user:
GET https://graph.microsoft.com/v1.0/me
Authorization: Bearer {access_token}
9. Resource Server Validates Access Token
The resource server (e.g., Microsoft Graph API) validates the access token’s signature and claims.
10. Application Receives Protected Data
If the token is valid, the resource server responds with the requested data.
Deep Dive: Understanding Scopes and Permissions
In Azure, scopes are essential for defining what resources and operations your application can access. Common scopes include:
openid: Requests an ID token for user authentication.
profile: Access to basic user profile information.
email: Access to the user’s email address.
offline_access: Request a refresh token.
When registering your application in Azure AD, you can define custom scopes or use predefined ones.
Security Considerations
State Parameter: Always use the
state
parameter to prevent CSRF attacks. Store a unique session identifier or token, and validate it upon return.PKCE (Proof Key for Code Exchange): For public clients (like mobile apps or SPAs), implement PKCE to enhance security by mitigating authorization code interception attacks.
Client Secret Protection: Treat your client secret like a password. Never expose it in client-side code or commit it to version control.
Refresh Tokens: Handle refresh tokens securely. Store them safely and refresh access tokens as needed.
Connecting Back to Digital Signatures and JWTs
Remember when we discussed how digital signatures ensure the integrity and authenticity of JWTs? The id_token and access_token you receive from Azure AD are JWTs signed by Azure’s private key.
Verifying the Token’s Signature:
Retrieve Azure AD’s Public Keys
Azure publishes its public keys (JWKS) at:
https://login.microsoftonline.com/{tenant}/discovery/v2.0/keys
2. Decode the JWT
Use a JWT library to decode the token and extract the header, payload, and signature.
3. Validate the Signature
Use the public key corresponding to the kid
(Key ID) in the JWT header to verify the signature.
Why This Matters
Authenticity: Ensures the token was issued by Azure AD.
Integrity: Confirms the token hasn’t been tampered with.
Trust: Builds confidence that you’re securely handling user authentication.
Example: Validating an ID Token in Azure
Suppose you receive the following id_token
:
eyJ0eXAiOiJKV1QiLCJub25jZSI6IjA0ZDV... (header)
.eyJhdF9oYXNoIjoiV0R6YkthNkF... (payload)
.LvMO5LwC_EKcP_V7_i6d6... (signature)
Steps to Validate:
1.Decode the Header and Payload
The header will contain the signing algorithm (alg
) and the Key ID (kid
).
2.Fetch Azure AD’s Public Keys
Retrieve the keys from the JWKS endpoint.
3.Find the Matching Key
Match the kid
from the JWT header with one of the keys in the JWKS.
4.Verify the Signature
Use the appropriate public key to verify the signature using the algorithm specified in alg
.
5.Validate Claims
Issuer (
iss
): Should match your Azure AD tenant's issuer URI.Audience (
aud
): Should match your application's client ID.Expiration (
exp
): Ensure the token hasn't expired.Nonce (
nonce
): If used, validate to prevent replay attacks.
Final Thoughts
We should now have a clearer understanding of how OAuth 2.0 facilitates secure authorization between applications and services, especially within the Azure ecosystem.
We’ve connected the dots between OAuth 2.0, JWTs, and digital signatures, highlighting their roles in securing modern web applications.
As always, I encourage you to experiment with these concepts in a practical setting.
Set up a test application in Azure, implement the OAuth 2.0 flow, and see firsthand how these components interact. Hands-on experience is probably the best way forsolidifying your understanding.
Stay tuned for the next part, where we’ll unlock the mysteries of OpenID Connect and take our authentication journey to the next level!
P.S depending on when you read this, there may be slight modifications on things such as Azure Endpoints or stuff like that, please do keep in mind that validating everything you read with you own environment and ensuring that you are doing your due diligence before starting to implement stuff in production.
You made it so simple to understand.