/// <summary>Asynchronously authorizes the web application to access user's protected data.</summary> /// <param name="userId">User identifier</param> /// <param name="taskCancellationToken">Cancellation token to cancel an operation</param> /// <returns> /// Auth result object which contains the user's credential or redirect URI for the authorization server /// </returns> public async Task <AuthResult> AuthorizeAsync(string userId, CancellationToken taskCancellationToken) { // Try to load a token from the data store. var token = await Flow.LoadTokenAsync(userId, taskCancellationToken).ConfigureAwait(false); // If the stored token is null or it doesn't have a refresh token and the access token is expired, we need // to retrieve a new access token. if (token == null || (token.RefreshToken == null && token.IsExpired(flow.Clock))) { // Create a authorization code request. AuthorizationCodeRequestUrl codeRequest = Flow.CreateAuthorizationCodeRequest(redirectUri); // Add a random number to the end of the state so we can indicate the original request was made by this // call. var oauthState = state; if (Flow.DataStore != null) { var rndString = new string('9', StateRandomLength); var random = new Random().Next(int.Parse(rndString)).ToString("D" + StateRandomLength); oauthState += random; await Flow.DataStore.StoreAsync(StateKey + userId, oauthState).ConfigureAwait(false); } codeRequest.State = oauthState; return(new AuthResult { RedirectUri = codeRequest.Build().ToString() }); } return(new AuthResult { Credential = new UserCredential(flow, userId, token) }); }
/// <inheritdoc/> public async Task <UserCredential> AuthorizeAsync(string userId, CancellationToken taskCancellationToken) { // Try to load a token from the data store. var token = await Flow.LoadTokenAsync(userId, taskCancellationToken).ConfigureAwait(false); // Check if a new authorization code is needed. if (ShouldRequestAuthorizationCode(token)) { // Create an authorization code request. var redirectUri = CodeReceiver.RedirectUri; AuthorizationCodeRequestUrl codeRequest = Flow.CreateAuthorizationCodeRequest(redirectUri); // Receive the code. var response = await CodeReceiver.ReceiveCodeAsync(codeRequest, taskCancellationToken) .ConfigureAwait(false); if (string.IsNullOrEmpty(response.Code)) { var errorResponse = new TokenErrorResponse(response); Logger.Info("Received an error. The response is: {0}", errorResponse); throw new TokenResponseException(errorResponse); } Logger.Debug("Received \"{0}\" code", response.Code); // Get the token based on the code. token = await Flow.ExchangeCodeForTokenAsync(userId, response.Code, redirectUri, taskCancellationToken).ConfigureAwait(false); } return(new UserCredential(flow, userId, token)); }
/// <summary>Asynchronously authorizes the web application to access user's protected data.</summary> /// <param name="userId">User identifier</param> /// <param name="taskCancellationToken">Cancellation token to cancel an operation</param> /// <returns> /// Auth result object which contains the user's credential or redirect URI for the authorization server /// </returns> public async Task <AuthResult> AuthorizeAsync(string userId, CancellationToken taskCancellationToken) { // Try to load a token from the data store. var token = await Flow.LoadTokenAsync(userId, taskCancellationToken).ConfigureAwait(false); // Check if a new authorization code is needed. if (ShouldRequestAuthorizationCode(token)) { // Create an authorization code request. AuthorizationCodeRequestUrl codeRequest = Flow.CreateAuthorizationCodeRequest(redirectUri); // Add a random number to the end of the state so we can indicate the original request was made by this // call. var oauthState = state; if (Flow.DataStore != null) { var rndString = new string('9', StateRandomLength); var random = new Random().Next(int.Parse(rndString)).ToString("D" + StateRandomLength); oauthState += random; await Flow.DataStore.StoreAsync(StateKey + userId, oauthState).ConfigureAwait(false); } codeRequest.State = oauthState; return(new AuthResult { RedirectUri = codeRequest.Build().ToString() }); } return(new AuthResult { Credential = new UserCredential(flow, userId, token) }); }
public async Task <UserCredential> AuthorizeAsync(string userId, CancellationToken taskCancellationToken) { // Try to load a token from the data store. var token = await Flow.LoadTokenAsync(userId, taskCancellationToken).ConfigureAwait(false); // If the stored token is null or it doesn't have a refresh token and the access token is expired we need // to retrieve a new authorization code. if (token == null || (token.RefreshToken == null && token.IsExpired(flow.Clock))) { // Create an authorization code request. var redirectUri = CodeReceiver.RedirectUri; AuthorizationCodeRequestUrl codeRequest = Flow.CreateAuthorizationCodeRequest(redirectUri); // Receive the code. var response = await CodeReceiver.ReceiveCodeAsync(codeRequest, taskCancellationToken) .ConfigureAwait(false); if (string.IsNullOrEmpty(response.Code)) { var errorResponse = new TokenErrorResponse(response); Logger.Info("Received an error. The response is: {0}", errorResponse); throw new TokenResponseException(errorResponse); } Logger.Debug("Received \"{0}\" code", response.Code); // Get the token based on the code. token = await Flow.ExchangeCodeForTokenAsync(userId, response.Code, CodeReceiver.RedirectUri, taskCancellationToken).ConfigureAwait(false); } return(new UserCredential(flow, userId, token)); }
public string RedirectToGoogleAuthorizationPage() { var codeRequest = Flow.CreateAuthorizationCodeRequest(RedirectUri); // TODO: Use a more cryptographically safe nonce generator var oauthState = $"{State}{new Random().Next(int.Parse(new string('9', 8))).ToString("D" + 8)}"; // TODO: What should happen if an OAuth state is already in the database? // TODO: For now, upsert _context.GoogleOauthStates.AddOrUpdate( new GoogleOauthState { UserId = UserId, Value = oauthState }); // TODO: Make sure the code request URL can be built before saving the state in the database _context.SaveChanges(); codeRequest.State = oauthState; // HACK: Needed to add "&prompt=select_account" to force Google account selection screen return($"{codeRequest.Build()}&prompt=select_account+consent"); }