Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Auth for ASP.NET Core #1163

Merged
merged 15 commits into from
Nov 28, 2018
Merged

Auth for ASP.NET Core #1163

merged 15 commits into from
Nov 28, 2018

Conversation

chrisdunelm
Copy link
Contributor

No description provided.

@googlebot googlebot added the cla: yes This human has signed the Contributor License Agreement. label Feb 19, 2018
@chrisdunelm
Copy link
Contributor Author

Tests still to come.

Copy link
Collaborator

@jskeet jskeet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Drive-by review of just the project file :)

<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>

This comment was marked as spam.

This comment was marked as spam.

</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="2.0.1" />

This comment was marked as spam.

This comment was marked as spam.

var optionsMonitor = _services.GetRequiredService<IOptionsMonitor<OpenIdConnectOptions>>();
var clock = _services.GetRequiredService<ISystemClock>();
var authProperties = auth.Properties;
var options = optionsMonitor.Get(OpenIdConnectDefaults.AuthenticationScheme);

This comment was marked as spam.

This comment was marked as spam.

// TODO: Logging
return null;
}
var optionsMonitor = _services.GetRequiredService<IOptionsMonitor<OpenIdConnectOptions>>();

This comment was marked as spam.

This comment was marked as spam.

@andyfmiller
Copy link

@gijswijs I wrote a sample AspNetCore 2.1-RC1 app that uses a combination of Microsoft's AspNetCore Authentication middleware and Google's .NET Client. No changes or additions are needed to the .NET Client. In a nutshell, I use Microsoft's middleware to get a token, GoogleCredential.FromAccessToken to get the credential, and generated client APIs to use Google services.

All of the interesting code is in Startup.cs and HomeController.cs.

It might work with AspNetCore 2.0.

@mattwoberts
Copy link

Hi, just looking for an update on this?

I've already got google auth in my asp.net core 2.1 web app (.AddGoogle()) but now I want to use the Google APIs for things like calendar integration.

If indeed work is on-going on this PR, is the best advice in the meantime to do something similar to the sample provided by @andyfmiller ?

Thanks

@gijswijs
Copy link

gijswijs commented Jul 4, 2018

