Search code examples
azureauthenticationoauth-2.0microsoft-graph-apimicrosoft-identity-platform

What type of 3rd party authentication(OAuth) should be used to sign in users to own API


I have an API and it's using the Microsoft Identity Platform as a way to authenticate users.

I need to refactor It because I think I've done some errors in the implementation.

So to start fresh, I want to know what is the logic on how to handle 3rd party authenticators. With that said, I would be thankful if someone could confirm if the following authentication flow makes sense.

The sequence that seems plausible is: Authentication Sequence

  • Client APP (Web Browser, Mobile App)requests to microsoft login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize
  • After the user enters his credentials, Microsoft redirects to Client App with a ?code parameter
  • Client App sends the code and redirect_uri to my API
  • MY API acquires the access_token and refresh_token by passing the code to the token endpoint login.microsoftonline.com/{tenant}/oauth2/v2.0/token.
  • My API Stores the tokens in the database.
  • My API generates a session hash that maps that user ID to those access_tokens and refresh_tokens
  • My API redirects that session_hash to the Client APP through the url.
  • Client APP uses that session hash to consume my API.

Token validation

When storing the tokens in the database, store their expiration date.

  1. For every request done to my API check if the current date is before expiration.
  2. If it is not, refresh the token using the refresh_token and replace old tokens with the new tokens.
  3. If it's not possible to refresh the token, send a 401 error and trigger a new OAuth authentication on the Client APP. Run the "Authentication Sequence" again.
  4. Allow the request to proceed.

Concerns about different client platforms.

Microsoft provides authentication libraries (MSAL) for different clients. But these libraries, from what I understand, it is to authenticate the user, storing the tokens locally, and consume the Microsft Graph API. This leads me to question the reliability of my flow, because the way I made it, it is not compatible with these libraries.


Solution

  • I believe you need not do all of these and can make things really simple.

    Here's what you can do:

    • From the client application you can authenticate the user and once the user is authenticated, you can acquire a token for your API. You can use MSAL for that. MSAL will take care of caching the tokens (both access and refresh tokens) and will renew them as and when needed.
    • When your client application makes the API call, you can simply request a token from MSAL silently. If the token acquisition fails for any reason, MSAL will throw an error and you will handle that error in your client application accordingly (e.g. you can redirect the user to login again).
    • Once your API receives the access token, you can validate it. I asked a question sometime ago regarding the same that you can read here - Azure AD - Why can't I validate JWT token issued by Azure AD for my Web API? Getting "IDX10516: Signature validation failed" error.
    • If your API needs to get access to protected resources on behalf of the signed-in user (OneDrive for example), you can get that token inside your API using the token that's being sent along with the request. For example, take a look at code snippets below. It gets a token for Azure Resource Manager API.

    Assuming you're using .Net 5/Core, you would need to add the following lines in your Startup.cs first:

    services
        .AddMicrosoftIdentityWebApiAuthentication(Configuration, "ApiSettingsConfigurationSectionName")
        .EnableTokenAcquisitionToCallDownstreamApi()//This does the magic of getting the token for protected resources.
        .AddInMemoryTokenCaches();
    

    Then this is how you would get the token for a protected resources in your API controllers:

    
    private readonly ITokenAcquisition _tokenAcquisition;
    
    ...
    ...
    ...
    
    public YourController(ITokenAcquisition tokenAcquisition,
        ...other injected parameters
        )
    {
        _tokenAcquisition = tokenAcquisition;
        ...
    }
    
    
    /// <summary>
    /// Gets the access token on behalf of signed-in user to perform Azure
    /// Resource Manager (ARM) API.
    /// </summary>
    /// <returns>
    /// Access token.
    /// </returns>
    private async Task<string> GetAccessTokenForAzureSubscriptionManagementApiRequest()
    {
        string accessToken = await _tokenAcquisition.GetAccessTokenForUserAsync(['scopes for the protected API e.g. https://management.azure.com/user_impersonation']);
        return accessToken;
    }
    

    Microsoft provides authentication libraries (MSAL) for different clients. But these libraries, from what I understand, it is to authenticate the user, storing the tokens locally, and consume the Microsft Graph API.

    This is not entirely true. MSAL can be used to acquire token for any API that is protected by Azure AD. Graph API is certainly one of them but then you can also use MSAL against your own API provided it is protected by Azure AD.