Initial commit: Open sourcing all of the Maple Open Technologies code.
This commit is contained in:
commit
755d54a99d
2010 changed files with 448675 additions and 0 deletions
123
cloud/maplepress-backend/internal/service/gateway/refresh.go
Normal file
123
cloud/maplepress-backend/internal/service/gateway/refresh.go
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
package gateway
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/internal/service"
|
||||
"codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/pkg/security/jwt"
|
||||
)
|
||||
|
||||
// RefreshTokenService handles token refresh operations
|
||||
type RefreshTokenService interface {
|
||||
RefreshToken(ctx context.Context, input *RefreshTokenInput) (*RefreshTokenResponse, error)
|
||||
}
|
||||
|
||||
// RefreshTokenInput represents the input for token refresh
|
||||
type RefreshTokenInput struct {
|
||||
RefreshToken string
|
||||
}
|
||||
|
||||
// RefreshTokenResponse represents the response after successful token refresh
|
||||
type RefreshTokenResponse struct {
|
||||
// User details
|
||||
UserID string `json:"user_id"`
|
||||
UserEmail string `json:"user_email"`
|
||||
UserName string `json:"user_name"`
|
||||
UserRole string `json:"user_role"`
|
||||
|
||||
// Tenant details
|
||||
TenantID string `json:"tenant_id"`
|
||||
|
||||
// Session and new tokens
|
||||
SessionID string `json:"session_id"`
|
||||
AccessToken string `json:"access_token"`
|
||||
AccessExpiry time.Time `json:"access_expiry"`
|
||||
RefreshToken string `json:"refresh_token"`
|
||||
RefreshExpiry time.Time `json:"refresh_expiry"`
|
||||
|
||||
RefreshedAt time.Time `json:"refreshed_at"`
|
||||
}
|
||||
|
||||
type refreshTokenService struct {
|
||||
sessionService service.SessionService
|
||||
jwtProvider jwt.Provider
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
// NewRefreshTokenService creates a new refresh token service
|
||||
func NewRefreshTokenService(
|
||||
sessionService service.SessionService,
|
||||
jwtProvider jwt.Provider,
|
||||
logger *zap.Logger,
|
||||
) RefreshTokenService {
|
||||
return &refreshTokenService{
|
||||
sessionService: sessionService,
|
||||
jwtProvider: jwtProvider,
|
||||
logger: logger.Named("refresh-token-service"),
|
||||
}
|
||||
}
|
||||
|
||||
// RefreshToken validates the refresh token and generates new access/refresh tokens
|
||||
// CWE-613: Validates session still exists before issuing new tokens
|
||||
func (s *refreshTokenService) RefreshToken(ctx context.Context, input *RefreshTokenInput) (*RefreshTokenResponse, error) {
|
||||
s.logger.Info("processing token refresh request")
|
||||
|
||||
// Validate the refresh token and extract session ID
|
||||
sessionID, err := s.jwtProvider.ValidateToken(input.RefreshToken)
|
||||
if err != nil {
|
||||
s.logger.Warn("invalid refresh token", zap.Error(err))
|
||||
return nil, fmt.Errorf("invalid or expired refresh token")
|
||||
}
|
||||
|
||||
s.logger.Debug("refresh token validated", zap.String("session_id", sessionID))
|
||||
|
||||
// Retrieve the session to ensure it still exists
|
||||
// CWE-613: This prevents using a refresh token after logout/session deletion
|
||||
session, err := s.sessionService.GetSession(ctx, sessionID)
|
||||
if err != nil {
|
||||
s.logger.Warn("session not found or expired",
|
||||
zap.String("session_id", sessionID),
|
||||
zap.Error(err))
|
||||
return nil, fmt.Errorf("session not found or expired")
|
||||
}
|
||||
|
||||
s.logger.Info("session retrieved for token refresh",
|
||||
zap.String("session_id", sessionID),
|
||||
zap.String("user_id", session.UserUUID.String()),
|
||||
zap.String("tenant_id", session.TenantID.String()))
|
||||
|
||||
// Generate new JWT access and refresh tokens
|
||||
// Both tokens are regenerated to maintain rotation best practices
|
||||
accessToken, accessExpiry, refreshToken, refreshExpiry, err := s.jwtProvider.GenerateTokenPair(
|
||||
session.ID,
|
||||
AccessTokenDuration,
|
||||
RefreshTokenDuration,
|
||||
)
|
||||
if err != nil {
|
||||
s.logger.Error("failed to generate new token pair", zap.Error(err))
|
||||
return nil, fmt.Errorf("failed to generate new tokens")
|
||||
}
|
||||
|
||||
s.logger.Info("token refresh completed successfully",
|
||||
zap.String("user_id", session.UserUUID.String()),
|
||||
zap.String("tenant_id", session.TenantID.String()),
|
||||
zap.String("session_id", session.ID))
|
||||
|
||||
return &RefreshTokenResponse{
|
||||
UserID: session.UserUUID.String(),
|
||||
UserEmail: session.UserEmail,
|
||||
UserName: session.UserName,
|
||||
UserRole: session.UserRole,
|
||||
TenantID: session.TenantID.String(),
|
||||
SessionID: session.ID,
|
||||
AccessToken: accessToken,
|
||||
AccessExpiry: accessExpiry,
|
||||
RefreshToken: refreshToken,
|
||||
RefreshExpiry: refreshExpiry,
|
||||
RefreshedAt: time.Now().UTC(),
|
||||
}, nil
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue