Skip to content

Instantly share code, notes, and snippets.

@chrisjmccrum
Last active November 14, 2017 17:34
Show Gist options
  • Select an option

  • Save chrisjmccrum/3e3bf3cc7c2f32d89ecb323653f2f603 to your computer and use it in GitHub Desktop.

Select an option

Save chrisjmccrum/3e3bf3cc7c2f32d89ecb323653f2f603 to your computer and use it in GitHub Desktop.
AuthenticationHelper for WebApp Cookie Auth
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using AspNet.Security.OpenIdConnect.Client;
using AspNet.Security.OpenIdConnect.Primitives;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.Extensions.Configuration;
namespace ASPNET_Core_1_0
{
public class CustomCookieAuthenticationEvents : CookieAuthenticationEvents
{
private readonly OpenIdConnectClient _client;
private readonly IConfiguration _config;
public CustomCookieAuthenticationEvents(
OpenIdConnectClient client,
IConfiguration config
)
{
_client = client;
_config = config;
}
public override async Task ValidatePrincipal(CookieValidatePrincipalContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
// Try to resolve the expiration date from the authentication properties.
var expiration = context.Properties.GetTokenValue("expires_at");
if (string.IsNullOrEmpty(expiration))
{
return;
}
// If the token is still valid, skip the additional validation logic.
if (DateTimeOffset.UtcNow < (DateTimeOffset.Parse(expiration) - TimeSpan.FromMinutes(5)))
{
return;
}
var token = context.Properties.GetTokenValue(OpenIdConnectConstants.Parameters.RefreshToken);
if (string.IsNullOrEmpty(token))
{
return;
}
var request = new OpenIdConnectRequest
{
ClientId = _config["OpenId:ClientId"],
ClientSecret = _config["OpenId:ClientSecret"],
GrantType = OpenIdConnectConstants.GrantTypes.RefreshToken,
RefreshToken = token
};
var response = await _client.PostAsync(_config["OpenId:TokenEndpoint"], request);
// If an error was returned by the authorization server, invalidate the cookie.
if (!string.IsNullOrEmpty(response.Error) || string.IsNullOrEmpty(response.AccessToken) ||
string.IsNullOrEmpty(response.IdToken))
{
context.RejectPrincipal();
await context.HttpContext.SignOutAsync(context.Scheme.Name);
return;
}
var tokens = GetTokens(response).ToList();
// If no refresh token was returned in the token response, keep using the old token.
if (!tokens.Any(item => item.Value == OpenIdConnectConstants.Parameters.RefreshToken))
{
tokens.Add(new AuthenticationToken
{
Name = OpenIdConnectConstants.Parameters.RefreshToken,
Value = token
});
}
context.Properties.StoreTokens(tokens: tokens);
context.ReplacePrincipal(principal: GetPrincipal(response));
context.ShouldRenew = true;
}
public ClaimsPrincipal GetPrincipal(OpenIdConnectResponse response)
{
// Validating the identity token is not necessary,
// as it's retrieved using backchannel communication.
var token = new JwtSecurityToken(response.IdToken);
// Create a new identity containing the claims retrieved from the identity token.
var identity = new ClaimsIdentity(token.Claims, CookieAuthenticationDefaults.AuthenticationScheme);
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, token.Payload.Sub));
// identity.AddClaim(new Claim(ClaimTypes.Name, (string) token.Payload["unique_name"]));
return new ClaimsPrincipal(identity);
}
public IEnumerable<AuthenticationToken> GetTokens(OpenIdConnectResponse response)
{
if (response == null)
{
throw new ArgumentNullException(nameof(response));
}
yield return new AuthenticationToken
{
Name = OpenIdConnectConstants.Parameters.AccessToken,
Value = response.AccessToken
};
// Note: the refresh_token is optional.
if (!string.IsNullOrEmpty(response.RefreshToken))
{
yield return new AuthenticationToken
{
Name = OpenIdConnectConstants.Parameters.RefreshToken,
Value = response.RefreshToken
};
}
// Note: the expires_in parameter is optional.
if (response.ExpiresIn != null)
{
yield return new AuthenticationToken
{
Name = "expires_at",
Value = (DateTimeOffset.UtcNow + TimeSpan.FromSeconds(response.ExpiresIn.Value)).ToString("o", CultureInfo.InvariantCulture)
};
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment