/// <summary> /// Converts a set of JWTs into a Keycloak identity /// If the access token of the identity is about to expire the identity gets refreshed /// If a <see cref="SecurityTokenExpiredException"/> is thrown when converting the set of jwts, the identity /// gets refreshed. /// </summary> /// <param name="parameters"></param> /// <param name="accessToken"></param> /// <param name="refreshToken"></param> /// <param name="idToken"></param> /// <returns>The identity is returned</returns> public static async Task <KeycloakIdentity> ConvertFromJwtAsync(IKeycloakParameters parameters, string accessToken, string refreshToken = null, string idToken = null) { if (parameters == null) { throw new ArgumentNullException(nameof(parameters)); } if (accessToken == null) { throw new ArgumentNullException(nameof(accessToken)); } var kcIdentity = new KeycloakIdentity(parameters); try { await kcIdentity.CopyFromJwt(accessToken, refreshToken, idToken); //check if identity is about to expire in 30 secs (default). If yes refresh identity! DateTime?accessValidTo = DateTimeExtension.ParseClaimsDateToFormat( kcIdentity.Claims?.FirstOrDefault(c => c.Type == Constants.ClaimTypes.AccessTokenExpiration)? .Value); DateTime?refreshValidTo = DateTimeExtension.ParseClaimsDateToFormat( kcIdentity.Claims?.FirstOrDefault(c => c.Type == Constants.ClaimTypes.RefreshTokenExpiration)? .Value); var utcNow = DateTime.UtcNow; //_logger.Debug($"access {accessValidToX?.ToUniversalTime()} " + // $"utcnow {utcNow} refresh {refreshValidToX?.ToUniversalTime()}."); if (utcNow >= accessValidTo?.Subtract(parameters.RefreshBeforeTokenExpiration).ToUniversalTime() && utcNow <= refreshValidTo?.Subtract(parameters.RefreshBeforeTokenExpiration).ToUniversalTime()) { _logger.Debug( $"{kcIdentity.Name} access token will expire in less then {parameters.RefreshBeforeTokenExpiration} seconds. Refresh identity."); await kcIdentity.RefreshIdentity(refreshToken); } } catch (SecurityTokenExpiredException) { _logger.Debug($"SecurityTokenExpiredException was thrown.Refreshing identity with refresh token"); // Load new identity from token endpoint via refresh token (if possible) await kcIdentity.RefreshIdentity(refreshToken); } catch (ArgumentOutOfRangeException) { _logger.Debug($"ArgumentOutOfRangeException was thrown when calculating acces token expiration timeframe. No refreshing of identity. User is out of luck."); } return(kcIdentity); }