@mattwoberts If you have the auth up & running, than you have the hard part behind you. The rest is a matter of adding the correct API package using nuget (https://www.nuget.org/profiles/google-apis-packages) and then start using that.

Presumably you'll get credentials back from the Auth, and with those credentials you can instantiate a Google API service.

It could look like this:

if (result.Credential != null)
            {
                var service = new AnalyticsReportingService(new BaseClientService.Initializer
                {
                    HttpClientInitializer = result.Credential,
                    ApplicationName = "Your Application"
                });
                //YOUR CODE
            }

@mattwoberts
Copy link

Thanks @gijswijs . but right now, I'm totally confused..

I'm using .AddGoogle to authenticate users with my app, when that completes I get the email claim from google, match that to a user in my app, and then log them on:

public async Task<ActionResult> GoogleAuthComplete()
{
    var loginInfo = await _signInManager.GetExternalLoginInfoAsync();
    if (loginInfo == null)
        return RedirectToAction("Login");

    // At this point we know the email address.
    var email = loginInfo.Principal.Claims.Where(c => c.Type == ClaimTypes.Email).Select(c => c.Value).SingleOrDefault();

    // find the user that matches this email, then ..

    await _signInManager.SignInAsync(user, isPersistent:true);
}

But in the spirit of incremental auth, if the user then decides they want to integrate with their calendar, then I send another challenge to google with the new scope (very similar to what @andyfmiller has). Now that works, but what it gives me back isn't a nice UserCredential or anything, but I can get an access token and a refresh token.

I know that I can then make use of the Google API with that access token:

HttpClientInitializer = GoogleCredential.FromAccessToken(accessToken),

But, that token is going to expire in an hour, so I'd need to make use of the refresh token to get another access token... Feels like I'm going about this the wrong way....

@gijswijs
Copy link

gijswijs commented Jul 5, 2018

@mattwoberts Ah, yes. I've been at the exact same point of total confusion. Remember, if you are not confused by oAuth at some point, you're doing it wrong.

.AddGoogle works perfectly if you want users to sign into your application using their Google account. But as far as I figured it out, you can't use it for anything else. So you can't use it to do the oAuth token dance, if you want to access the Google API of your liking. You can only use it to get an email address from a user, that you from then on can consider to be signed in into your application.

Obviously, behind the scenes AddGoogle does that oAuth token dance as well, but sadly it's not possible to use those methods for anything else than interacting with the Google+ API. (Which is what AddGoogle interacts with if I remember correctly)

This was discussed in PR #1109 after @buzallen created that PR to offer an alternative solution for the authentication flow in dotnet core. Based on that PR @chrisdunelm professed his preference for using the OpenIdConnect flow built into ASP.NET Core. This PR is his first stab at that approach. I'm not entirely sure why @chrisdunelm wants to use OpenIdConnect instead of directly use AspNetCore.Authentication.OAuth, which seems like a possibility as well.

Anyhow, I ended up using the approach @buzallen took in PR #1109 , that, although less elegant, is the approach that I had success with. So my advice would be to try to fit his code into your application. Good luck!

@andyfmiller
Copy link

@mattwoberts - Have you tried re-issuing the Challenge when the access token has expired? This snippet checks to see if the access token has expired and re-issues the Challenge if it has. The login_hint parameter (which is the user's email) stops the sign in prompt. The token I get back is good for another hour. The include_granted_scopes parameter is probably not necessary unless there is a chance you may be asking for more scopes at the same time. It does not seem to hurt anything to include it.

            var loginHint = GetUserEmail();
            var accessToken = await HttpContext.GetTokenAsync("ClassList", "access_token");
            var expires = await HttpContext.GetTokenAsync("ClassList", "expires_at");
            DateTime.TryParse(expires, out var expiresAt);

            if (accessToken == null || DateTime.Now > expiresAt)
            {
                return new ChallengeResult("ClassList", new AuthenticationProperties()
                {
                    Parameters =
                    {
                        new KeyValuePair<string, object>("login_hint", loginHint ),
                        new KeyValuePair<string, object>("include_granted_scopes", true)
                    },
                    RedirectUri = Url.Action("ListCourses")
                });
            }

@gijswijs
Copy link

gijswijs commented Jul 6, 2018

@andyfmiller interesting approach. How would you go about instantiating a AnalyticsReportingService for instance?
You still need the credentials for that, right? I don't directly understand how you would do that, using your code.

@mattwoberts
Copy link

Cheers @andyfmiller and @gijswijs for the help here ;)

@andyfmiller - the issue that I have is that I need to do the oauth dance, get a refresh token, and then use that going forwards to do things from the back end - that aren't user-driven. So I can't issue another challenge to the user.

I have however got something working - I've not yet looked at the code in PR #1109 but here's what I have:

Firstly, I've got a second AddGoogle, similar to what @andyfmiller does in his sample:

.AddGoogle("GoogleCalendar","GoogleCalendar", googleOptions =>
{
    googleOptions.CallbackPath = new PathString("/signin-google-calendar");
    googleOptions.ClientId = "***";
    googleOptions.ClientSecret = "***";
    googleOptions.AccessType = "offline";
    googleOptions.SaveTokens = true;
    googleOptions.Scope.Add(Google.Apis.Calendar.v3.CalendarService.Scope.Calendar);
});

Then, in my controller, I have an action method that is responsible for adding my google calendar integration (so once added, my backend services will use it long-term). So I check for tokens (hat-tip again to @andyfmiller):

var redirectUrl = Url.Action("GoogleCalendar", "Integrations");

var loginHint = _currentUser.User.Email;
var accessToken = await HttpContext.GetTokenAsync("GoogleCalendar", "access_token");
var refreshToken = await HttpContext.GetTokenAsync("GoogleCalendar", "refresh_token");
var expires = await HttpContext.GetTokenAsync("GoogleCalendar", "expires_at");

DateTime.TryParse(expires, out var expiresAt);

if (accessToken == null || DateTime.Now > expiresAt)
{
    return new ChallengeResult("GoogleCalendar", new AuthenticationProperties()
    {
        Parameters =
        {
            new KeyValuePair<string, object>("login_hint", loginHint ),
            new KeyValuePair<string, object>("include_granted_scopes", true)
        },
        RedirectUri = redirectUrl
    });
}

Once I've done all that, then I've got a refresh token from google :) So then, I pass that over to the google APIs and let it do its thing:

