Documentation
¶
Index ¶
- Constants
- Variables
- func BuildReservedClaimKeys(prefix string) map[string]struct{}
- func ComputeAtHash(accessToken string) string
- func DeriveKeyID(pub crypto.PublicKey) (string, error)
- func EmittedName(prefix, logical string) string
- func LoadSigningKey(path string) (crypto.Signer, error)
- func ParseSigningKey(data []byte) (crypto.Signer, error)
- func ValidateExtraClaims(m map[string]any, reserved map[string]struct{}) error
- type IDTokenParams
- type IDTokenProvider
- type LocalTokenProvider
- func (p *LocalTokenProvider) Algorithm() string
- func (p *LocalTokenProvider) GenerateClientCredentialsToken(ctx context.Context, userID, clientID, scopes string, ttl time.Duration, ...) (*Result, error)
- func (p *LocalTokenProvider) GenerateIDToken(params IDTokenParams) (string, error)
- func (p *LocalTokenProvider) GenerateRefreshToken(ctx context.Context, userID, clientID, scopes string, ttl time.Duration, ...) (*Result, error)
- func (p *LocalTokenProvider) GenerateToken(ctx context.Context, userID, clientID, scopes string, ttl time.Duration, ...) (*Result, error)
- func (p *LocalTokenProvider) KeyID() string
- func (p *LocalTokenProvider) Name() string
- func (p *LocalTokenProvider) ParseJWT(tokenString string) (*ValidationResult, error)
- func (p *LocalTokenProvider) PublicKey() crypto.PublicKey
- func (p *LocalTokenProvider) RefreshAccessToken(ctx context.Context, refreshToken string, accessTTL, refreshTTL time.Duration, ...) (*RefreshResult, error)
- func (p *LocalTokenProvider) ValidateRefreshToken(ctx context.Context, tokenString string) (*ValidationResult, error)
- func (p *LocalTokenProvider) ValidateToken(ctx context.Context, tokenString string) (*ValidationResult, error)
- type Option
- type PrivateClaim
- type RefreshResult
- type Result
- type ValidationResult
Constants ¶
const ( TokenCategoryAccess = "access" TokenCategoryRefresh = "refresh" )
Token category constants used in the "type" JWT claim.
const (
TokenTypeBearer = "Bearer"
)
Token type constants
Variables ¶
var ( // ErrTokenGeneration indicates token generation failed ErrTokenGeneration = errors.New("failed to generate token") // ErrInvalidToken indicates the token is invalid ErrInvalidToken = errors.New("invalid token") // ErrExpiredToken indicates the token has expired ErrExpiredToken = errors.New("token expired") // ErrInvalidRefreshToken indicates the refresh token is invalid ErrInvalidRefreshToken = errors.New("invalid refresh token") // ErrExpiredRefreshToken indicates the refresh token has expired ErrExpiredRefreshToken = errors.New("refresh token expired") // ErrInvalidScope indicates scope validation failed ErrInvalidScope = errors.New("invalid scope") )
var ErrReservedClaimKey = errors.New("reserved claim key")
ErrReservedClaimKey is returned when caller-supplied extra claims attempt to set a reserved JWT/OIDC standard claim. The issuer owns these claims and callers must not provide them via extra_claims.
Functions ¶
func BuildReservedClaimKeys ¶ added in v0.29.0
BuildReservedClaimKeys returns the set of JWT claim keys that callers must not supply via extra_claims for a deployment configured with the given private-claim prefix. It includes:
- the static RFC/OIDC/AuthGate-internal keys (canonical list owned by internal/config to avoid drift between this package's runtime check and config's startup collision check),
- the bare logical names from privateClaims (legacy-name impersonation guard — without it, callers could submit extra_claims={"domain":"evil"} and the bare claim would survive into the signed JWT),
- the composed `<prefix>_<logical>` key for every entry in privateClaims,
- the default-prefixed forms (extra_<logical>) ALWAYS, regardless of the configured prefix. Reserving the default forms universally blocks an impersonation vector during prefix transitions: a deployment running JWT_PRIVATE_CLAIM_PREFIX=acme would otherwise accept caller-supplied "extra_domain" and let it land in the signed JWT, fooling any un-migrated downstream consumer that still reads the default key.
Build once at parser construction time and reuse — the result is intended to be passed into ValidateExtraClaims rather than recomputed per request.
func ComputeAtHash ¶ added in v0.13.0
ComputeAtHash computes the at_hash claim value per OIDC Core 1.0 §3.3.2.11. at_hash = base64url( left-most 128 bits of SHA-256( ASCII(access_token) ) )
func DeriveKeyID ¶ added in v0.22.0
DeriveKeyID computes a deterministic kid from the SHA-256 hash of the DER-encoded public key (SPKI format). Returns a base64url-encoded string of the full 32-byte hash, suitable for JWKS key rotation.
func EmittedName ¶ added in v0.29.0
EmittedName composes the JWT key written for a private claim: "<prefix>_<logical>". AuthGate adds the separating underscore itself; the configured prefix must therefore not have a trailing underscore (validated at startup in config.validateJWTPrivateClaimPrefix).
Centralizing composition here means every emission site, every reserved-key derivation, and every test reads the same source of truth — there is no place where someone could forget to add the underscore.
func LoadSigningKey ¶ added in v0.22.0
LoadSigningKey reads a PEM file and returns the parsed private key. Supports RSA (PKCS#1 / PKCS#8) and ECDSA (SEC1 / PKCS#8).
func ParseSigningKey ¶ added in v0.28.0
ParseSigningKey parses PEM-encoded data into a supported private key. Supports RSA (PKCS#1 / PKCS#8) and ECDSA (SEC1 / PKCS#8). All PEM blocks are tried in order until a supported key is found.
func ValidateExtraClaims ¶ added in v0.29.0
ValidateExtraClaims rejects empty keys and any key in the supplied reserved set. Returns the first violation found; nil for an empty or nil claims map. The reserved set must be supplied by the caller (typically built once via BuildReservedClaimKeys at parser construction time) and must be non-nil — a nil reserved map would silently disable reserved-key enforcement because nil-map lookups always return ok=false. No additional key-format validation (length, character set, namespacing) is performed — callers that need stricter input rules must layer them on top.
Types ¶
type IDTokenParams ¶ added in v0.13.0
type IDTokenParams = core.IDTokenParams
IDTokenParams holds all data needed to generate an OIDC ID Token (OIDC Core 1.0 §2). Re-exported from core as a type alias so existing callers (token.IDTokenParams{...}) compile unchanged while the canonical definition lives in core.
type IDTokenProvider ¶ added in v0.15.0
type IDTokenProvider = core.IDTokenProvider
IDTokenProvider is an optional capability of a TokenProvider. Currently, LocalTokenProvider is the only built-in production implementation. Re-exported from core for callers that import only the token package.
type LocalTokenProvider ¶
type LocalTokenProvider struct {
// contains filtered or unexported fields
}
LocalTokenProvider generates and validates JWT tokens locally
func NewLocalTokenProvider ¶
func NewLocalTokenProvider(cfg *config.Config, opts ...Option) (*LocalTokenProvider, error)
NewLocalTokenProvider creates a new local token provider. By default it uses HS256. Use WithSigningKey and WithKeyID for asymmetric algorithms. Returns an error if the algorithm requires an asymmetric key but none was provided.
func (*LocalTokenProvider) Algorithm ¶ added in v0.22.0
func (p *LocalTokenProvider) Algorithm() string
Algorithm returns the JWT signing algorithm name (e.g. "HS256", "RS256", "ES256").
func (*LocalTokenProvider) GenerateClientCredentialsToken ¶ added in v0.12.0
func (p *LocalTokenProvider) GenerateClientCredentialsToken( ctx context.Context, userID, clientID, scopes string, ttl time.Duration, extraClaims map[string]any, ) (*Result, error)
GenerateClientCredentialsToken creates an access token for the client_credentials grant. If ttl > 0 it overrides the default CLIENT_CREDENTIALS_TOKEN_EXPIRATION. The userID field carries the synthetic machine identity "client:<clientID>".
func (*LocalTokenProvider) GenerateIDToken ¶ added in v0.13.0
func (p *LocalTokenProvider) GenerateIDToken(params IDTokenParams) (string, error)
GenerateIDToken creates a signed JWT ID Token for the given params. The signing algorithm and key are determined by the provider's configuration. ID tokens are not stored in the database; they are short-lived and non-revocable by design.
func (*LocalTokenProvider) GenerateRefreshToken ¶
func (p *LocalTokenProvider) GenerateRefreshToken( ctx context.Context, userID, clientID, scopes string, ttl time.Duration, extraClaims map[string]any, ) (*Result, error)
GenerateRefreshToken creates a refresh token JWT. If ttl > 0 it overrides the default REFRESH_TOKEN_EXPIRATION.
func (*LocalTokenProvider) GenerateToken ¶
func (p *LocalTokenProvider) GenerateToken( ctx context.Context, userID, clientID, scopes string, ttl time.Duration, extraClaims map[string]any, ) (*Result, error)
GenerateToken creates a JWT access token using local signing. If ttl > 0 it overrides p.config.JWTExpiration and no jitter is applied (the caller has chosen an explicit lifetime per client profile).
func (*LocalTokenProvider) KeyID ¶ added in v0.22.0
func (p *LocalTokenProvider) KeyID() string
KeyID returns the "kid" value used in JWT headers.
func (*LocalTokenProvider) Name ¶
func (p *LocalTokenProvider) Name() string
Name returns provider name for logging
func (*LocalTokenProvider) ParseJWT ¶ added in v0.18.0
func (p *LocalTokenProvider) ParseJWT(tokenString string) (*ValidationResult, error)
ParseJWT parses a JWT token, verifies its signature, and extracts standard claims. It does not check the "type" claim — callers (ValidateToken, ValidateRefreshToken) add their own type-specific checks on top.
func (*LocalTokenProvider) PublicKey ¶ added in v0.22.0
func (p *LocalTokenProvider) PublicKey() crypto.PublicKey
PublicKey returns the asymmetric public verification key. Returns nil for HS256 (symmetric key).
func (*LocalTokenProvider) RefreshAccessToken ¶
func (p *LocalTokenProvider) RefreshAccessToken( ctx context.Context, refreshToken string, accessTTL, refreshTTL time.Duration, extraClaims map[string]any, ) (*RefreshResult, error)
RefreshAccessToken generates new access token (and optionally new refresh token in rotation mode). accessTTL and refreshTTL override the default expirations when > 0, allowing the caller (TokenService) to apply the client's current TokenProfile at refresh time rather than reusing the TTL the original tokens were issued with.
extraClaims is also re-applied here, so callers (TokenService) can inject the client's CURRENT project / service_account at refresh time rather than freezing values from the original issuance.
func (*LocalTokenProvider) ValidateRefreshToken ¶
func (p *LocalTokenProvider) ValidateRefreshToken( ctx context.Context, tokenString string, ) (*ValidationResult, error)
ValidateRefreshToken verifies a refresh token JWT
func (*LocalTokenProvider) ValidateToken ¶
func (p *LocalTokenProvider) ValidateToken( ctx context.Context, tokenString string, ) (*ValidationResult, error)
ValidateToken verifies a JWT access token using local verification. It rejects refresh tokens (type=="refresh") at the JWT level.
type Option ¶ added in v0.22.0
type Option func(*LocalTokenProvider)
Option configures a LocalTokenProvider.
func WithSigningKey ¶ added in v0.22.0
WithSigningKey sets the asymmetric signing and verification keys. Only *rsa.PrivateKey/*rsa.PublicKey (RS256) and *ecdsa.PrivateKey/*ecdsa.PublicKey (ES256) are supported; NewLocalTokenProvider validates concrete types and returns an error on mismatch.
type PrivateClaim ¶ added in v0.29.0
type PrivateClaim struct {
// LogicalName is the stable identifier used internally and inside
// EmittedName composition. It must NOT be changed without coordinating
// with downstream consumers — the composed emitted key is part of the
// public token contract.
LogicalName string
}
PrivateClaim describes an AuthGate-emitted private JWT claim issued under the configurable prefix (JWT_PRIVATE_CLAIM_PREFIX). The emitted key is composed at runtime via EmittedName(prefix, LogicalName).
Trust levels differ across the registry:
- `domain` is **server-attested**: sourced from the AuthGate process's JWT_DOMAIN configuration; cannot be set per-client or by a caller.
- `uid` is **server-attested**: sourced from the User.Username row resolved at issuance/refresh time; cannot be set per-client or by a caller. Omitted when the issuance has no real user (client_credentials grant) or the user lookup fails. Reflects username-at-issuance — a subsequent admin rename surfaces on the next issuance/refresh.
- `project` and `service_account` are **owner-set**: sourced from the OAuthApplication row (admin or client owner). A signed JWT only proves AuthGate emitted these values, not that the asserted project / service-account ownership has been independently verified.
Downstream gateways that route or authorize on these claims must verify the JWT signature AND apply their own access policies — never treat owner-set values as authoritative proof of identity. See docs/JWT_VERIFICATION.md for the full trust model.
func PrivateClaimRegistry ¶ added in v0.29.0
func PrivateClaimRegistry() []PrivateClaim
PrivateClaimRegistry returns a defensive copy of the AuthGate-emitted private-claim registry. Callers that need to iterate the registry from outside this package (tests, downstream tooling) must use this accessor; the underlying slice is intentionally unexported to prevent cross-package mutation.
type RefreshResult ¶
type RefreshResult = core.TokenRefreshResult
RefreshResult is an alias for core.TokenRefreshResult.
type Result ¶
type Result = core.TokenResult
Result is an alias for core.TokenResult. All existing callers using *token.Result continue to compile unchanged.
type ValidationResult ¶
type ValidationResult = core.TokenValidationResult
ValidationResult is an alias for core.TokenValidationResult.