0
votes

In the Startup.Auth.cs, on the AuthorizationCodeReceived notification, I receive both the accessToken (lifetime 1h) and the refreshToken (24h). The problem is I don't know when to request a new access token and how to request it. A full-code example would be very useful, as I am a noob, regarding adfs and owin.

The users are, at some point, redirected to the adfs and then back to the website, but they lose their session and errors occur.

here's the full code dump:

public partial class Startup
{
    private readonly string authority = ConfigurationManager.AppSettings["auth:Authority"];
    private readonly string clientId = ConfigurationManager.AppSettings["auth:ClientId"];
    private readonly string clientSecret = ConfigurationManager.AppSettings["auth:ClientSecret"];
    private readonly string metadataAddress = ConfigurationManager.AppSettings["auth:MetadataAddress"];

    private readonly string postLogoutRedirectUri = ConfigurationManager.AppSettings["auth:PostLogoutRedirectUri"];
    private readonly string redirectUri = ConfigurationManager.AppSettings["auth:RedirectUri"];
    private readonly string tokenEndpoint = ConfigurationManager.AppSettings["auth:TokenEndpoint"];

    public void ConfigureAuth(IAppBuilder app)
    {
        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationType = "Cookies",
            CookieHttpOnly = true
        });

        app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
        {
            Authority = this.authority,
            ClientId = this.clientId,
            ClientSecret = this.clientSecret,
            MetadataAddress = this.metadataAddress,
            RedirectUri = this.redirectUri,
            ResponseType = "code id_token",
            Scope = "offline_access openid profile customscope",
            RequireHttpsMetadata = false, //bool.Parse(ConfigurationManager.AppSettings["IsProduction"]),
            PostLogoutRedirectUri = this.postLogoutRedirectUri,
            SignInAsAuthenticationType = "Cookies",
            AuthenticationMode = AuthenticationMode.Active,
            UseTokenLifetime = false,

            Notifications = new OpenIdConnectAuthenticationNotifications
            {
                AuthorizationCodeReceived = async n =>
                {
                    // use the code to get the access and refresh token
                    var tokenClient = new TokenClient(
                        this.tokenEndpoint,
                        this.clientId,
                        this.clientSecret);

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

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

                    var handler = new JwtSecurityTokenHandler();
                    var identityToken = handler.ReadJwtToken(tokenResponse.IdentityToken);
                    var upn = identityToken.Claims.ToList().FirstOrDefault(c => c.Type == "upn")?.Value;

                    var localUser = new UserReader().GetByUpn(upn);

                    // mandatory for logout user
                    var id = new ClaimsIdentity(n.AuthenticationTicket.Identity.AuthenticationType);

                    if (localUser?.Id != null)
                    {
                        id.AddClaim(new Claim(ClaimTypes.Upn, localUser.Upn));
                        id.AddClaim(new Claim("Id", localUser.Id.ToString()));
                        id.AddClaim(new Claim("Name", localUser.Name));
                        id.AddClaim(new Claim("RoleId", localUser.Role.Id.ToString()));
                        id.AddClaim(new Claim("RoleName", localUser.Role.Name));
                        id.AddClaim(new Claim("IsOffice", localUser.Role.IsOffice.ToString()));
                        id.AddClaim(new Claim("IsInvestment", localUser.Role.IsInvestment.ToString()));
                    }

                    id.AddClaim(new Claim("identityToken", tokenResponse.IdentityToken));
                    id.AddClaim(new Claim("access_token", tokenResponse.AccessToken));
                    id.AddClaim(new Claim("expires_at",
                        DateTime.UtcNow.AddSeconds(tokenResponse.ExpiresIn).ToString(CultureInfo.InvariantCulture)));
                    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(
                        new ClaimsIdentity(id.Claims, n.AuthenticationTicket.Identity.AuthenticationType, "name",
                            "role"),
                        n.AuthenticationTicket.Properties);
                },
                RedirectToIdentityProvider = n =>
                {
                    if (n.ProtocolMessage.RequestType == OpenIdConnectRequestType.Logout)
                    {
                        // valoarea idTokenHint nu persistă și fără, nu face redirect către login, imediat după log-out

                        var idTokenHint = n.OwinContext.Authentication.User.FindFirst("id_token");

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

                    n.ProtocolMessage.PostLogoutRedirectUri = this.postLogoutRedirectUri;
                    return Task.FromResult(0);
                },
                AuthenticationFailed = (context) =>
                {
                    if (context.Exception.Message.Contains("IDX21323") || context.Exception.Message.Contains("IDX10311"))
                    {
                        // Cateodata da eroare ca nu gaseste nonce cookie, si atunci trebuie relogat la ADFS
                        context.HandleResponse();
                        context.OwinContext.Authentication.Challenge();
                    }


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

1 Answers

0
votes

To use the refresh token, make a POST request to the ADFS token endpoint with:

grant_type=refresh_token

Include the refresh token as well as the client credentials.

e.g.

https://ADFS tenant/oauth/token?grant_type=refresh_token&client_id=CLIENT_ID&client_secret=CLIENT_SECRET&refresh_token=REFRESH_TOKEN

The thing is that the MSAL library should handle this for you.

You don't need to write the code.

Have a look at the code samples here under ADAL / MSAL.