none
Refresh an id_token from aspnet core MVC application to access an API RRS feed

  • Question

  • I am working on a aspnet core MVC project which calls an API which is secured by OAuth2.0. I have to pass the id token in the header of the API request.

    I was able to access the API and get the response properly with the code below,

    Startup.cs

    public void ConfigureServices(IServiceCollection services)
            {
                services.Configure<CookiePolicyOptions>(options =>
                {
                    options.CheckConsentNeeded = context => true;
                    options.MinimumSameSitePolicy = SameSiteMode.None;
                });
    
                services.AddAuthentication(options =>
                    {
                        options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                        options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
                        options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                    })
                    .AddCookie()
                    .AddOpenIdConnect(options =>
                    {
                        options.Authority = Configuration["AzureAD:Instance"] + 
                         "/" + Configuration["AzureAD:TenantId"];
                        options.ClientId = Configuration["AzureAD:ClientId"];
                        options.Secret = Configuration["AzureAD:Secret"];
                        options.Callback = Configuration["AzureAD:Callback"];
                        options.ResponseType = "code id_token";
                        options.SaveTokens = true;
                    });
    
                services.AddMvc(options =>
                    {
                        var policy = new AuthorizationPolicyBuilder()
                            .RequireAuthenticatedUser()
                            .Build();
                        options.Filters.Add(new AuthorizeFilter(policy));
                    })
                    .SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
              
            }
    
     public void Configure(IApplicationBuilder app, IHostingEnvironment env)
            {
                ...
                app.UseCookiePolicy();
                app.UseAuthentication();
                app.UseMvc(routes =>
                {
                    routes.MapRoute(
                        name: "sign-in",
                        template: "signin-oidc")};
                       
    
                    ...
    
            });
            }


    Controller.cs

    I am getting the token from the HttpContext.

    But the id_token expires after time, and when I load the MVC app it returns unauthorized. Is there a way to refresh the id token before it expires.
    I tried few examples in stack overflow. But none worked for me.

    Is there a way to get this to work without using the IdentityModel used in example below?
    https://github.com/mderriey/aspnet-core-token-renewal/blob/master/src/MvcClient/Startup.cs

    Few stackoverflows , suggest there is no way to refresh an id_toke, then how would I not let go about doing this?

    Tuesday, July 9, 2019 9:07 PM

