Azure-Samples / active-directory-aspnetcore-webapp-openidconnect-v2

An ASP.NET Core Web App which lets sign-in users (including in your org, many orgs, orgs + personal accounts, sovereign clouds) and call Web APIs (including Microsoft Graph)
MIT License
1.38k stars 992 forks source link

When Access Token expires CAE doesn't kick in #657

Open JoeRicci opened 1 year ago

JoeRicci commented 1 year ago

Please provide us with the following information:

This issue is for a: (mark with an x)

- [ ] bug report -> please search issues before submitting
- [ ] feature request
- [X] documentation issue or request
- [ ] regression (a behavior that used to work and stopped in a new release)

The issue was found for the following scenario:

Please add an 'x' for the scenario(s) where you found an issue

  1. Web app that signs in users
    1. [ ] with a work and school account in your organization: 1-WebApp-OIDC/1-1-MyOrg
    2. [ ] with any work and school account: /1-WebApp-OIDC/1-2-AnyOrg
    3. [ ] with any work or school account or Microsoft personal account: 1-WebApp-OIDC/1-3-AnyOrgOrPersonal
    4. [ ] with users in National or sovereign clouds 1-WebApp-OIDC/1-4-Sovereign
    5. [ ] with B2C users 1-WebApp-OIDC/1-5-B2C
  2. Web app that calls Microsoft Graph
    1. [X] Calling graph with the Microsoft Graph SDK: 2-WebApp-graph-user/2-1-Call-MSGraph
    2. [ ] With specific token caches: 2-WebApp-graph-user/2-2-TokenCache
    3. [ ] Calling Microsoft Graph in national clouds: 2-WebApp-graph-user/2-4-Sovereign-Call-MSGraph
  3. [ ] Web app calling several APIs 3-WebApp-multi-APIs
  4. [ ] Web app calling your own Web API
    1. [ ] with a work and school account in your organization: 4-WebApp-your-API/4-1-MyOrg
    2. [ ] with B2C users: 4-WebApp-your-API/4-2-B2C
    3. [ ] with any work and school account: 4-WebApp-your-API/4-3-AnyOrg
  5. Web app restricting users
    1. [ ] by Roles: 5-WebApp-AuthZ/5-1-Roles
    2. [ ] by Groups: 5-WebApp-AuthZ/5-2-Groups
  6. [ ] Deployment to Azure
  7. [ ] Other (please describe)

Repro-ing the issue

Repro steps

Using 2-1-Call-MSGraph as is with replacing my Azure App Service & Azure AD details into the appsettings.json file

Expected behavior

When the Access token expires, I expect that CAE should kick in and and refresh the access token

Actual behavior

Error is thrown invalidAuthenticationToken Message: Access token has expired or is not yet valid.

Possible Solution

Additional context/ Error codes / Screenshots

Any log messages given by the failure

Add any other context about the problem here, such as logs.

OS and Version?

Windows 7, 8 or 10. Linux (which distribution). macOS (Yosemite? El Capitan? Sierra?) Windows 10

Versions

of ASP.NET Core, of MSAL.NET asp.net core 6

Attempting to troubleshooting yourself:

Originally, there was not Refresh Token being issued and had to go into into Resources.azure.com to set the offline access. Th research I did seems to indicate this doesn't work with a free Azure Account, but not sure if that's correct. I coudln't see any option to turn on CAE in the oducmentation I followed

Mention any other details that might be useful

This is my first forray into Azure App Service.


Thanks! We'll be in touch soon.

kastroph commented 1 year ago

We have been recently experiencing this issue since updating to dot net 7.

We are using the in-memory cache when this issue pops up I have to reset the application to fix the issue.

I have set the Absolute Expiration Relative To Now to 20 minutes

Max age 1 day Refresh interval to 20 minutes Automatic Refresh Interval to 1 minute

But this issue still happens after a few days of the production app running which makes it nearly impossible to replicate in devlopment.

