feat: new ValidateToken method for AuthService, based on code from the monolithic implementation of auth middleware;

feat: add detailed authentication error types;
This commit is contained in:
2025-07-15 21:59:05 +03:00
parent b3a405016e
commit a582b75c82
2 changed files with 85 additions and 1 deletions

View File

@@ -601,7 +601,85 @@ func (a *authServiceImpl) Refresh(request models.RefreshRequest) (*models.Refres
return nil, errs.ErrNotImplemented
}
func (a *authServiceImpl) ValidateToken(token string, tokenType enums.JwtTokenType) (*dto.SessionInfo, error) {
func (a *authServiceImpl) ValidateToken(jwtToken string, tokenType enums.JwtTokenType) (*dto.SessionInfo, error) {
var err error
token, err := jwt.ParseWithClaims(
jwtToken,
&dto.UserClaims{},
func(token *jwt.Token) (any, error) {
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
}
return []byte(config.GetConfig().JwtSecret), nil
},
)
if err != nil {
if errors.Is(err, jwt.ErrTokenExpired) {
return nil, errs.ErrTokenExpired
}
return nil, errs.ErrInvalidToken
}
if claims, ok := token.Claims.(*dto.UserClaims); ok && token.Valid {
if claims.Type != tokenType {
return nil, errs.ErrWrongTokenType
}
ctx := context.TODO()
isTerminated, redisErr := a.redis.Get(ctx, fmt.Sprintf("session::%s::is_terminated", claims.Session)).Bool()
if redisErr != nil && redisErr != redis.Nil {
a.log.Error(
"Failed to lookup cache to check whether session is not terminated",
zap.Error(redisErr))
return nil, redisErr
}
// Cache if nil
if redisErr == redis.Nil {
db := database.NewDbHelper(a.dbctx)
session, err := db.Queries.GetSessionByGuid(db.CTX, claims.Session)
if err != nil {
if errors.Is(err, pgx.ErrNoRows) {
a.log.Warn(
"Session does not exist or was deleted",
zap.String("session", claims.Session))
return nil, errs.ErrSessionNotFound
}
a.log.Error(
"Failed to lookup session in database",
zap.String("session", claims.Session),
zap.Error(err))
return nil, err
}
if err := a.redis.Set(
ctx,
fmt.Sprintf("session::%s::is_terminated", claims.Session),
session.Terminated,
time.Duration(8 * time.Hour), // XXX: magic number
).Err(); err != nil {
a.log.Error(
"Failed to cache session's is_terminated state",
zap.String("session", claims.Session),
zap.Error(err))
// c.AbortWithStatus(http.StatusInternalServerError)
return nil, err
}
isTerminated = *session.Terminated
}
if isTerminated {
return nil, errs.ErrSessionTerminated
}
}
return nil, errs.ErrNotImplemented
}