All replies

  • Hello, currently we're looking into this issue and will get back to you once we have a response in regards to this. 
    Unfortunately from my understanding you'll have to ask the user to login again. Typically, using the Microsoft Auth libraries (ADAL/MSAL), you can utilize the acquiretokensilentasync method.

    The Wiki for the ADAL library can be found here : https://github.com/AzureAD/azure-activedirectory-library-for-dotnet/wiki

    And the silentasync methods are found here : 

    https://github.com/AzureAD/azure-activedirectory-library-for-dotnet/wiki/AcquireTokenSilentAsync-using-a-cached-token

    https://github.com/AzureAD/azure-activedirectory-library-for-dotnet/wiki/AcquireTokenSilentAsync-using-Integrated-authentication-on-Windows-(Kerberos)

    In addition to that the git library you provided is not a Microsoft supported library, my suggestion is to file an issue against the git repo for more information. 

    https://github.com/mderriey/aspnet-core-token-renewal/issues

    Thanks for your question, 

    Wednesday, July 10, 2019 11:29 PM
    Moderator
  • I'm following up on this, if you're using the code id_token flow you can utilize the authorization code to get an access token and refresh token that you can use to refresh your access and identity token. 

    However if you're solely taking advantage of the Id_token and stopping and not even bothering to get the access token using the auth code, you would have to utilize something along the lines of implicit flow and the acquiretokensilentasync method call per the docs : https://github.com/AzureAD/azure-activedirectory-library-for-dotnet/wiki/AcquireTokenSilentAsync-using-a-cached-token

    If you're interested in trying to implement this yourself my suggestion would be to take a look at this post on refreshing id tokens with implicit flow : https://www.scottbrady91.com/OpenID-Connect/Silent-Refresh-Refreshing-Access-Tokens-when-using-the-Implicit-Flow

    Or take a look at the code in the ADAL .net library.https://github.com/AzureAD/azure-activedirectory-library-for-dotnet/search?q=acquiretokensilentasync&unscoped_q=acquiretokensilentasync

    Please let me know if you have anymore questions within the scope of this thread otherwise please mark a response as answer. Thanks! 

    Thursday, July 11, 2019 12:20 AM
    Moderator
  • I'm following up on this, please remember to mark one of the responses as answer if your question has been answered. If not please let us know if there are anymore questions.
    Friday, July 12, 2019 12:15 AM
    Moderator
  • Thanks Frank.

    I am trying to get access token from a .netcore MVC application using the MSAL.Net.

    I have amended the code in the Startup.cs

    public void ConfigureServices(IServiceCollection services)
            {
                services.Configure<CookiePolicyOptions>(options =>
                {
                    options.CheckConsentNeeded = context => true;
                    options.MinimumSameSitePolicy = SameSiteMode.None;
                });
    
                services.AddAuthentication(options =>
                    {
                        options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                        options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
                        options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                    })
                    .AddCookie(options =>
                    {
                        options.Events= new CookieAuthenticationEvents()
                        {
                            OnValidatePrincipal = OnValidatePrincipal
                        };
                    })
                    .AddOpenIdConnect(options =>
                    {
                        options.Authority = "https://login.microsoftonline.com/{tenantId}/v2.0";
                        options.ClientId = Configuration["AzureAD:ClientId"];
                        options.ClientSecret = Configuration["AzureAD:ClientSecret"];
                        options.CallbackPath = Configuration["AzureAD:CallbackPath"];
                        options.ResponseType = "code id_token";
                        options.Scope.Add("openid");
                        options.Scope.Add("profile");
                        options.Scope.Add("offline_access");
                        options.Scope.Add("api://{ClientidOfAPI}/user_impersonation");
                        options.SaveTokens = true;
                        options.Events= new OpenIdConnectEvents()
                        {
                            OnAuthorizationCodeReceived = OnAuthorizationCodeReceived
                        };
                    });
    
                services.AddMvc(options =>
                {
                    var policy = new AuthorizationPolicyBuilder()
                        .RequireAuthenticatedUser()
                        .Build();
                    options.Filters.Add(new AuthorizeFilter(policy));
                })
                .SetCompatibilityVersion(CompatibilityVersion.Version_2_1); 
               
            }
             
    
             private async Task OnValidatePrincipal(CookieValidatePrincipalContext context)
             {
    
                 var application = GetOrBuildConfidentialClientApplication(context.HttpContext, context.Principal);
                 var accounts = await application.GetAccountsAsync();
                 
                AuthenticationResult result = await application.AcquireTokenSilent(
                    new []{ "openid", "profile", "offline_access", "api://{ClientidOfAPI}/user_impersonation" },
                    accounts.FirstOrDefault()).ExecuteAsync();
                
            }
    
    
             private async Task OnAuthorizationCodeReceived(AuthorizationCodeReceivedContext context)
            {
                var application = GetOrBuildConfidentialClientApplication(context.HttpContext, context.Principal);
    
                var result = await application.AcquireTokenByAuthorizationCode(new [] { "api://{ClientidOfAPI}/user_impersonation" }, context.ProtocolMessage.Code)
                    .ExecuteAsync();
    
                context.HandleCodeRedemption(result.AccessToken, result.IdToken);
            }
            private IConfidentialClientApplication GetOrBuildConfidentialClientApplication(HttpContext httpContext, ClaimsPrincipal claimsPrincipal)
            {
                var request = httpContext.Request;
                string currentUri = UriHelper.BuildAbsolute(request.Scheme, request.Host, request.PathBase, "/signin-oidc" ?? string.Empty);
                string authority = $"https://login.microsoftonline.com/{tenantid}/v2.0";
    
                var app = ConfidentialClientApplicationBuilder.CreateWithApplicationOptions(new ConfidentialClientApplicationOptions()
                    {
                        ClientId = "Clientid of Client,
                        ClientSecret = "password of Client"
                })
                    .WithRedirectUri(currentUri)
                    .WithAuthority(authority)
                    .Build();
                return app;
            }
    
            
            public void Configure(IApplicationBuilder app, IHostingEnvironment env)
            {
                if (env.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                }
                else
                {
                   app.UseHsts();
                }
                ...
    
                app.UseAuthentication();
    
                app.UseMvc();
            }
    		



    I am getting the access_token in the OnAuthorizationCodeReceived method. But when I try to refresh it using the OnValidatePrincipal(), I get no result for the accounts using the below code.

    var accounts = await application.GetAccountsAsync();

    How can I refresh the access_token, as it expires every hour.

    Is there a better was of getting the access_token and refresh them before they expire?



    2 hours 39 minutes ago