Accessing identity token in Blazor WASM

I still remember a time, when OAuth has a promise to make authentication and authorization on the internet easy. But in the meantime vendors implemented so many frameworks and identity products, that it is really, really not easy anymore to be aware of everything (anything).
Also Blazor, a great technology need to support this. Some things work great, but some don't.
In this specific case, I use OID authentication and want to access the raw token hiden somewhere in Blazore framework. I want to use this token to read all of the claims in there because Blazor maps just some of them. I also want to pass this token to my REST and validate it in there to implement authorization.
But why this? Because I do not want to use any of the STS providers for authorization. I want that authorization remains a part of the application or my REST service. Why this? Because it is so simple.

Depending on the STS you use (I mean some of services.AddFoo() statements), the token in Blazor is stored differently. After successful authentication, token specifics are stored in the browsers session store.
21143_blazortoken1
In this post, I will describe how to access Google and Azure Active Directory id-tokens. These tokens are issued by STS when the user successfully logs in.
For both cases, I implemented:

  1. A Blazor method to invoke javascript that returns the token
  2. A short Javascript that returns the token. This JS script must be added to the Index.html file of your Blazor project (described later).

How to access the JWT Token created by ADD?

Assuming that your Blazor is configured following way:

builder.Services.AddMsalAuthentication(options =>
{
  builder.Configuration.Bind("AzureAD",  
  options.ProviderOptions.Authentication);
  options.ProviderOptions.DefaultAccessTokenScopes.Add("openid");
  options.ProviderOptions.DefaultAccessTokenScopes.Add("offline_access");
  options.ProviderOptions.LoginMode = "redirect";
 });

 builder.Services.AddMsalAuthentication(options =>
 {
    options.ProviderOptions.AdditionalScopesToConsent.Add("https://todo");
});

The configuration used in this sample stored in appsettings.json looks as follows:

"AzureAd": {
    "Authority": "https://login.microsoftonline.com/TENANTID",
    "ClientId": "e1661***4ed",
    "ValidateAuthority": true
  },

The configuration must contain the the authgority url, which is the endpoint of the STS (security token service).
I created following Blazor method to access the AAD token by invoking the javascript function designed for this purpose.

        /// <summary>
        /// Gets the raw JWT id_token.
        /// </summary>
        /// <returns></returns>
        public async Task<string> GetJwtToken()
        {
            string token = null;

            // Uses MSAL when working with AAD only
            token = await this.jsRuntime
            .InvokeAsync<string>("getMsalToken", "hello");
         
            if (token != null)
            {
                Console.WriteLine($"TOKEN:{token}");
            }
            else
                Console.WriteLine($"Token not found!");

            return token;
        }

It is up to you where to implement the method. That can be some razor.cs file or injectable component called service in Blazor.

JAVAscript for AAD created JWT token

To access the token we have to traverse all keys int session storage and lookup that one that contains the credential type called ‘IdToken’. This is by design how Blazor persists the token in the session store.

function getMsalToken(abc) {

            var keys = Object.keys(sessionStorage);
            for (var i = 0; i < keys.length; i++) {
                var entry = sessionStorage.getItem(sessionStorage.key(i));
                var json = JSON.parse(entry);
               
                if (json.credentialType == "IdToken") {
                    return json.secret;
                }
            }
            
            return null;
        }

How to access JWT Token created by Google STS?

When working with Google provider, Blazor uses OID authentication as shown in the following snippet.

   builder.Services.AddOidcAuthentication(options =>
   {
      builder.Configuration.Bind("Google", options.ProviderOptions);      
    });

The following configuration in appsettings.json is used to activate Google provider.

"Google": {
"Authority": "https://accounts.google.com/",
"ClientId": "****u.apps.googleusercontent.com",
"PostLogoutRedirectUri": "https://localhost:44316/authentication/logout-callback",
"RedirectUri": "https://localhost:44316/authentication/login-callback",
//"ResponseType": "id_token" not required. It is the default value.
},

The already known method GetJwtToken invokes this time a slightly different javascript function.

        /// <summary>
        /// Gets the raw JWT id_token.
        /// </summary>
        /// <returns></returns>
        public async Task<string> GetJwtToken()
        {
            string token = null;

            token = await this.jsRuntime
            .InvokeAsync<string>("getOidToken", "oidc.user:{Authority}:{ClientId}");

            if (token != null)
            {
                Console.WriteLine($"TOKEN:{token}");
            }
            else
                Console.WriteLine($"Token not found!");

            return token;
        }

JAVAscript for Google (any other OID provider) created JWT token

The javascript that lookups the JWT token looks as shown in the function getOidToken.

function getOidToken(key) {

        var strJson = sessionStorage.getItem(key);
        if (strJson != null) {
            var json = JSON.parse(strJson);
            return json.id_token;
        }

        return null;
    }

In this case, we know the key in the browse session storage:

"oidc.user:{Authority}:{ClientId}"

We do not have to traverse all entries as in a previous case. You can find the token in the console (obfuscated):

eyJhbGciO
***
gv8rlabRQ77LZ8hefyI-AU5Xiohh3g

Paste this to https://jwt.io/ and you should see decoded claims contained in the token.


comments powered by Disqus