var flow = new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer
{
    
    ClientSecrets = new ClientSecrets
    {
        ClientId = "***",
        ClientSecret = "***"
    },
    Scopes = new[] { CalendarService.Scope.CalendarReadonly },
    DataStore = _dataStore // I have my own db-based IDataStore.
});

var tokenResponse = new TokenResponse
    {AccessToken = accessToken, RefreshToken = refreshToken, TokenType = "offline"};

var c = new UserCredential(flow,"user",tokenResponse);

I now have a UserCredential, plus I know everything is being taken care of via the flow, and my refresh token.

Feel free to tell me I've done it all wrong :)

@chrisdunelm chrisdunelm mentioned this pull request Aug 6, 2018
@mattwoberts
Copy link

Hi all. Just revisiting my code around this, and while it's working for me (Using the built in asp.net core OpenIdConnect bits, I just wondered what the story is with this PR? Surely there is quite a demand for asp.net core users to be able to use this lib?

@gijswijs
Copy link

I would like to stress my interest for this as well. I'd love to yank out my crappy code for something proper.

@rv-dasglobtech
Copy link

I was not able to complete google authentication for Google drive API in ASP.net core 2.0 so I followed the following a link for console project and then applied the same process for ASP.net core 2.0.
https://www.c-sharpcorner.com/article/view-content-of-your-google-drive-using-net/
I can authentication now but I am not able to get google drive file list.
I am getting files to count 0 by the following code.

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Drive.v3;
using Google.Apis.Drive.v3.Data;
using Google.Apis.Services;
using Google.Apis.Util.Store;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ThriivDental.Controllers
{
public class TestController : BaseController
{
public IActionResult Authenticate()
{
UserCredential credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
new ClientSecrets
{
ClientId = "*******************************************************",
ClientSecret = "***********************"

           },
           new[] { DriveService.Scope.Drive },
           "user",
           CancellationToken.None).Result;

		   // Create the service.
        var service = new DriveService(new BaseClientService.Initializer()
        {
            HttpClientInitializer = credential,
            ApplicationName = "thriivdental3",
        });

        // Define parameters of request.
        FilesResource.ListRequest listRequest = service.Files.List();
        listRequest.PageSize = 10;
        listRequest.Fields = "nextPageToken, files(id, name)";

        // List files.
        IList<Google.Apis.Drive.v3.Data.File> files = listRequest.Execute()
             .Files;

        ViewBag.filecount = files.Count;

        if (files != null && files.Count > 0)
        {
            foreach (var file in files)
            {
               ViewBag.fileName = file.Name;
            }
        }
        return View("Test");

    }
}

}Please provide me solution.

@mattwoberts
Copy link

This is looking good, must be nice being able to call on @jskeet for code reviews ;)

@mattwoberts
Copy link

Something that might be relevant, since you're plugging into OIDC - there is a bug/issue in safari where the asp.net core SameSite cookie settings mean that the post back to your app will fail.

