-
-
Save rudiv/26a341bf09439f3420b25311419226b4 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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