This commit is contained in:
2025-08-23 16:48:31 -04:00
parent 3e02ef57b9
commit 632473a7d8
8 changed files with 75 additions and 45 deletions

View File

@ -104,11 +104,10 @@ type UserToken struct {
// VerifyRequest represents a token verification request // VerifyRequest represents a token verification request
type VerifyRequest struct { type VerifyRequest struct {
AppID string `json:"app_id" validate:"required"` AppID string `json:"app_id" validate:"required"`
Type TokenType `json:"type" validate:"required,oneof=static user"` UserID string `json:"user_id,omitempty"` // Required for user tokens
UserID string `json:"user_id,omitempty"` // Required for user tokens Token string `json:"token" validate:"required"`
Token string `json:"token" validate:"required"` Permissions []string `json:"permissions,omitempty"`
Permissions []string `json:"permissions,omitempty"`
} }
// VerifyResponse represents a token verification response // VerifyResponse represents a token verification response

View File

@ -98,7 +98,7 @@ func (h *AuthHandler) Verify(c *gin.Context) {
return return
} }
h.logger.Debug("Verifying token", zap.String("app_id", req.AppID), zap.String("type", string(req.Type))) h.logger.Debug("Verifying token", zap.String("app_id", req.AppID))
response, err := h.tokenService.VerifyToken(c.Request.Context(), &req) response, err := h.tokenService.VerifyToken(c.Request.Context(), &req)
if err != nil { if err != nil {

View File

@ -265,10 +265,47 @@ func (s *tokenService) GenerateUserToken(ctx context.Context, appID, userID stri
return finalToken, nil return finalToken, nil
} }
// detectTokenType detects the token type based on its prefix
func (s *tokenService) detectTokenType(token string, app *domain.Application) domain.TokenType {
// Check for user token pattern first (UT- suffix)
if app.TokenPrefix != "" {
userPrefix := app.TokenPrefix + "UT-"
if strings.HasPrefix(token, userPrefix) {
return domain.TokenTypeUser
}
staticPrefix := app.TokenPrefix + "T-"
if strings.HasPrefix(token, staticPrefix) {
return domain.TokenTypeStatic
}
}
// Check for custom prefix pattern in case app prefix is not set
// Look for pattern: 2-4 uppercase letters + "UT-" or "T-"
if len(token) >= 6 {
dashIndex := strings.Index(token, "-")
if dashIndex >= 3 && dashIndex <= 6 { // 2-4 chars + "T" or "UT"
prefixPart := token[:dashIndex+1]
if strings.HasSuffix(prefixPart, "UT-") {
return domain.TokenTypeUser
}
if strings.HasSuffix(prefixPart, "T-") {
return domain.TokenTypeStatic
}
}
}
// Check for default kms_ prefix
if strings.HasPrefix(token, "kms_") {
return domain.TokenTypeStatic // Default tokens are static
}
// Default to static if pattern is unclear
return domain.TokenTypeStatic
}
// VerifyToken verifies a token and returns verification response // VerifyToken verifies a token and returns verification response
func (s *tokenService) VerifyToken(ctx context.Context, req *domain.VerifyRequest) (*domain.VerifyResponse, error) { func (s *tokenService) VerifyToken(ctx context.Context, req *domain.VerifyRequest) (*domain.VerifyResponse, error) {
s.logger.Debug("Verifying token", zap.String("app_id", req.AppID), zap.String("type", string(req.Type)))
// Validate request // Validate request
if req.Token == "" { if req.Token == "" {
return &domain.VerifyResponse{ return &domain.VerifyResponse{
@ -289,7 +326,15 @@ func (s *tokenService) VerifyToken(ctx context.Context, req *domain.VerifyReques
}, nil }, nil
} }
switch req.Type { // Always auto-detect token type from prefix
tokenType := s.detectTokenType(req.Token, app)
s.logger.Debug("Auto-detected token type",
zap.String("app_id", req.AppID),
zap.String("detected_type", string(tokenType)))
s.logger.Debug("Verifying token", zap.String("app_id", req.AppID), zap.String("type", string(tokenType)))
switch tokenType {
case domain.TokenTypeStatic: case domain.TokenTypeStatic:
return s.verifyStaticToken(ctx, req, app) return s.verifyStaticToken(ctx, req, app)
case domain.TokenTypeUser: case domain.TokenTypeUser:

View File

@ -182,10 +182,9 @@ const TokenTester: React.FC = () => {
console.log('Testing callback with token verification:', values); console.log('Testing callback with token verification:', values);
// Verify the token received in the callback // Verify the token received in the callback (type will be auto-detected)
const verifyResponse = await apiService.verifyToken({ const verifyResponse = await apiService.verifyToken({
app_id: values.app_id, app_id: values.app_id,
type: 'user',
token: values.token, token: values.token,
permissions: values.permissions || [], permissions: values.permissions || [],
}); });

View File

@ -111,7 +111,6 @@ const TokenTesterCallback: React.FC = () => {
const verifyRequest = { const verifyRequest = {
app_id: appId, app_id: appId,
type: 'user',
token: token, token: token,
permissions: [], // We'll verify without specific permissions permissions: [], // We'll verify without specific permissions
}; };

View File

@ -184,7 +184,7 @@ const Tokens: React.FC = () => {
const verifyRequest: VerifyRequest = { const verifyRequest: VerifyRequest = {
app_id: values.app_id, app_id: values.app_id,
type: values.token_type || 'static', // Remove explicit type - it will be auto-detected from token prefix
token: values.token, token: values.token,
permissions: values.permissions || [], permissions: values.permissions || [],
}; };
@ -505,41 +505,30 @@ const Tokens: React.FC = () => {
width={800} width={800}
> >
<Space direction="vertical" size="large" style={{ width: '100%' }}> <Space direction="vertical" size="large" style={{ width: '100%' }}>
<Alert
message="Automatic Token Type Detection"
description="The system will automatically detect if your token is a static token (KMST-, KMS2T-, etc.) or user token (KMSUT-, KMS2UT-, etc.) based on its prefix."
type="info"
showIcon
/>
<Form <Form
form={verifyForm} form={verifyForm}
layout="vertical" layout="vertical"
onFinish={handleVerifyToken} onFinish={handleVerifyToken}
> >
<Row gutter={16}> <Form.Item
<Col span={12}> name="app_id"
<Form.Item label="Application"
name="app_id" rules={[{ required: true, message: 'Please select an application' }]}
label="Application" >
rules={[{ required: true, message: 'Please select an application' }]} <Select placeholder="Select application">
> {applications.map(app => (
<Select placeholder="Select application"> <Option key={app.app_id} value={app.app_id}>
{applications.map(app => ( {app.app_id}
<Option key={app.app_id} value={app.app_id}> </Option>
{app.app_id} ))}
</Option> </Select>
))} </Form.Item>
</Select>
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="token_type"
label="Token Type"
rules={[{ required: true, message: 'Please select token type' }]}
initialValue="static"
>
<Select placeholder="Select token type">
<Option value="static">Static Token</Option>
<Option value="user">User Token (JWT)</Option>
</Select>
</Form.Item>
</Col>
</Row>
<Form.Item <Form.Item
name="token" name="token"

View File

@ -72,7 +72,6 @@ export interface PaginatedResponse<T> {
export interface VerifyRequest { export interface VerifyRequest {
app_id: string; app_id: string;
type: string;
user_id?: string; user_id?: string;
token: string; token: string;
permissions?: string[]; permissions?: string[];

View File

@ -96,7 +96,7 @@ func (suite *IntegrationTestSuite) setupServer() {
// Initialize services // Initialize services
appService := services.NewApplicationService(appRepo, logger) appService := services.NewApplicationService(appRepo, logger)
tokenService := services.NewTokenService(tokenRepo, appRepo, permRepo, grantRepo, suite.cfg.GetString("INTERNAL_HMAC_KEY"), logger) tokenService := services.NewTokenService(tokenRepo, appRepo, permRepo, grantRepo, suite.cfg.GetString("INTERNAL_HMAC_KEY"), suite.cfg, logger)
authService := services.NewAuthenticationService(suite.cfg, logger) authService := services.NewAuthenticationService(suite.cfg, logger)
// Initialize handlers // Initialize handlers