It's pretty simple to reproduce - from looking at your integration test @chrisdunelm I think you should find it doesn't work in the latest safari (I'm on Version 12.0.1 (14606.2.104.1.1))

There are a number of workarounds posted, but so far the only success I've had personally is to set the cookie as follows:

.AddCookie(opts => { opts.Cookie.SameSite = SameSiteMode.None; })

@chrisdunelm
Copy link
Contributor Author

@mattwoberts thanks for pointing out the potential Safari problem. I can't check this immediately as Safari is no longer available for Windows, and I don't have an easy way to test this on a Mac right now. As this is a known OIDC issue, I'll probably go ahead with an initial beta, then see if we can work-around it for a beta02 release.

Copy link
Collaborator

@jskeet jskeet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've looked through the "address PR comments" commit and it looks good. Happy to look at anything else you'd like me to take a closer look at, but if not, feel free to merge.

@chrisdunelm chrisdunelm changed the title [Do not merge] Auth for ASP.NET Core Auth for ASP.NET Core Nov 20, 2018
@chrisdunelm
Copy link
Contributor Author

@jskeet Please could you check the csproj, especially the package title and description.
And do you think Google.Apis.Auth.AspNetCore is a reasonable package name?
I think I'll hold off on merging this until next week, so we can touch base beforehand, and so it won't be inadvertently auto-released ;)

@andyfmiller
Copy link

andyfmiller commented Nov 20, 2018 via email

@chrisdunelm
Copy link
Contributor Author

@andyfmiller Thanks.

@mattwoberts, @andyfmiller As far as you can see, does this fulfill the requirements you have for an Google ASP.NET auth package? I.e. Auth with Google; support for incremental auth; access via DI to Google credentials and scopes; and the GoogleScopedAuthorize attribute to require specific scope(s) for a MVC handler?

One extra feature that I would hope to implement soon is a programmatic scope check and (incremental) re-challenge if scope(s) isn't yet authorized.
Would this also be useful?

Thanks.

@andyfmiller
Copy link

That is a great list! I'll look at it more deeply this weekend.

Copy link
Collaborator

@jskeet jskeet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few thoughts about the project file. (I didn't look at the integration tests project file; can do that later if it's deemed useful.)

<Import Project="..\CommonProjectProperties.xml" />

<PropertyGroup>
<!-- Only ASP.NET Core 2.0 on netstandard2.0 supported -->

This comment was marked as spam.

This comment was marked as spam.

<!-- Only ASP.NET Core 2.0 on netstandard2.0 supported -->
<TargetFramework>netstandard2.0</TargetFramework>
<!-- Beta release -->
<Version>$(Version)-beta01</Version>

This comment was marked as spam.

This comment was marked as spam.

<Version>$(Version)-beta01</Version>
</PropertyGroup>

<!-- nupkg information -->

This comment was marked as spam.

This comment was marked as spam.

<PackageReference Include="Microsoft.AspNetCore.Authorization" Version="2.0.4" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Abstractions" Version="2.0.4" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.0.4" />
<ProjectReference Include="..\Google.Apis.Auth\Google.Apis.Auth.csproj" />

This comment was marked as spam.

This comment was marked as spam.

Supports incremental auth, and an injectable IGoogleAuthProvider to supply Google credentials.

Supported Platforms:
- ASP.NET Core 2.x on netstandard2.x

This comment was marked as spam.

This comment was marked as spam.

@andyfmiller
Copy link

andyfmiller commented Nov 24, 2018

This makes the app code much simpler. I was able to remove quite a bit of code from my MVC sample which allows the user to sign in (no special scopes), then list their Google Classroom courses (which requires "https://www.googleapis.com/auth/classroom.courses.readonly"). For example, the following 4 lines of code replaced 2 AppFlowMetaData files and about 30 lines of code in the controller:

