package jwt import ( "database/sql" "github.com/pkg/errors" ) // ValidateAccess parses and validates a JWT access token string. // // This method performs comprehensive validation including: // - Signature verification using the secret key // - Expiration time checking (token must not be expired) // - Issuer verification (must match trusted host) // - Scope verification (must be "access" token) // - Revocation status check (if database is configured) // // The validation must be performed within a database transaction context to ensure // consistency when checking the blacklist. If no database is configured, the // revocation check is skipped. // // Parameters: // - tx: Database transaction for checking token revocation status // - tokenString: The JWT token string to validate // // Returns: // - *AccessToken: The validated token with all claims, or nil if validation fails // - error: Detailed error if validation fails (expired, revoked, invalid signature, etc.) func (gen *TokenGenerator) ValidateAccess( tx *sql.Tx, tokenString string, ) (*AccessToken, error) { if tokenString == "" { return nil, errors.New("Access token string not provided") } claims, err := parseToken(gen.secretKey, tokenString) if err != nil { return nil, errors.Wrap(err, "parseToken") } expiry, err := checkTokenExpired(claims["exp"]) if err != nil { return nil, errors.Wrap(err, "checkTokenExpired") } issuer, err := checkTokenIssuer(gen.trustedHost, claims["iss"]) if err != nil { return nil, errors.Wrap(err, "checkTokenIssuer") } ttl, err := getTokenTTL(claims["ttl"]) if err != nil { return nil, errors.Wrap(err, "getTokenTTL") } scope, err := getTokenScope(claims["scope"]) if err != nil { return nil, errors.Wrap(err, "getTokenScope") } if scope != "access" { return nil, errors.New("Token is not an Access token") } issuedAt, err := getIssuedTime(claims["iat"]) if err != nil { return nil, errors.Wrap(err, "getIssuedTime") } subject, err := getTokenSubject(claims["sub"]) if err != nil { return nil, errors.Wrap(err, "getTokenSubject") } fresh, err := getFreshTime(claims["fresh"]) if err != nil { return nil, errors.Wrap(err, "getFreshTime") } jti, err := getTokenJTI(claims["jti"]) if err != nil { return nil, errors.Wrap(err, "getTokenJTI") } token := &AccessToken{ ISS: issuer, TTL: ttl, EXP: expiry, IAT: issuedAt, SUB: subject, Fresh: fresh, JTI: jti, Scope: scope, gen: gen, } valid, err := token.CheckNotRevoked(tx) if err != nil && gen.db != nil { return nil, errors.Wrap(err, "token.CheckNotRevoked") } if !valid && gen.db != nil { return nil, errors.New("Token has been revoked") } return token, nil } // ValidateRefresh parses and validates a JWT refresh token string. // // This method performs comprehensive validation including: // - Signature verification using the secret key // - Expiration time checking (token must not be expired) // - Issuer verification (must match trusted host) // - Scope verification (must be "refresh" token) // - Revocation status check (if database is configured) // // The validation must be performed within a database transaction context to ensure // consistency when checking the blacklist. If no database is configured, the // revocation check is skipped. // // Parameters: // - tx: Database transaction for checking token revocation status // - tokenString: The JWT token string to validate // // Returns: // - *RefreshToken: The validated token with all claims, or nil if validation fails // - error: Detailed error if validation fails (expired, revoked, invalid signature, etc.) func (gen *TokenGenerator) ValidateRefresh( tx *sql.Tx, tokenString string, ) (*RefreshToken, error) { if tokenString == "" { return nil, errors.New("Refresh token string not provided") } claims, err := parseToken(gen.secretKey, tokenString) if err != nil { return nil, errors.Wrap(err, "parseToken") } expiry, err := checkTokenExpired(claims["exp"]) if err != nil { return nil, errors.Wrap(err, "checkTokenExpired") } issuer, err := checkTokenIssuer(gen.trustedHost, claims["iss"]) if err != nil { return nil, errors.Wrap(err, "checkTokenIssuer") } ttl, err := getTokenTTL(claims["ttl"]) if err != nil { return nil, errors.Wrap(err, "getTokenTTL") } scope, err := getTokenScope(claims["scope"]) if err != nil { return nil, errors.Wrap(err, "getTokenScope") } if scope != "refresh" { return nil, errors.New("Token is not an Refresh token") } issuedAt, err := getIssuedTime(claims["iat"]) if err != nil { return nil, errors.Wrap(err, "getIssuedTime") } subject, err := getTokenSubject(claims["sub"]) if err != nil { return nil, errors.Wrap(err, "getTokenSubject") } jti, err := getTokenJTI(claims["jti"]) if err != nil { return nil, errors.Wrap(err, "getTokenJTI") } token := &RefreshToken{ ISS: issuer, TTL: ttl, EXP: expiry, IAT: issuedAt, SUB: subject, JTI: jti, Scope: scope, gen: gen, } valid, err := token.CheckNotRevoked(tx) if err != nil && gen.db != nil { return nil, errors.Wrap(err, "token.CheckNotRevoked") } if !valid && gen.db != nil { return nil, errors.New("Token has been revoked") } return token, nil }