public static IOAuthOpenIdToken NewOpenIdToken(this IOAuthAccessToken accessToken, OpenIdToken idToken, string json) { var session = EntityHelper.GetSession(accessToken); var tknEnt = accessToken.OpenIdToken = session.NewEntity <IOAuthOpenIdToken>(); tknEnt.Issuer = idToken.Issuer; tknEnt.AuthContextRef = idToken.ContextRef; tknEnt.Subject = idToken.Subject; tknEnt.Audience = idToken.Audience; tknEnt.IssuedAt = OpenIdConnectUtil.FromUnixTime(idToken.IssuedAt); tknEnt.ExpiresAt = OpenIdConnectUtil.FromUnixTime(idToken.ExpiresAt); if (idToken.AuthTime > 0) { tknEnt.AuthTime = OpenIdConnectUtil.FromUnixTime(idToken.AuthTime); } tknEnt.FullJson = json; return(tknEnt); }
public async Task <Guid> RetrieveAccessTokenAsync(OperationContext context, Guid flowId) { var session = context.OpenSystemSession(); var flow = session.GetEntity <IOAuthClientFlow>(flowId); Util.Check(flow != null, "OAuth client flow not found, ID: {0}", flowId); ThrowIfExpired(flow); string err = null; switch (flow.Status) { case OAuthFlowStatus.Started: err = "Access not authorized yet."; break; case OAuthFlowStatus.TokenRetrieved: err = "Authorization code already used to retrieve token."; break; case OAuthFlowStatus.Error: err = "Authorization failed or denied - " + flow.Error; break; } Util.Check(err == null, "Cannot retrieve token: {0}.", err); Util.CheckNotEmpty(flow.AuthorizationCode, "Authorization code not retrieved, cannot retrieve access token."); var apiClient = new WebApiClient(context, flow.Account.Server.TokenRequestUrl, ClientOptions.Default, badRequestContentType: typeof(string)); var clientSecret = flow.Account.ClientSecret; var server = flow.Account.Server; var serverOptions = server.Options; // Some servers expect clientId/secret in Authorization header string query; if (serverOptions.IsSet(OAuthServerOptions.ClientInfoInAuthHeader)) { AddClientInfoHeader(apiClient, flow.Account.ClientIdentifier, clientSecret); query = StringHelper.FormatUri(AccessTokenUrlQueryTemplate, flow.AuthorizationCode, flow.RedirectUrl); } else { //others - clientId/secret mixed with other parameters query = StringHelper.FormatUri(AccessTokenUrlQueryTemplateWithClientInfo, flow.AuthorizationCode, flow.RedirectUrl, flow.Account.ClientIdentifier, clientSecret); } query = StringHelper.FormatUri(AccessTokenUrlQueryTemplateWithClientInfo, flow.AuthorizationCode, flow.RedirectUrl, flow.Account.ClientIdentifier, clientSecret); //Make a call; standard is POST, but some servers use GET (LinkedIn) AccessTokenResponse tokenResp; if (serverOptions.IsSet(OAuthServerOptions.TokenUseGet)) { //GET, no body tokenResp = await apiClient.GetAsync <AccessTokenResponse>("?" + query); } else { var formContent = CreateFormUrlEncodedContent(query); tokenResp = await apiClient.PostAsync <HttpContent, AccessTokenResponse>(formContent, string.Empty); } flow.Status = OAuthFlowStatus.TokenRetrieved; //LinkedIn returns milliseconds here - it's a bug, reported. So here is workaround var expIn = tokenResp.ExpiresIn; if (expIn > 1e+9) //if more than one billion, it is milliseconds { expIn = expIn / 1000; } var expires = this.App.TimeService.UtcNow.AddSeconds(expIn); OAuthTokenType tokenType; var ok = Enum.TryParse <OAuthTokenType>(tokenResp.TokenType, true, out tokenType); //should be Bearer // Create AccessToken entity var accessToken = flow.Account.NewOAuthAccessToken(flow.UserId, tokenResp.AccessToken, tokenType, tokenResp.RefreshToken, tokenResp.IdToken, flow.Scopes, App.TimeService.UtcNow, expires, Settings.EncryptionChannel); // Unpack OpenId id_token - it is JWT token if (serverOptions.IsSet(OAuthServerOptions.OpenIdConnect) && !string.IsNullOrWhiteSpace(tokenResp.IdToken)) { var payload = OpenIdConnectUtil.GetJwtPayload(tokenResp.IdToken); var idTkn = Settings.JsonDeserializer.Deserialize <OpenIdToken>(payload); accessToken.NewOpenIdToken(idTkn, payload); } session.SaveChanges(); Authorized?.Invoke(this, new OAuthClient.OAuthEventArgs(context, flow.Id)); return(accessToken.Id); }