Skip to content

Instantly share code, notes, and snippets.

@rudiv
Created April 12, 2018 16:45
Show Gist options
  • Save rudiv/26a341bf09439f3420b25311419226b4 to your computer and use it in GitHub Desktop.
Save rudiv/26a341bf09439f3420b25311419226b4 to your computer and use it in GitHub Desktop.
// Copyright (c) Cedita Ltd. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the solution root for license information.
using Cedita.One.Microservice.Platform.Abstractions.Providers;
using IdentityModel.Client;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Threading.Tasks;
namespace Cedita.One.Microservice.Platform.Core.Providers
{
/// <summary>
/// Cookie-Based Access Token Provider
/// </summary>
public class CookieAccessTokenProvider : IAccessTokenProvider
{
private const string ExpiresAtToken = "expires_at";
private const string TokenRefreshEndpoint = "/connect/token";
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly MicroservicePlatformOptions _options;
protected string IdToken;
protected string AccessToken;
protected string RefreshToken;
protected string ExpiresAt;
protected DateTimeOffset ExpiresAtDate;
public CookieAccessTokenProvider(IHttpContextAccessor httpContextAccessor, IOptions<MicroservicePlatformOptions> options)
{
_httpContextAccessor = httpContextAccessor;
_options = options.Value;
}
public async Task<string> GetAccessTokenAsync()
{
await GetTokensFromContextAsync();
// If we're close to expiry (5 minutes in future), refresh the token
if (DateTime.Now >= ExpiresAtDate.AddMinutes(-5))
{
await RefreshTokenAsync();
}
return AccessToken;
}
protected async Task GetTokensFromContextAsync()
{
// Already called in this scope
if (AccessToken != null) return;
IdToken = await _httpContextAccessor.HttpContext.GetTokenAsync(OpenIdConnectParameterNames.IdToken);
RefreshToken = await _httpContextAccessor.HttpContext.GetTokenAsync(OpenIdConnectParameterNames.RefreshToken);
AccessToken = await _httpContextAccessor.HttpContext.GetTokenAsync(OpenIdConnectParameterNames.AccessToken);
ExpiresAt = await _httpContextAccessor.HttpContext.GetTokenAsync(ExpiresAtToken);
ExpiresAtDate = DateTime.Parse(ExpiresAt);
}
protected async Task SetTokensInContextAsync()
{
var tokens = new List<AuthenticationToken>
{
new AuthenticationToken { Name = OpenIdConnectParameterNames.IdToken, Value = IdToken },
new AuthenticationToken { Name = OpenIdConnectParameterNames.RefreshToken, Value = RefreshToken },
new AuthenticationToken { Name = OpenIdConnectParameterNames.AccessToken, Value = AccessToken },
new AuthenticationToken { Name = ExpiresAtToken, Value = ExpiresAt },
};
var currentAuthentication = await _httpContextAccessor.HttpContext.AuthenticateAsync(CookieAuthenticationDefaults.AuthenticationScheme);
currentAuthentication.Properties.StoreTokens(tokens);
await _httpContextAccessor.HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, currentAuthentication.Principal, currentAuthentication.Properties);
}
protected async Task RefreshTokenAsync()
{
var tokenClient = new TokenClient(_options.AuthUrl + TokenRefreshEndpoint, _options.AuthClientId, _options.AuthClientSecret);
var response = await tokenClient.RequestRefreshTokenAsync(RefreshToken);
if (!response.IsError)
{
AccessToken = response.AccessToken;
RefreshToken = response.RefreshToken;
ExpiresAtDate = DateTime.UtcNow + TimeSpan.FromSeconds(response.ExpiresIn);
ExpiresAt = ExpiresAtDate.ToString("o", CultureInfo.InvariantCulture);
await SetTokensInContextAsync();
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment