diff --git a/internal/api/external.go b/internal/api/external.go index 0f88a64b8..ec9cb7132 100644 --- a/internal/api/external.go +++ b/internal/api/external.go @@ -165,6 +165,7 @@ func (a *API) internalExternalProviderCallback(w http.ResponseWriter, r *http.Re grantParams.FillGrantParams(r) providerType, emailOptional := getExternalProviderType(ctx) + grantParams.Provider = providerType data, err := a.handleOAuthCallback(r) if err != nil { return err @@ -367,6 +368,8 @@ func (a *API) createAccountFromExternalIdentity(tx *storage.Connection, r *http. user = decision.User identity = decision.Identities[0] + now := time.Now() + identity.LastSignInAt = &now identity.IdentityData = identityData if terr = tx.UpdateOnly(identity, "identity_data", "last_sign_in_at"); terr != nil { return 0, nil, terr diff --git a/internal/api/token.go b/internal/api/token.go index 9ef0ae727..9925da799 100644 --- a/internal/api/token.go +++ b/internal/api/token.go @@ -91,12 +91,14 @@ func (a *API) ResourceOwnerPasswordGrant(ctx context.Context, w http.ResponseWri if params.Email != "" { provider = "email" + grantParams.Provider = "email" if !config.External.Email.Enabled { return apierrors.NewUnprocessableEntityError(apierrors.ErrorCodeEmailProviderDisabled, "Email logins are disabled") } user, err = models.FindUserByEmailAndAudience(db, params.Email, aud) } else if params.Phone != "" { provider = "phone" + grantParams.Provider = "phone" if !config.External.Phone.Enabled { return apierrors.NewUnprocessableEntityError(apierrors.ErrorCodePhoneProviderDisabled, "Phone logins are disabled") } @@ -238,6 +240,7 @@ func (a *API) PKCE(ctx context.Context, w http.ResponseWriter, r *http.Request) } else if err != nil { return err } + grantParams.Provider = flowState.ProviderType if flowState.IsExpired(a.config.External.FlowStateExpiryDuration) { return apierrors.NewUnprocessableEntityError(apierrors.ErrorCodeFlowStateExpired, "invalid flow state, flow state has expired") } diff --git a/internal/api/verify.go b/internal/api/verify.go index 212d7388e..6bec9d3a3 100644 --- a/internal/api/verify.go +++ b/internal/api/verify.go @@ -131,6 +131,7 @@ func (a *API) verifyGet(w http.ResponseWriter, r *http.Request, params *VerifyPa ) grantParams.FillGrantParams(r) + grantParams.Provider = "email" flowType := models.ImplicitFlow var authenticationMethod models.AuthenticationMethod @@ -238,6 +239,11 @@ func (a *API) verifyPost(w http.ResponseWriter, r *http.Request, params *VerifyP var isSingleConfirmationResponse = false grantParams.FillGrantParams(r) + if params.Type == smsVerification || params.Type == phoneChangeVerification { + grantParams.Provider = "phone" + } else { + grantParams.Provider = "email" + } err := db.Transaction(func(tx *storage.Connection) error { var terr error diff --git a/internal/models/refresh_token.go b/internal/models/refresh_token.go index 63e60fd14..0d3130583 100644 --- a/internal/models/refresh_token.go +++ b/internal/models/refresh_token.go @@ -51,6 +51,7 @@ type GrantParams struct { UserAgent string IP string + Provider string } func (g *GrantParams) FillGrantParams(r *http.Request) { diff --git a/internal/tokens/service.go b/internal/tokens/service.go index 3a479d04c..2f42842e1 100644 --- a/internal/tokens/service.go +++ b/internal/tokens/service.go @@ -873,6 +873,21 @@ func (s *Service) IssueRefreshToken(r *http.Request, responseHeaders http.Header err := conn.Transaction(func(tx *storage.Connection) error { var terr error + if grantParams.Provider != "" { + if terr = tx.Load(user, "Identities"); terr != nil { + return apierrors.NewInternalServerError("Error loading user identities").WithInternalError(terr) + } + for i := range user.Identities { + if user.Identities[i].Provider == grantParams.Provider { + user.Identities[i].LastSignInAt = &now + if terr = tx.UpdateOnly(&user.Identities[i], "last_sign_in_at"); terr != nil { + return apierrors.NewInternalServerError("Error updating identity last_sign_in_at").WithInternalError(terr) + } + break + } + } + } + if config.Security.RefreshTokenAlgorithmVersion == 2 { session, terr := models.NewSession(user.ID, grantParams.FactorID) if terr != nil {