anonpenguin23 fda47533c3 feat: per-namespace rate-limit self-service + WS JWT auth + release 0.122.12
Per-namespace rate-limit config (feature #69)
- Migration 027: new `namespace_rate_limit_config` table
  (namespace PK, requests_per_minute, burst, audit metadata).
- pkg/ratelimit: Manager + RQLite ConfigStore + types. Same pattern
  as the push config in bug #220's follow-up — LRU cache, invalidate
  on PUT/DELETE, falls back to YAML defaults when no row exists.
- pkg/gateway/handlers/ratelimit: GET/PUT/DELETE /v1/namespace/rate-limit.
  PUT requests are rejected if they exceed the operator's configured
  ceiling (MaxRequestsPerMinute / MaxBurst) — tenants self-serve but
  cannot raise their quota past the cap.
- pkg/gateway/rate_limiter.go: per-namespace lookup, default fallback.
- pkg/gateway/middleware.go: WS JWT middleware (middleware_ws_jwt_test.go).
- pkg/gateway/auth/service.go: refresh-token rotation hardening with
  regression test in refresh_rotation_test.go.

AI agent instructions
- Add AGENTS.md, CLAUDE.md, .github/copilot-instructions.md (DeBros v0.2.0
  baseline).

DeBros rules bumped to v0.2.0 (sha bb6e6ef).

VERSION bumped to 0.122.12.
2026-05-13 15:41:36 +03:00

73 lines
3.5 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 claims and TTL.
// Returns: token, expirationUnix, error.
GenerateJWT(namespace, subject string, ttl time.Duration) (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
}