diff --git a/src/OidcClient/OidcClient.cs b/src/OidcClient/OidcClient.cs index c11f99c..f7c53cd 100644 --- a/src/OidcClient/OidcClient.cs +++ b/src/OidcClient/OidcClient.cs @@ -5,7 +5,9 @@ using IdentityModel.Client; using IdentityModel.OidcClient.Infrastructure; using IdentityModel.OidcClient.Results; + using Microsoft.Extensions.Logging; + using System; using System.Collections.Generic; using System.Linq; @@ -20,6 +22,7 @@ namespace IdentityModel.OidcClient /// public class OidcClient { + private const long TOKEN_START_TIME = 621355968000000000;// 1970-01-01T00:00:00Z UTCTicks private readonly ILogger _logger; private readonly AuthorizeClient _authorizeClient; @@ -76,7 +79,7 @@ public virtual async Task LoginAsync(LoginRequest request = null, C Timeout = request.BrowserTimeout, ExtraParameters = request.FrontChannelExtraParameters }, cancellationToken); - + if (authorizeResult.IsError) { return new LoginResult(authorizeResult.Error, authorizeResult.ErrorDescription); @@ -229,6 +232,12 @@ public virtual async Task ProcessResponseAsync(string data, Authori var user = ProcessClaims(result.User, userInfoClaims); + long seconds = 0; + var authTimeValue = result.TokenResponse.TryGet(JwtClaimTypes.AuthenticationTime); + DateTimeOffset? authTime = null; + if (authTimeValue.IsPresent() && long.TryParse(authTimeValue, out seconds)) + authTime = new DateTimeOffset(TOKEN_START_TIME, TimeSpan.Zero).AddSeconds(seconds); + var loginResult = new LoginResult { User = user, @@ -236,7 +245,7 @@ public virtual async Task ProcessResponseAsync(string data, Authori RefreshToken = result.TokenResponse.RefreshToken, AccessTokenExpiration = DateTimeOffset.Now.AddSeconds(result.TokenResponse.ExpiresIn), IdentityToken = result.TokenResponse.IdentityToken, - AuthenticationTime = DateTimeOffset.Now, + AuthenticationTime = authTime, TokenResponse = result.TokenResponse // In some cases there is additional custom response data that clients need access to }; @@ -307,7 +316,7 @@ public virtual async Task RefreshTokenAsync(string refreshTo await EnsureConfigurationAsync(cancellationToken); var client = Options.CreateClient(); - + var response = await client.RequestRefreshTokenAsync(new RefreshTokenRequest { Address = Options.ProviderInformation.TokenEndpoint, @@ -341,8 +350,8 @@ public virtual async Task RefreshTokenAsync(string refreshTo IdentityToken = response.IdentityToken, AccessToken = response.AccessToken, RefreshToken = response.RefreshToken, - ExpiresIn = (int)response.ExpiresIn, - AccessTokenExpiration = DateTime.Now.AddSeconds(response.ExpiresIn) + ExpiresIn = response.ExpiresIn, + AccessTokenExpiration = DateTimeOffset.Now.AddSeconds(response.ExpiresIn) }; } @@ -377,11 +386,11 @@ internal async Task EnsureProviderInformationAsync(CancellationToken cancellatio Address = Options.Authority, Policy = Options.Policy.Discovery }, cancellationToken).ConfigureAwait(false); - + if (disco.IsError) { _logger.LogError("Error loading discovery document: {errorType} - {error}", disco.ErrorType.ToString(), disco.Error); - + if (disco.ErrorType == ResponseErrorType.Exception) { throw new InvalidOperationException("Error loading discovery document: " + disco.Error, disco.Exception); diff --git a/src/OidcClient/Results/LoginResult.cs b/src/OidcClient/Results/LoginResult.cs index 3892b7e..e809f7f 100644 --- a/src/OidcClient/Results/LoginResult.cs +++ b/src/OidcClient/Results/LoginResult.cs @@ -88,7 +88,7 @@ public LoginResult(string error, string errorDescription) /// /// The authentication time. /// - public virtual DateTimeOffset AuthenticationTime { get; internal set; } + public virtual DateTimeOffset? AuthenticationTime { get; internal set; } /// /// Gets or sets the refresh token handler. diff --git a/src/OidcClient/Results/RefreshTokenResult.cs b/src/OidcClient/Results/RefreshTokenResult.cs index c81a8b1..47cd6d4 100644 --- a/src/OidcClient/Results/RefreshTokenResult.cs +++ b/src/OidcClient/Results/RefreshTokenResult.cs @@ -50,7 +50,7 @@ public class RefreshTokenResult : Result /// /// The access token expiration. /// - public virtual DateTime AccessTokenExpiration { get; internal set; } + public virtual DateTimeOffset AccessTokenExpiration { get; internal set; } } } \ No newline at end of file