IdentityServer / IdentityServer3.AccessTokenValidation

OWIN Middleware to validate access tokens from IdentityServer3
Apache License 2.0
91 stars 149 forks source link

Using UseIdentityServerBearerTokenAuthentication returning 401 with new token #116

Closed mribichich closed 7 years ago

mribichich commented 7 years ago

Hi there, I've been trying to use the UseIdentityServerBearerTokenAuthentication , but it's not working all the time.

I couldn't find a way to debug it or enable logging to see how its working.

I have an MVC app with hybrid flow, an API (the one with the problem) and an identity server.

This works most of the times fine. I can login, and call my API from the MVC app without a problem.

But if I leave the webpage open for a while, less than the expire time, and I refresh the page and get a new access_token, when I call the API, it returns 401. Even though its actually authenticated.

If I see the logs from identity server it seems that the API its calling the server and asking for the info, and the server is returning token success, but the API returns 401.

If I refresh the page a couple of times, it works again.

Is there a way to debug the MW or enable logging? I can not figure out why it does that.

This is my setup:

MVC:

AntiForgeryConfig.UniqueClaimTypeIdentifier = "sub";
            JwtSecurityTokenHandler.InboundClaimTypeMap = new Dictionary<string, string>();

            app.UseCookieAuthentication(new CookieAuthenticationOptions
            {
                AuthenticationType = "Cookies",
                CookieSecure = CookieSecureOption.SameAsRequest
            });

            app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
            {
                ClientId = ClientId,
                Authority = config.IdentityServerUrl,
                RedirectUri = config.ServiceUrl,
                PostLogoutRedirectUri = config.ServiceUrl,

                ResponseType = "code id_token",
                Scope = "openid profile offline_access roles all_claims permissions Sis.Presentismo.Api",

                TokenValidationParameters = new TokenValidationParameters
                {
                    NameClaimType = "name",
                    RoleClaimType = "role"
                },

                SignInAsAuthenticationType = "Cookies",

                Notifications = new OpenIdConnectAuthenticationNotifications
                {
                    SecurityTokenValidated = async n =>
                    {
                        n.AuthenticationTicket.Properties.IsPersistent = true;
                    },

                    MessageReceived =  n =>
                        {
                            return Task.FromResult(0);
                        },

                    AuthorizationCodeReceived = async n =>
                    {
                        // use the code to get the access and refresh token
                        var tokenClient = new TokenClient(
                            n.Options.Authority + "/connect/token",
                            ClientId,
                            SecretClient);

                        var tokenResponse = await tokenClient.RequestAuthorizationCodeAsync(n.Code, n.RedirectUri);

                        if (tokenResponse.IsError)
                        {
                            // todo: tokenResponse.IsError
                            throw new Exception(tokenResponse.Error);
                        }

                        // use the access token to retrieve claims from userinfo
                        var userInfoClient = new UserInfoClient(n.Options.Authority + "/connect/userinfo");

                        var userInfoResponse = await userInfoClient.GetAsync(tokenResponse.AccessToken);

                        // create new identity
                        var id = new ClaimsIdentity(n.AuthenticationTicket.Identity.AuthenticationType, "name", "role");

                        id.AddClaims(userInfoResponse.Claims);
                        id.AddClaim(new Claim("access_token", tokenResponse.AccessToken));
                        id.AddClaim(new Claim("expires_at", DateTime.Now.AddSeconds(tokenResponse.ExpiresIn).ToLocalTime().ToString()));
                        id.AddClaim(new Claim("refresh_token", tokenResponse.RefreshToken));
                        id.AddClaim(new Claim("id_token", n.ProtocolMessage.IdToken));
                        id.AddClaim(new Claim("sid", n.AuthenticationTicket.Identity.FindFirst("sid").Value));

                        n.AuthenticationTicket = new AuthenticationTicket(id, n.AuthenticationTicket.Properties);
                    },

                    RedirectToIdentityProvider = n =>
                    {
                        // if signing out, add the id_token_hint
                        if (n.ProtocolMessage.RequestType == OpenIdConnectRequestType.LogoutRequest)
                        {
                            var idTokenHint = n.OwinContext.Authentication.User.FindFirst("id_token");

                            if (idTokenHint != null)
                            {
                                n.ProtocolMessage.IdTokenHint = idTokenHint.Value;
                            }
                        }

                        return Task.FromResult(0);
                    }
                }
            });

API:

        private const string ClientId = "Sis.Presentismo.Api";
        private const string SecretClient = ClientId + "-secret";

JwtSecurityTokenHandler.InboundClaimTypeMap.Clear();

            app.UseIdentityServerBearerTokenAuthentication(new IdentityServerBearerTokenAuthenticationOptions
            {
                Authority = config.IdentityServerUrl,
                ValidationMode = ValidationMode.ValidationEndpoint,

                RequiredScopes = new[] { ClientId },

                ClientId = ClientId,
                ClientSecret = SecretClient
            });

Server logs:

2016-10-19 12:21:52.969 -03:00 [Debug] Start scope validation
2016-10-19 12:21:52.969 -03:00 [Debug] Start parsing Basic Authentication secret
2016-10-19 12:21:52.969 -03:00 [Debug] Parser found secret: "BasicAuthenticationSecretParser"
iisexpress.exe Information: 0 : 2016-10-19 12:21:52.969 -03:00 [Information] Secret id found: "Sis.Presentismo.Api"
2016-10-19 12:21:52.969 -03:00 [Debug] Secret validator success: "HashedSharedSecretValidator"
iisexpress.exe Information: 0 : 2016-10-19 12:21:52.969 -03:00 [Information] Scope validation success
iisexpress.exe Information: 0 : 2016-10-19 12:21:52.974 -03:00 [Information] Start access token validation
iisexpress.exe Information: 0 : 2016-10-19 12:21:52.982 -03:00 [Information] "Token validation success"

thanks!

leastprivilege commented 7 years ago

Well - check the docs:

https://identityserver.github.io/Documentation/docsv2/consuming/diagnostics.html

mribichich commented 7 years ago

great thanks! I didn't find it before. my bad