anonpenguin23 d113b75497 feat(auth): refresh-token custom claims hook (#548)
Custom JWT claims survive token refresh: migration 031 adds the
custom-claims column to refresh tokens, the new gateway ClaimsProvider
re-resolves claims on refresh, and the serverless invoke path carries
them through. Includes refresh-rotation, WS-JWT middleware, and
claims-provider test coverage.
2026-06-12 08:05:27 +03:00

74 lines
3.6 KiB
Go

package contracts
import (
"context"
"time"
)
// AuthService handles wallet-based authentication and authorization.
// Provides nonce generation, signature verification, JWT lifecycle management,
// and application registration for the gateway.
type AuthService interface {
// CreateNonce generates a cryptographic nonce for wallet authentication.
// The nonce is valid for a limited time and used to prevent replay attacks.
// wallet is the wallet address, purpose describes the nonce usage,
// and namespace isolates nonces across different contexts.
CreateNonce(ctx context.Context, wallet, purpose, namespace string) (string, error)
// VerifySignature validates a cryptographic signature from a wallet.
// Supports multiple blockchain types (ETH, SOL) for signature verification.
// Returns true if the signature is valid for the given nonce.
VerifySignature(ctx context.Context, wallet, nonce, signature, chainType string) (bool, error)
// IssueTokens generates a new access token and refresh token pair.
// Access tokens are short-lived (typically 15 minutes).
// Refresh tokens are long-lived (typically 30 days).
// Returns: accessToken, refreshToken, expirationUnix, error.
IssueTokens(ctx context.Context, wallet, namespace string) (string, string, int64, error)
// RefreshToken atomically rotates a refresh token: validates the supplied
// token, revokes it, mints a fresh refresh token alongside a new access
// token, and returns both. RFC 9700 §4.12 / feature #68.
// Returns: newAccessToken, newRefreshToken, subject (wallet), expirationUnix, error.
// The error sentinel ErrRefreshTokenReplay indicates the CAS lock was lost
// (concurrent use or replay attempt).
RefreshToken(ctx context.Context, refreshToken, namespace string) (string, string, string, int64, error)
// RevokeToken invalidates a refresh token or all tokens for a subject.
// If token is provided, revokes that specific token.
// If all is true and subject is provided, revokes all tokens for that subject.
RevokeToken(ctx context.Context, namespace, token string, all bool, subject string) error
// ParseAndVerifyJWT validates a JWT access token and returns its claims.
// Verifies signature, expiration, and issuer.
ParseAndVerifyJWT(token string) (*JWTClaims, error)
// GenerateJWT creates a new signed JWT with the specified subject, TTL, and
// optional additive custom claims (nil = none; bugboard #548).
// Returns: token, expirationUnix, error.
GenerateJWT(namespace, subject string, ttl time.Duration, custom map[string]string) (string, int64, error)
// RegisterApp registers a new client application with the gateway.
// Returns an application ID that can be used for OAuth flows.
RegisterApp(ctx context.Context, wallet, namespace, name, publicKey string) (string, error)
// GetOrCreateAPIKey retrieves an existing API key or creates a new one.
// API keys provide programmatic access without interactive authentication.
GetOrCreateAPIKey(ctx context.Context, wallet, namespace string) (string, error)
// ResolveNamespaceID ensures a namespace exists and returns its internal ID.
// Creates the namespace if it doesn't exist.
ResolveNamespaceID(ctx context.Context, namespace string) (interface{}, error)
}
// JWTClaims represents the claims contained in a JWT access token.
type JWTClaims struct {
Iss string `json:"iss"` // Issuer
Sub string `json:"sub"` // Subject (wallet address)
Aud string `json:"aud"` // Audience
Iat int64 `json:"iat"` // Issued At
Nbf int64 `json:"nbf"` // Not Before
Exp int64 `json:"exp"` // Expiration
Namespace string `json:"namespace"` // Namespace isolation
}