Enhance refresh token functionality and response handling
- Updated MakeRefreshToken and generateRefreshToken methods to accept an optional expiresIn parameter for customizable token expiration. - Modified storeRefreshTokenWithScope to handle dynamic expiration times based on the provided parameter. - Enhanced the authback function to send cookies with access and refresh tokens, including their respective expiration times. - Updated LoginResponse structure to include RefreshTokenExpiresIn for better client-side management of token lifetimes. - Adjusted client configuration to set default refresh token expiration duration.
This commit is contained in:
parent
c1b28f3b69
commit
5657c75201
5 changed files with 45 additions and 25 deletions
|
|
@ -253,8 +253,8 @@ func (s *Service) MakeAccessToken(clientID, scope, subject string, expiresIn int
|
|||
}
|
||||
|
||||
// MakeRefreshToken generates a new refresh token with specific parameters and stores it
|
||||
func (s *Service) MakeRefreshToken(clientID, scope, subject string) (string, error) {
|
||||
return s.generateRefreshToken(clientID, scope, subject)
|
||||
func (s *Service) MakeRefreshToken(clientID, scope, subject string, expiresIn ...int) (string, error) {
|
||||
return s.generateRefreshToken(clientID, scope, subject, expiresIn...)
|
||||
}
|
||||
|
||||
// Subject converts a userID to a subject using NanoID fingerprint
|
||||
|
|
@ -415,14 +415,14 @@ func (s *Service) revokeAccessToken(accessToken string) error {
|
|||
}
|
||||
|
||||
// generateRefreshToken generates and stores a new refresh token with scope and subject
|
||||
func (s *Service) generateRefreshToken(clientID, scope, subject string) (string, error) {
|
||||
func (s *Service) generateRefreshToken(clientID, scope, subject string, expiresIn ...int) (string, error) {
|
||||
refreshToken, err := s.generateToken("rfk", clientID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Store refresh token with metadata
|
||||
err = s.storeRefreshTokenWithScope(refreshToken, clientID, scope, subject)
|
||||
err = s.storeRefreshTokenWithScope(refreshToken, clientID, scope, subject, expiresIn...)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
|
@ -529,7 +529,7 @@ func (s *Service) storeRefreshToken(refreshToken, clientID string) error {
|
|||
}
|
||||
|
||||
// storeRefreshTokenWithScope stores refresh token with metadata including scope and subject
|
||||
func (s *Service) storeRefreshTokenWithScope(refreshToken, clientID, scope, subject string) error {
|
||||
func (s *Service) storeRefreshTokenWithScope(refreshToken, clientID, scope, subject string, expiresIn ...int) error {
|
||||
tokenData := map[string]interface{}{
|
||||
"client_id": clientID,
|
||||
"scope": scope,
|
||||
|
|
@ -538,7 +538,12 @@ func (s *Service) storeRefreshTokenWithScope(refreshToken, clientID, scope, subj
|
|||
"issued_at": time.Now().Unix(),
|
||||
}
|
||||
|
||||
return s.store.Set(s.refreshTokenKey(refreshToken), tokenData, s.config.Token.RefreshTokenLifetime)
|
||||
expires := s.config.Token.RefreshTokenLifetime
|
||||
if len(expiresIn) > 0 && expiresIn[0] > 0 {
|
||||
expires = time.Duration(expiresIn[0]) * time.Second
|
||||
}
|
||||
|
||||
return s.store.Set(s.refreshTokenKey(refreshToken), tokenData, expires)
|
||||
}
|
||||
|
||||
// getRefreshTokenData retrieves refresh token data
|
||||
|
|
|
|||
|
|
@ -214,7 +214,18 @@ func authback(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
response.RespondWithSuccess(c, response.StatusOK, loginResponse)
|
||||
// Authorize Cookie
|
||||
accessToken := fmt.Sprintf("%s %s", loginResponse.TokenType, loginResponse.AccessToken)
|
||||
refreshToken := fmt.Sprintf("%s %s", loginResponse.TokenType, loginResponse.RefreshToken)
|
||||
|
||||
// Send Cookie
|
||||
expires := time.Now().Add(time.Duration(loginResponse.ExpiresIn) * time.Second)
|
||||
refreshExpires := time.Now().Add(time.Duration(loginResponse.RefreshTokenExpiresIn) * time.Second)
|
||||
response.SendAccessTokenCookieWithExpiry(c, accessToken, expires)
|
||||
response.SendRefreshTokenCookieWithExpiry(c, refreshToken, refreshExpires)
|
||||
|
||||
// Send IDToken to the client
|
||||
response.RespondWithSuccess(c, response.StatusOK, map[string]interface{}{"id_token": loginResponse.IDToken})
|
||||
}
|
||||
|
||||
// getOAuthAuthorizationURL generates OAuth authorization URL for a provider
|
||||
|
|
|
|||
|
|
@ -119,17 +119,18 @@ func LoginByUserID(userid string, ip string) (*LoginResponse, error) {
|
|||
}
|
||||
|
||||
// Refresh Token
|
||||
refreshToken, err := oauth.OAuth.MakeRefreshToken(yaoClientConfig.ClientID, strings.Join(scopes, " "), subject)
|
||||
refreshToken, err := oauth.OAuth.MakeRefreshToken(yaoClientConfig.ClientID, strings.Join(scopes, " "), subject, yaoClientConfig.RefreshTokenExpiresIn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &LoginResponse{
|
||||
AccessToken: accessToken,
|
||||
IDToken: oidcToken,
|
||||
RefreshToken: refreshToken,
|
||||
ExpiresIn: yaoClientConfig.ExpiresIn,
|
||||
TokenType: "Bearer",
|
||||
Scope: strings.Join(scopes, " "),
|
||||
AccessToken: accessToken,
|
||||
IDToken: oidcToken,
|
||||
RefreshToken: refreshToken,
|
||||
ExpiresIn: yaoClientConfig.ExpiresIn,
|
||||
RefreshTokenExpiresIn: yaoClientConfig.RefreshTokenExpiresIn,
|
||||
TokenType: "Bearer",
|
||||
Scope: strings.Join(scopes, " "),
|
||||
}, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -156,7 +156,8 @@ func registerClient(clientID string) (*YaoClientConfig, error) {
|
|||
var clientConfig *YaoClientConfig = &YaoClientConfig{}
|
||||
clientConfig.ClientID = response.ClientID
|
||||
clientConfig.ClientSecret = response.ClientSecret
|
||||
clientConfig.ExpiresIn = 3600 * 24 // 24 hours
|
||||
clientConfig.ExpiresIn = 3600 * 24 // 24 hours
|
||||
clientConfig.RefreshTokenExpiresIn = 3600 * 24 * 30 // 30 days
|
||||
clientConfig.Scopes = []string{"openid", "profile", "email"}
|
||||
return clientConfig, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,10 +66,11 @@ type RegisterConfig struct {
|
|||
|
||||
// YaoClientConfig represents the Yao OpenAPI Client config
|
||||
type YaoClientConfig struct {
|
||||
ClientID string `json:"client_id,omitempty"`
|
||||
ClientSecret string `json:"client_secret,omitempty"`
|
||||
Scopes []string `json:"scopes,omitempty"` // Default scopes if not set in the provider config
|
||||
ExpiresIn int `json:"expires_in,omitempty"` // Default expires in for the access token (optional) in seconds
|
||||
ClientID string `json:"client_id,omitempty"`
|
||||
ClientSecret string `json:"client_secret,omitempty"`
|
||||
Scopes []string `json:"scopes,omitempty"` // Default scopes if not set in the provider config
|
||||
ExpiresIn int `json:"expires_in,omitempty"` // Default expires in for the access token (optional) in seconds
|
||||
RefreshTokenExpiresIn int `json:"refresh_token_expires_in,omitempty"` // Default expires in for the refresh token (optional) in seconds
|
||||
}
|
||||
|
||||
// Provider represents a third party login provider
|
||||
|
|
@ -161,12 +162,13 @@ type OIDCAddress = oauthtypes.OIDCAddress
|
|||
|
||||
// LoginResponse represents the response for login
|
||||
type LoginResponse struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
IDToken string `json:"id_token,omitempty"`
|
||||
RefreshToken string `json:"refresh_token,omitempty"`
|
||||
ExpiresIn int `json:"expires_in,omitempty"`
|
||||
TokenType string `json:"token_type,omitempty"`
|
||||
Scope string `json:"scope,omitempty"`
|
||||
AccessToken string `json:"access_token"`
|
||||
IDToken string `json:"id_token,omitempty"`
|
||||
RefreshToken string `json:"refresh_token,omitempty"`
|
||||
ExpiresIn int `json:"expires_in,omitempty"`
|
||||
RefreshTokenExpiresIn int `json:"refresh_token_expires_in,omitempty"`
|
||||
TokenType string `json:"token_type,omitempty"`
|
||||
Scope string `json:"scope,omitempty"`
|
||||
}
|
||||
|
||||
// Built-in preset mapping types
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue