'How to validate AzureAD accessToken in the backend API

I just wanted to know how can we validate the azure ad access token in a backend API in my case i.e. Django rest framework.

Consider that I have a single page app or a native app and a backend API (django rest framework) completely independen of each other. In my case if my single page app/native app wants to access certain data from the backend API, and inorder to access the API, user should be logged in the backend API.

So what my approch is to make use of MSAL library to get the access token from the SPA/native app and then once token is acquired, pass that token to backend API, validate it, get the user info from graph api. If user exists in the DB then login the user and pass the required info. If user info doesn't exist then create the user, login and pass the info from the API.

So my question is when I pass the access token to my backend api, how can I validate that the token that a user/SPA/native app has passed to backend API is valid token or not?

Is it just we need to make an API call to graph API endpoint with accessToken that user/SPA/native passed and if it is able to get the user data with the accessToken then then token is valid or if it fails then the accessToken is invalid.

Is it the general way to validate the token or some better approach is there? Please help



Solution 1:[1]

Good day sir, I wanna share some of my ideas here and I know it's not a solution but it's too long for a comment.

I created a SPA before which used msal.js to make users sign in and generate access token to call graph api, you must know here that when you generate the access token you need to set the scope of the target api, for example, you wanna call 'graph.microsoft.com/v1.0/me', you need a token with the scope 'User.Read, User.ReadWrite' and you also need to add delegated api permission to the azure app.

So as the custom api of your own backend program. I created a springboot api which will return 'hello world' if I call 'localhost:8080/hello', if I wanna my api protected by azure ad, I need to add a filter to validate all the request if has a valid access token. So I need to find a jwt library to decode the token in request head and check if it has a token, if the token has expired and whether the token has the correct scope. So here, which scope is the correct scope? It's decided by the api you exposed in azure ad. You can set the scope named like 'AA_Custom_Impression', and then you can add this delegate api permission to the client azure ad app, then you that app to generate an access token with the scope of 'AA_Custom_Impression'. After appending the Bearer token in calling request, it will be filtered by backend code.

I don't know about python, so I can just recommend you this sample, you may try it, it's provided by microsoft.

Solution 2:[2]

I've solved the similar issue. I don't found how to directly validate access token, but you can just call graph API on backend with token you've got on client side with MSAL.

Node.js example:

class Microsoft {

  get baseUrl() {
    return 'https://graph.microsoft.com/v1.0'
  }

  async getUserProfile(accessToken) {
    const response = await got(`${this.baseUrl}/me`, {
      headers: {
        'x-li-format': 'json',
        Authorization: `Bearer ${accessToken}`,
      },
      json: true,
    })
    return response.body
  }
  
  // `acessToken` - passed from client
  async authorize(accessToken) {
    try {
      const userProfile = await this.getUserProfile(accessToken)
      const email = userProfile.userPrincipalName

      // Note: not every MS account has email, so additional validation may be required
      const user = await db.users.findOne({ email })

      if (user) {
        // login logic
      } else {
        // create user logic
      }
    } catch (error) {
      // If request to graph API fails we know that token wrong or not enough permissions. `error` object may be additionally parsed to get relevant error message. See https://docs.microsoft.com/en-us/graph/errors 
      throw new Error('401 (Unauthorized)')
    }
  }
}

Solution 3:[3]

Yes we can validate the Azure AD Bearer token.

You can fellow up below link,

https://github.com/odwyersoftware/azure-ad-verify-token https://pypi.org/project/azure-ad-verify-token/

We can use this for both Django and flask.

You can directly install using pip but I'm not sure in Django. If Django install working failed then try to copy paste the code from GitHub

Validation steps this library makes:
    1. Accepts an Azure AD B2C JWT.
         Bearer token
    2. Extracts `kid` from unverified headers.
         kid from **Bearer token**
    3. Finds `kid` within Azure JWKS.
         KID from list of kid from this link `https://login.microsoftonline.com/{tenantid}/discovery/v2.0/keys`
    4. Obtains RSA key from JWK.

    5. Calls `jwt.decode` with necessary parameters, which inturn validates:
    
        - Signature
        - Expiration
        - Audience
        - Issuer
        - Key
        - Algorithm

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 tiny-wa
Solution 2 Kuzzy
Solution 3 Eric Aya