public StravaConnectController( IOptions <SegmentChallengeConfiguration> challengeConfiguration, IOptions <StravaConfiguration> stravaConfiguration, Func <DbConnection> dbConnectionFactory, StravaApiHelper apiHelper, ILogger <StravaConnectController> logger) { this.challengeConfiguration = challengeConfiguration; this.stravaConfiguration = stravaConfiguration; this.dbConnectionFactory = dbConnectionFactory; this.apiHelper = apiHelper; this.logger = logger; }
public async Task <IActionResult> Authorize( [FromQuery] String state, [FromQuery] String code, [FromQuery] String scope, CancellationToken cancellationToken) { var expected_state = Request.Cookies["authentication_state"]; if (!String.Equals(state, expected_state)) { this.logger.LogWarning( "The state {ActualState} did not match the expected authentication state {ExpectedState}", state, expected_state ); } var codeExchangeClient = new HttpClient { BaseAddress = new Uri("https://www.strava.com") }; codeExchangeClient.DefaultRequestHeaders.Add("Accept", "application/json"); var response = await this.apiHelper.MakeThrottledApiRequest( () => codeExchangeClient.PostAsync( "/api/v3/oauth/token", new FormUrlEncodedContent(new Dictionary <string, string> { { "client_id", this.stravaConfiguration.Value.ClientId }, { "client_secret", this.stravaConfiguration.Value.ClientSecret }, { "code", code }, { "grant_type", "authorization_code" } }), cancellationToken ), cancellationToken); if (response.IsSuccessStatusCode) { var session = await response.Content.ReadAsAsync <StravaSession>(cancellationToken); await using var connection = this.dbConnectionFactory(); await connection.OpenAsync(cancellationToken); await using var dbContext = new SegmentChallengeDbContext(connection); var athleteTable = dbContext.Set <Athlete>(); // Does user exist? If not create them. var existingAthlete = await athleteTable.SingleOrDefaultAsync(a => a.Id == session.Athlete.Id, cancellationToken); EntityEntry <Athlete> newAthlete = null; if (existingAthlete == null) { newAthlete = await athleteTable.AddAsync( new Athlete { Id = session.Athlete.Id, Username = session.Athlete.Username, FirstName = session.Athlete.FirstName, LastName = session.Athlete.LastName, Gender = !String.IsNullOrEmpty(session.Athlete.Sex) ? session.Athlete.Sex[0] : (Char?)null, ProfilePicture = session.Athlete.ProfileMedium ?? session.Athlete.Profile, AccessToken = session.AccessToken, RefreshToken = session.RefreshToken, TokenExpiration = StravaApiHelper.DateTimeFromUnixTime(session.ExpiresAt) }, cancellationToken ); } else { existingAthlete.Username = session.Athlete.Username; existingAthlete.FirstName = session.Athlete.FirstName; existingAthlete.LastName = session.Athlete.LastName; if (!String.IsNullOrEmpty(session.Athlete.Sex)) { existingAthlete.Gender = session.Athlete.Sex[0]; } existingAthlete.ProfilePicture = session.Athlete.ProfileMedium ?? session.Athlete.Profile; existingAthlete.AccessToken = session.AccessToken; existingAthlete.RefreshToken = session.RefreshToken; existingAthlete.TokenExpiration = StravaApiHelper.DateTimeFromUnixTime(session.ExpiresAt); athleteTable.Update(existingAthlete); } var changes = await dbContext.SaveChangesAsync(cancellationToken); if (changes != 1) { logger.LogWarning( $"Unexpected number of rows changed {(existingAthlete == null ? "creating" : "updating")} Athlete {{AthleteId}} ({{RowsChanged}})", session.Athlete.Id, changes ); } Response.Cookies.Append( "id_token", CreateAthleteJwt( this.challengeConfiguration.Value, existingAthlete ?? newAthlete?.Entity), new CookieOptions { Expires = DateTime.UtcNow.AddDays(this.challengeConfiguration.Value.TokenExpiration) } ); return(Redirect("/")); } else { logger.LogError( "Authentication Failed with HTTP Status {StatusCode}: {Content}", response.StatusCode, await response.Content.ReadAsStringAsync() ); return(this.Problem( $"An unexpected error occurred. Please contact {this.challengeConfiguration.Value.SupportContact}")); } }