[GoogleScopedAuthorize("https://www.googleapis.com/auth/classroom.courses.readonly")]
public async Task<IActionResult> ListCourses()
{
    var cred = await _auth.GetCredentialAsync();

However I lost the ability to pass in a login hint with the request for additional scope. Passing in a login hint greatly simplifies the UX for additional scope. Is there a way to supply a login hint to the incremental authorization request?

The full sample is here: https://github.com/andyfmiller/google-incremental-auth-sample/tree/master/src/GoogleIncrementalMvcSample


After some experimentation, I found that I could add a LoginHint by handling OnRedirectToIdentityProvder in ConfigureServices:

options.Events.OnRedirectToIdentityProvider = MyRedirectToIdentityProviderHandler;

And set LoginHint to the current user's email:

        private Task MyRedirectToIdentityProviderHandler(RedirectContext context)
        {
            var user = context.HttpContext.User;

            if (user.Identity.IsAuthenticated)
            {
                context.ProtocolMessage.LoginHint = user.Claims.SingleOrDefault(c => c.Type == ClaimTypes.Email)?.Value;
            }

            return Task.FromResult(0);
        }

I can see the prompt in the authorization request to google, but google is still prompting me to select my account prior to showing me the consent screen for the additional scope. Is there any way to disable the step of selecting my account again?

@chrisdunelm
Copy link
Contributor Author

@andyfmiller The login_hint is now set for incremental auth. However, I agree that account selection is still occurring. This may be intentional, and is pre-selecting the correct account, but that still needs confirming by the user?

@chrisdunelm
Copy link
Contributor Author

I am seeing a problem with incremental auth.
If there are two different required increments of auth, e.g. one action requires storage, another requires translate (as in the test in this PR), then the incremental auth appears to "forget" about the 1st increment when the 2nd increment is authorized.
The steps are:

  1. Initial auth with no scopes happens successfully.
  2. Incremental auth to add storage scope happens successfully; storage can be accessed.
  3. Incremental auth to add translate scope appears to happen successfully; translate can be accessed.
  4. Trying to access storage again fails, because it appears that the previously authorized storage scope has been "forgotten".

I'm investigating to work out why this is happening.

@andyfmiller
Copy link

@andyfmiller The login_hint is now set for incremental auth. However, I agree that account selection is still occurring. This may be intentional, and is pre-selecting the correct account, but that still needs confirming by the user?

Thank you for including login_hint with incremental auth. I think it is a good idea even if it is not eliminating the account re-selection.

It has occurred to me that account re-selection is occurring because my client has not been verified by Google (it is just for development/test like this) so accounts.google.com is being extra cautious. If I was using a verified client, the account re-selection might go away.

@chrisdunelm
Copy link
Contributor Author

I'm using a verified account for testing, and I'm still seeing the account selection.

@chrisdunelm
Copy link
Contributor Author

Possibly relevant SO question about the incremental auth: https://stackoverflow.com/questions/51495056/google-oauth-2-0-incremental-authorization-with-offline-access

@andyfmiller
Copy link

I'm using a verified account for testing, and I'm still seeing the account selection.

Bummer. I've also noticed that when I sign out (await HttpContext.SignOutAsync();), Google forgets that I have consented. This will make young student facing apps very hard to use :(.

@chrisdunelm
Copy link
Contributor Author

The problem I was having with incremental auth was due to using the incorrect type of oauth credential. Using the correct "web" type means this now works as expected.
I think this is now ready for a beta01 release.
Possibly things to understand/resolve for beta02 are the sign-out behaviour when re-signing-in; and the account selection.

@chrisdunelm chrisdunelm merged commit a96967d into googleapis:master Nov 28, 2018
@chrisdunelm chrisdunelm deleted the aspnetcore branch November 28, 2018 14:07
@andyfmiller
Copy link

Congratulations!

@chrisdunelm
Copy link
Contributor Author

@andyfmiller :)
The beta01 version is now published: https://www.nuget.org/packages/Google.Apis.Auth.AspNetCore/1.36.1-beta01

@mattwoberts
Copy link

This is great @chrisdunelm! Sorry I’ve not had chance to try it out yet but I’m going to plumb it in on Monday and test it out👍

@oishiimendesu
Copy link

@amakrf
Copy link

amakrf commented Jun 19, 2019

I followed the example in Google.Apis.Auth.AspNetCore.IntegrationTests - which worked great the way it was.

However, when I try to introduce Identity to the application via Startup.cs, I keep getting redirected back to the account selector/sign-in page after I select my account. But as soon as I remove Identity, it works again. More specifically, when I choose my account, the application redirects to /Account/Login every time I select the account. Here is the /Account/Login code:

