aspnet / AspNetKatana

Microsoft's OWIN implementation, the Katana project
Apache License 2.0
967 stars 333 forks source link

AuthenticationTicket is null in OnAuthorizationCodeReceived for code flow #442

Closed quanth29 closed 10 months ago

quanth29 commented 2 years ago

I'm using OpenIdConnectAuthentication with code flow to implement the OpenIdConnect login. But on the AuthorizationCodeReceived, the property notification.AuthenticationTicket is null value. Any advice? Here is my startup:

public void Configuration(IAppBuilder app)
        {
            app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
            string auth0RedirectUri = "http://localhost:44335/";
            app.UseCookieAuthentication(new CookieAuthenticationOptions(){});
            app.UseOpenIdConnectAuthentication(
                new OpenIdConnectAuthenticationOptions
                {
                    AuthenticationType = "OIDC",
                    ClientId = "qKu-JoUguDjzrvBm*****",
                    ClientSecret = "w7JPnYYIttT8aDYPrZL9lvQzNaXP0QDqyVMu4AHZYWkUrczG4WJThmo3blHEvfz*******",
                    Authority = "https://******/authorize",
                    RedirectUri= auth0RedirectUri,
                    ResponseType = OpenIdConnectResponseType.Code,
                    Scope =  OpenIdConnectScope.Email+" "+OpenIdConnectScope.OpenIdProfile,

                    TokenValidationParameters = new TokenValidationParameters()
                    {
                        ValidateIssuer = false // This is a simplification
                    },
                    Notifications = new OpenIdConnectAuthenticationNotifications
                    {
                        AuthorizationCodeReceived = (notification) =>
                        {
                            Debug.WriteLine("*** AuthorizationCodeReceived");

                            //TODO: get access token from token endpoint later

                            var authClaim = new ClaimsIdentity("OIDC", ClaimsIdentity.DefaultNameClaimType, ClaimsIdentity.DefaultRoleClaimType);
                            authClaim.AddClaim(new System.Security.Claims.Claim("Email","abc@mail.com"));

                            // notification.AuthenticationTicket is null 
                            notification.AuthenticationTicket = new AuthenticationTicket(authClaim, notification.AuthenticationTicket.Properties);

                            return Task.FromResult(0);
                        },
                        AuthenticationFailed = (context) =>
                        {
                            Debug.WriteLine("*** AuthenticationFailed");
                            return Task.FromResult(0);
                        },
                    },
                    UsePkce = false
                });
        }
justinjxzhang commented 2 years ago

As you're using OpenIdConnectResponseType.Code you either need to set OpenIdConnectOptions.RedeemCode to true, or exchange your authorization code for a token and set the TokenEndpointResponse accordingly.

You can see in the middleware code that this is where your AuthorizationCodeReceived notification is called and there is no AuthenticationTicket passed to you (as this only happens when an ID token is received in the response): https://github.com/aspnet/AspNetKatana/blob/dev/src/Microsoft.Owin.Security.OpenIdConnect/OpenidConnectAuthenticationHandler.cs#L431

If you want to let the middleware generate the AuthenticationTicket for you to manipulate, I suggest you do so in another notification, e.g. in the SecurityTokenValidated notification as you can see the `AuthenticationTicket is already given to you. https://github.com/aspnet/AspNetKatana/blob/dev/src/Microsoft.Owin.Security.OpenIdConnect/OpenidConnectAuthenticationHandler.cs#L495-L503

See this other open issue which is in a similar area to the problem you're facing.

quanth29 commented 2 years ago

Thanks, I have already fixed it. But why don’t set RedeemCode = true automatically if the reponse_type = code ?

justinjxzhang commented 2 years ago

That's a question for a maintainer - though consider this:

private bool _redeemCodeValue = false;

public bool RedeemCode {
    get {
        return this.ResponseType == OpenIdConnectResponseType.Code ? true : _redeemCodeValue;
    }
    set {
        this._redeemCodeValue = value;
    }
}

That seems a lot more confusing to me, not to mention it wouldn't work if I were to try to set RedeemCode to false and then we'd need another level of indirection to check whether the false value is a result of the default false or the explicitly set false.

Tratcher commented 2 years ago

But why don’t set RedeemCode = true automatically if the reponse_type = code ?

Automatic code redemption was added recently and was made opt in to avoid breaking people that had been doing it manually.