` services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme) .AddMicrosoftIdentityWebApp(Options => { configuration.Bind("AzureAd", Options);

                Options.Prompt = "select_account";

                Options.Authority = "https://login.microsoftonline.com/common/v2.0";

                Options.MaxAge = TimeSpan.FromDays(1);

                Options.UseTokenLifetime = false;

                Options.SaveTokens = true;

                Options.RefreshInterval = TimeSpan.FromSeconds(20);
                Options.AutomaticRefreshInterval = TimeSpan.FromMinutes(1);

                Options.ResponseType = OpenIdConnectResponseType.CodeToken;

                Options.Events.OnTokenValidated = async context => {
                    ITokenAcquisition tokenAcquisition = context.HttpContext.RequestServices
                        .GetRequiredService<ITokenAcquisition>();

                    GraphServiceClient graphClient = new GraphServiceClient(
                        new DelegateAuthenticationProvider(async (request) => {
                            string token =
                                await tokenAcquisition.GetAccessTokenForUserAsync(initialScopes,
                                    user: context.Principal);
                            request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
                        }));

                    //IUserRequest request = graphClient.Me.Request();

                    //User user = await request
                    //    .Select(u => new {
                    //        u.DisplayName,
                    //        u.Mail,
                    //        u.UserPrincipalName,
                    //        u.MailboxSettings,
                    //    })
                    //    .GetAsync();
                };

                Options.Events.OnAuthenticationFailed = context => {
                    string error = WebUtility.UrlEncode(context.Exception.Message);
                    context.Response
                        .Redirect($"/Home/ErrorWithMessage?message=Authentication+error&debug={error}");
                    context.HandleResponse();

                    return Task.FromResult(0);
                };

                Options.Events.OnRemoteFailure = context => {
                    if (context.Failure is OpenIdConnectProtocolException) {
                        string error = WebUtility.UrlEncode(context.Failure.Message);

                        context.Response
                            .Redirect($"/Home/ErrorWithMessage?message=Sign+in+error&debug={error}");
                        context.HandleResponse();
                    }

                    return Task.FromResult(0);
                };
            },
                cookieScheme: null, openIdConnectScheme: "AzureAD")
            .EnableTokenAcquisitionToCallDownstreamApi(options => {
                configuration.Bind("AzureAd", options);
            }, initialScopes)
            .AddMicrosoftGraph("https://graph.microsoft.com/v1.0",
                defaultScopes: "User.Read Mail.Send openid offline_access MailboxSettings.Read Calendars.Read")
            .AddInMemoryTokenCaches(optons =>
            optons.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(20)) ;`
crissb3 commented 1 year ago

Any workaround for this issue? I experience the same.

jmprieur commented 1 year ago

@crissb3, @JoeRicci There is a regression in .NET 7.0, related to the options. It should be fixed by the patch of .NET 7.0 that will be released mid february. Meanwhile, there is a workaroud, described in see https://github.com/AzureAD/microsoft-identity-web/issues/1995#issuecomment-1374281775

cc: @kalyankrishna1

crissb3 commented 1 year ago

Did this get fixed in the february 14th release 7.0.3? If so, do I need to upgrade my Nuget packages ("Microsoft.EntityFrameworkCore") to this version? When doing this I am getting this error: Microsoft.Common.CurrentVersion.targets(4862, 5): [MSB3021] Unable to copy file "C:\Users\user\.nuget\packages\microsoft.data.sqlclient.sni.runtime\5.0.1\runtimes\win-arm\native\Microsoft.Data.SqlClient.SNI.dll" to "bin\Debug\net7.0\runtimes\win-arm\native\Microsoft.Data.SqlClient.SNI.dll". Access to the path 'C:\WebPortal_new\webportBB\AppOwnsData\bin\Debug\net7.0\runtimes\win-arm\native\Microsoft.Data.SqlClient.SNI.dll' is denied.

I have tried doing what others suggest online; disabling Read-only for this folder, clearing nuget cache etc. But still getting this error and also still getting the error with CAE not kicking in.

I am using Jetbrains Rider and when selecting target framework I don't get the option to pick 7.0.3, only 7.0 and lower X.0, but guessing this includes 7.0.3?