public IActionResult Login(string returnUrl)
{
	var properties = new AuthenticationProperties { RedirectUri = returnUrl };
	return Challenge(properties, GoogleOpenIdConnectDefaults.AuthenticationScheme);
}

Here is my Startup.cs snippet which introduces Identity and services.ConfigureApplicationCookie():

.... snip ....

// Not in sample code.
services.AddDbContext<ApplicationDbContext>(options =>
	options.UseSqlServer(_config.GetConnectionString("AuthConnection")), 
ServiceLifetime.Scoped);

// Not in sample code.
services.AddIdentity<ApplicationUser, IdentityRole>()
	.AddEntityFrameworkStores<ApplicationDbContext>()
	.AddDefaultTokenProviders();

// Not in sample code.
services.ConfigureApplicationCookie(options =>
{
	options.ExpireTimeSpan = TimeSpan.FromDays(7);
	options.LoginPath = "/Account/Login";
	options.CookieManager = new ChunkingCookieManager();
	options.Cookie = new CookieBuilder
	{
		Name = ".AUTHXCOOKIE",
		Domain = ".DOMAIN.COM"
		IsEssential = true
	};
});

// From sample code, but notice how I removed ".AddCookie()" beneath ".AddAuthentication()"
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddGoogleOpenIdConnect(options =>
{
	var clientInfo = (ClientInfo)services.First(x => x.ServiceType == typeof(ClientInfo)).ImplementationInstance;
	options.ClientId = clientInfo.ClientId;
	options.ClientSecret = clientInfo.ClientSecret;
});

services.AddMvc();

Does this possibly have something to do with the options in .AddAuthentication() (do I need to manually set different types of schemes)?

I'm going off of how I have my current Startup.cs that is successfully setup with services.AddAuthentication().AddGoogle(...)

Am I going about this the wrong way?

Here are the logs for /Account/Login

Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Executed action method WebApplication4.Controllers.AccountController.Login (WebApplication4), returned result Microsoft.AspNetCore.Mvc.ChallengeResult in 18649.1559ms.
Microsoft.AspNetCore.Mvc.ChallengeResult:Information: Executing ChallengeResult with authentication schemes (GoogleOpenIdConnect).
Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler:Information: AuthenticationScheme: GoogleOpenIdConnect was challenged.
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Executed action WebApplication4.Controllers.AccountController.Login (WebApplication4) in 18665.764ms
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 18675.6015ms 302 
The thread 0x402c has exited with code 0 (0x0).
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 POST http://localhost:44392/signin-oidc application/x-www-form-urlencoded 841
Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler:Information: AuthenticationScheme: Identity.External signed in.
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 157.2983ms 302 
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 GET http://localhost:44392/home/showtokens  
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Route matched with {action = "ShowTokens", controller = "Home"}. Executing action WebApplication4.Controllers.HomeController.ShowTokens (WebApplication4)
Microsoft.AspNetCore.Authorization.DefaultAuthorizationService:Information: Authorization failed.
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Authorization failed for the request at filter 'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter'.
Microsoft.AspNetCore.Mvc.ChallengeResult:Information: Executing ChallengeResult with authentication schemes ().
Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler:Information: AuthenticationScheme: Identity.Application was challenged.
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Executed action WebApplication4.Controllers.HomeController.ShowTokens (WebApplication4) in 9.3813ms
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 16.6269ms 302 
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 GET http://localhost:44392/Account/Login?ReturnUrl=%2Fhome%2Fshowtokens  
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Route matched with {action = "Login", controller = "Account"}. Executing action WebApplication4.Controllers.AccountController.Login (WebApplication4)
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Executing action method WebApplication4.Controllers.AccountController.Login (WebApplication4) with arguments (/home/showtokens) - Validation state: Valid

@chrisdunelm
Copy link
Contributor Author

@amakrf Please can you open an issue for this, rather than discussing it in this PR.
Or, if this is the same problem you reported in #1413 then please let me know and we can re-open that issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cla: yes This human has signed the Contributor License Agreement.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants