/// <summary> /// Completes the Sign in process based on the authentication state and the received query string. /// </summary> /// <param name="authenticationState"></param> /// <param name="queryString"></param> protected virtual async Task CompleteSignIn(TRemoteAuthenticationState authenticationState, string queryString) { if (authenticationState is null) { throw new ArgumentNullException(nameof(authenticationState)); } if (string.IsNullOrEmpty(queryString)) { throw new ArgumentException($"'{nameof(queryString)}' cannot be null or empty", nameof(queryString)); } var internalState = new AuthorizeState() { CodeVerifier = authenticationState.CodeVerifier, Nonce = authenticationState.Nonce, RedirectUri = authenticationState.RedirectUrl, StartUrl = authenticationState.StartUrl, State = authenticationState.State, }; var loginResult = await Client.ProcessResponseAsync(queryString, internalState); if (loginResult.IdentityToken != null) { await TokenCache.Add(IdTokenKey, new System.IdentityModel.Tokens.Jwt.JwtSecurityToken(loginResult.IdentityToken)); } if (loginResult.RefreshToken != null) { await _protectedStorage.SetAsync(RefreshTokenKey, loginResult.RefreshToken); } if (loginResult.AccessToken != null) { await TokenCache.Add(AccessTokenKey, new System.IdentityModel.Tokens.Jwt.JwtSecurityToken(loginResult.AccessToken)); } }
/// <inheritdoc /> public virtual async Task <AccessTokenResult> RequestAccessToken() { await EnsureAuthService(); if (await TokenCache.TryGet(AccessTokenKey, out var accessToken)) { return(new AccessTokenResult(this, AccessTokenResultStatus.Success, new AccessToken() { Expires = accessToken.ValidTo.ToLocalTime(), GrantedScopes = accessToken.Claims.Where(x => x.Type.Equals(Options.UserOptions.ScopeClaim, StringComparison.Ordinal)).Select(x => x.Value).ToList(), Value = accessToken.RawData, })); } Task <Task <AccessTokenResult> > requestAccessTokenTask = null; // make sure we execute this method only once. We await the task otherwise. // With multiple components requesting the authentication state during reload, this happens. Multiple requests would be sent to the authentication // service with possible loss of the last refresh/or auth token. if ((requestAccessTokenTask = Interlocked.CompareExchange(ref _requestAccessTokenTask, new Task <Task <AccessTokenResult> >(InternalRequestAccessToken), null)) == null) { requestAccessTokenTask = _requestAccessTokenTask; requestAccessTokenTask.Start(); } return(await requestAccessTokenTask.Unwrap()); async Task <AccessTokenResult> InternalRequestAccessToken() { try { string refreshToken = null; if (!string.IsNullOrEmpty(refreshToken = await _protectedStorage.GetAsync <string>(RefreshTokenKey))) { var refreshTokenResult = await Client.RefreshTokenAsync(refreshToken); if (refreshTokenResult.IdentityToken != null) { await TokenCache.Add(IdTokenKey, new System.IdentityModel.Tokens.Jwt.JwtSecurityToken(refreshTokenResult.IdentityToken)); } if (refreshTokenResult.RefreshToken != null) { await _protectedStorage.SetAsync(RefreshTokenKey, refreshTokenResult.RefreshToken); } if (refreshTokenResult.AccessToken != null) { accessToken = new System.IdentityModel.Tokens.Jwt.JwtSecurityToken(refreshTokenResult.AccessToken); await TokenCache.Add(AccessTokenKey, accessToken); var grantedScopes = accessToken.Claims.Where(x => x.Type.Equals(Options.UserOptions.ScopeClaim, StringComparison.Ordinal)).Select(x => x.Value).ToList(); return(new AccessTokenResult(this, AccessTokenResultStatus.Success, new AccessToken() { Expires = accessToken.ValidTo.ToLocalTime(), GrantedScopes = grantedScopes, Value = accessToken.RawData, })); } } return(new AccessTokenResult(this, AccessTokenResultStatus.RequiresRedirect, null)); } finally { _requestAccessTokenTask = null; } } }