Documentation
¶
Index ¶
- func FetchJWKS(t *testing.T, jwksURI string) map[string]any
- func ParseJWTClaims(t *testing.T, tokenStr string) map[string]any
- func ParseJWTHeader(t *testing.T, tokenStr string) map[string]any
- type OIDCConfig
- type Option
- func WithAdminKey(key string) Option
- func WithAllowPlainPKCE(allow bool) Option
- func WithAudience(aud string) Option
- func WithAudienceFunc(fn func() string) Option
- func WithAuthorizeAutoApproveSubject(subject string) Option
- func WithAuthorizeEnabled(enabled bool) Option
- func WithAuthorizeRedirectOverride(fn func(values url.Values)) Option
- func WithClaimsSupported(claims []string) Option
- func WithConfidentialClient(clientID, secret string) Option
- func WithGrantTypesSupported(grants []string) Option
- func WithIDJAGIssuanceSelfSigned(ttl time.Duration) Option
- func WithIDJAGIssuer(issuer apiauth.IDJAGIssuer) Option
- func WithIssParameterSupported(supported bool) Option
- func WithIssuer(iss string) Option
- func WithScopes(scopes []string) Option
- func WithTrustedAssertionIssuers(issuers []apiauth.TrustedAssertionIssuer) Option
- type TestAuthServer
- func (s *TestAuthServer) AdminKey() string
- func (s *TestAuthServer) Close()
- func (s *TestAuthServer) Issuer() string
- func (s *TestAuthServer) JWKSURL() string
- func (s *TestAuthServer) MintToken(userID string, scopes []string) (string, error)
- func (s *TestAuthServer) MintTokenForSubject(subject string, scopes []string) (string, error)
- func (s *TestAuthServer) MintTokenWithClaims(claims jwt.MapClaims) (string, error)
- func (s *TestAuthServer) TokenEndpoint() string
- func (s *TestAuthServer) URL() string
- type TokenResponse
- func GetClientCredentialsToken(t *testing.T, tokenEndpoint, clientID, clientSecret string, scopes ...string) TokenResponse
- func GetPasswordToken(t *testing.T, tokenEndpoint, clientID, clientSecret, username, password string) TokenResponse
- func PostTokenEndpoint(t *testing.T, tokenEndpoint string, data url.Values) TokenResponse
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func FetchJWKS ¶
FetchJWKS fetches the raw JWKS JSON from the given URI and returns it as a map. Calls t.Fatal on any error.
func ParseJWTClaims ¶
ParseJWTClaims decodes the payload (claims) of a JWT without verifying the signature. For test introspection only — never use in production. Calls t.Fatal on any error.
Types ¶
type OIDCConfig ¶
type OIDCConfig struct {
Issuer string `json:"issuer"`
TokenEndpoint string `json:"token_endpoint"`
JWKSURI string `json:"jwks_uri"`
AuthorizationEndpoint string `json:"authorization_endpoint,omitempty"`
IntrospectionEndpoint string `json:"introspection_endpoint,omitempty"`
RegistrationEndpoint string `json:"registration_endpoint,omitempty"`
ScopesSupported []string `json:"scopes_supported,omitempty"`
ClaimsSupported []string `json:"claims_supported,omitempty"`
TokenEndpointAuthMethodsSupported []string `json:"token_endpoint_auth_methods_supported,omitempty"`
TokenEndpointAuthSigningAlgValuesSupported []string `json:"token_endpoint_auth_signing_alg_values_supported,omitempty"`
}
OIDCConfig holds discovered OIDC / OAuth Authorization Server endpoints. See: https://www.rfc-editor.org/rfc/rfc8414#section-2
func DiscoverOIDC ¶
func DiscoverOIDC(t *testing.T, issuerURL string) OIDCConfig
DiscoverOIDC fetches and parses the OpenID Connect / OAuth Authorization Server Metadata document from issuerURL/.well-known/openid-configuration. Calls t.Fatal on any error.
type Option ¶
type Option func(*config)
Option configures a TestAuthServer.
func WithAdminKey ¶
WithAdminKey sets the admin API key required for app registration endpoints. Default: "testutil-admin-key".
func WithAllowPlainPKCE ¶ added in v0.1.32
WithAllowPlainPKCE opts the test AS into OAuth 2.0 `plain` PKCE on the /authorize endpoint (RFC 7636 §4.4). OAuth 2.1 §7.5 retired plain; this option exists for conformance fixtures that need to exercise the OAuth 2.0 escape hatch documented under capability-gating umbrella #344. AS metadata `code_challenge_methods_supported` extends to ["S256", "plain"] when enabled. Production deployments never set this.
func WithAudience ¶
WithAudience sets the JWT audience claim on minted tokens. Default: "" (no audience restriction).
func WithAudienceFunc ¶ added in v0.1.31
WithAudienceFunc registers a closure consulted on every token mint and validation. A non-empty return takes precedence over the eager WithAudience value; an empty return falls back to it.
Use this when the audience is not known at construction time — the canonical case is an in-process AS whose `aud` must equal a resource server URL only allocated after `httptest.NewServer` runs. Build the AS once, then teach the closure to look up the current value when the RS comes online. The caller owns the storage and synchronisation; testutil only plumbs the closure to OneAuthConfig.AudienceFunc.
See docs/MIGRATION.md "Late-binding the audience" for the full pattern.
func WithAuthorizeAutoApproveSubject ¶ added in v0.1.30
WithAuthorizeAutoApproveSubject sets the subject the auto-approve path binds to issued codes. Empty falls back to "e2e-user".
func WithAuthorizeEnabled ¶ added in v0.1.30
WithAuthorizeEnabled mounts the RFC 6749 §4.1 authorization-code flow endpoint (`GET / POST /authorize`) on the test server. When enabled the AS metadata advertises `authorization_endpoint`, extends `response_types_supported` to include "code", and adds "authorization_code" to `grant_types_supported`.
The mounted flow auto-approves all requests with the subject set by WithAuthorizeAutoApproveSubject (default: "e2e-user"). This is suitable for conformance fixtures and in-process tests — NEVER for production deployments.
func WithAuthorizeRedirectOverride ¶ added in v0.1.30
WithAuthorizeRedirectOverride installs a hook that mutates the /authorize redirect's query values before they are URL-encoded. Lets conformance scenarios test misbehaving-AS branches that a correct production AS cannot simulate — e.g. "AS advertises authorization_response_iss_parameter_supported=true in metadata but does NOT emit iss in the redirect" — by stripping or corrupting individual values.
Production deployments never set this. Mirrors the PR 191 pattern.
func WithClaimsSupported ¶ added in v0.0.83
WithClaimsSupported sets the `claims_supported` field in AS metadata (OIDC Discovery 1.0 §3). Default: the claims OneAuth's bearer tokens already emit (sub, iss, aud, exp, iat, jti, scope, client_id).
func WithConfidentialClient ¶ added in v0.1.34
WithConfidentialClient registers a confidential client (token_endpoint_auth_method=client_secret_post) with the given secret, and wires the AS with an AppStore so confidential-client authentication is enforced on the grants that consult it (jwt-bearer / token-exchange, issue 356; device_code / authorization_code, issue 266).
Opt-in: absent this option the AS runs with no AppStore, preserving the public / assertion-only behavior existing tests rely on.
func WithGrantTypesSupported ¶ added in v0.0.82
WithGrantTypesSupported overrides the `grant_types_supported` field advertised in AS metadata (RFC 8414). Use this when enabling a grant beyond the default (`client_credentials`) — e.g., advertising the jwt-bearer (RFC 7523 §2.1) or token-exchange (RFC 8693) grants alongside the default.
The values supplied REPLACE the default. Callers that want to keep `client_credentials` and add more must include it in the slice.
Note: advertising a grant in metadata does NOT enable its handler at the token endpoint. Pair this with WithTrustedAssertionIssuers to actually serve jwt-bearer / token-exchange requests.
func WithIDJAGIssuanceSelfSigned ¶ added in v0.1.33
WithIDJAGIssuanceSelfSigned opts the token-exchange grant into ID-JAG issuance signed with the test server's OWN RS256 key — the key already published in the server's JWKS. This is the production-realistic path: a redeeming AS can discover the ID-JAG signing key over JWKS by `kid` (TrustedAssertionIssuer.KeyFunc) with only the issuer URL, no pre-shared static key.
ttl bounds the ID-JAG lifetime (<=0 uses the library default). Takes precedence over WithIDJAGIssuer when both are set.
func WithIDJAGIssuer ¶ added in v0.1.33
func WithIDJAGIssuer(issuer apiauth.IDJAGIssuer) Option
WithTrustedAssertionIssuers configures the AS to accept jwt-bearer (RFC 7523 §2.1) and token-exchange (RFC 8693) grants from the listed upstream IdPs. Each entry binds an issuer URL to a public key (or KeyFunc) so the AS can verify assertion signatures.
When the supplied slice is non-empty, this Option AUTOMATICALLY extends the advertised `grant_types_supported` to include the two new grant URIs (so callers don't need to remember the pair). Callers can still pass WithGrantTypesSupported AFTER this option to fully replace the advertised list — last-option-wins for the slice.
See:
- RFC 7523 §2.1: https://www.rfc-editor.org/rfc/rfc7523#section-2.1
- RFC 8693: https://www.rfc-editor.org/rfc/rfc8693
WithIDJAGIssuer opts the token-exchange grant into ID-JAG issuance (requested_token_type=urn:ietf:params:oauth:token-type:id-jag) for the MCP Enterprise-Managed Authorization flow (SEP-990). The issuer signs ID-JAGs with the IdP key the caller supplies; register that key's public half at the redeeming AS via WithTrustedAssertionIssuers so stage 2 can verify it.
Meaningful only alongside WithTrustedAssertionIssuers, which supplies the subject_token (id_token) issuers this AS validates on stage 1.
See: draft-ietf-oauth-identity-assertion-authz-grant-04
func WithIssParameterSupported ¶ added in v0.0.82
WithIssParameterSupported sets the `authorization_response_iss_parameter_supported` field in AS metadata (RFC 9207 §3). Mitigates mix-up attacks against clients that interact with multiple ASes by signaling that the AS includes an `iss` parameter on every authorization response.
When paired with WithAuthorizeEnabled(true), this flag ALSO drives the wire behavior — the /authorize redirect carries `iss=<issuer>` per RFC 9207 §2 — so the AS's advertisement matches what callers observe. To simulate the misbehaving-AS scenario (advertises but does not emit, or emits without advertising), combine with WithAuthorizeRedirectOverride to mutate the redirect query per-scenario.
func WithIssuer ¶
WithIssuer sets the JWT issuer claim and the issuer field in AS metadata. Default: "testutil-issuer" (overridden to server URL after start).
func WithScopes ¶
WithScopes sets the scopes_supported field in AS metadata. Default: ["read", "write", "admin"].
func WithTrustedAssertionIssuers ¶ added in v0.0.82
func WithTrustedAssertionIssuers(issuers []apiauth.TrustedAssertionIssuer) Option
type TestAuthServer ¶
type TestAuthServer struct {
// Server is the underlying httptest.Server. Use URL() for the base URL.
Server *httptest.Server
// OneAuth is the configured transport-independent core (RS256).
OneAuth *apiauth.OneAuth
// TokenEndpointHandler is the HTTP handler mounted at /api/token.
// Distinct name from the TokenEndpoint() method which returns the URL.
TokenEndpointHandler *apiauth.TokenEndpointHandler
// KeyStore holds the server's RSA key and any registered app keys.
KeyStore keys.KeyStorage
// Registrar manages app registrations and serves the /apps/ endpoints.
Registrar *admin.AppRegistrar
// contains filtered or unexported fields
}
TestAuthServer is an in-process oneauth authorization server for integration tests. It generates an RSA 2048 key pair, serves JWKS, issues tokens via the client_credentials grant, and provides OAuth AS metadata (RFC 8414).
The server is cleaned up automatically via t.Cleanup — callers never need to call Close manually.
Endpoints served:
GET /_ah/health — health check POST /api/token — token endpoint (client_credentials) POST /oauth/introspect — token introspection (RFC 7662) GET /.well-known/jwks.json — JWKS public key (RFC 7517) GET /.well-known/openid-configuration — AS metadata (RFC 8414) POST /apps/dcr — dynamic client registration (RFC 7591)
func NewAuthServer ¶ added in v0.0.74
func NewAuthServer(opts ...Option) (*TestAuthServer, error)
NewTestAuthServer creates and starts an in-process authorization server with an RSA 2048 key pair. The server is automatically shut down via t.Cleanup when the test completes.
The server signs JWTs with RS256 and serves the public key via JWKS. Apps can be registered via /apps/dcr (RFC 7591), and tokens can be obtained via /api/token (client_credentials grant). NewAuthServer creates an in-process OAuth authorization server without requiring *testing.T. Use this in standalone examples, benchmarks, or any non-test context. The caller must call Close() when done.
For test code, prefer NewTestAuthServer which auto-registers cleanup.
func NewTestAuthServer ¶
func NewTestAuthServer(t *testing.T, opts ...Option) *TestAuthServer
NewTestAuthServer creates an in-process authorization server for tests. Cleanup is registered via t.Cleanup — the server is stopped automatically.
func (*TestAuthServer) AdminKey ¶
func (s *TestAuthServer) AdminKey() string
AdminKey returns the admin API key configured for this server.
func (*TestAuthServer) Close ¶ added in v0.0.74
func (s *TestAuthServer) Close()
Close stops the underlying HTTP server.
func (*TestAuthServer) Issuer ¶
func (s *TestAuthServer) Issuer() string
Issuer returns the JWT issuer configured for this server.
func (*TestAuthServer) JWKSURL ¶
func (s *TestAuthServer) JWKSURL() string
JWKSURL returns the JWKS endpoint URL.
func (*TestAuthServer) MintToken ¶
func (s *TestAuthServer) MintToken(userID string, scopes []string) (string, error)
MintToken creates a valid RS256 JWT with standard claims for the given user and scopes. This is a fast path that bypasses the HTTP token endpoint — no network round-trip is involved.
The token includes: sub, iss, aud (if configured), type ("access"), scopes, iat, exp (15 min), jti, and a kid header matching the server's JWKS-published key.
See: https://www.rfc-editor.org/rfc/rfc7519 (JWT)
func (*TestAuthServer) MintTokenForSubject ¶ added in v0.0.74
func (s *TestAuthServer) MintTokenForSubject(subject string, scopes []string) (string, error)
MintTokenForSubject creates a valid RS256 JWT for the given subject and scopes. The token has iss=server issuer, aud=server audience, exp=15 min. Use this in standalone examples that don't have *testing.T.
func (*TestAuthServer) MintTokenWithClaims ¶
func (s *TestAuthServer) MintTokenWithClaims(claims jwt.MapClaims) (string, error)
MintTokenWithClaims creates an RS256 JWT with arbitrary claims. Standard defaults (iss, iat, exp) are set but can be overridden by the provided claims map. This is useful for testing edge cases: wrong issuer, expired tokens, missing claims, etc.
The kid header is always set to match the server's JWKS key.
See: https://www.rfc-editor.org/rfc/rfc7519 (JWT)
func (*TestAuthServer) TokenEndpoint ¶
func (s *TestAuthServer) TokenEndpoint() string
TokenEndpoint returns the token endpoint URL.
func (*TestAuthServer) URL ¶
func (s *TestAuthServer) URL() string
URL returns the base URL of the test auth server (e.g., "http://127.0.0.1:PORT").
type TokenResponse ¶
type TokenResponse struct {
AccessToken string `json:"access_token"`
TokenType string `json:"token_type"`
ExpiresIn int `json:"expires_in"`
Scope string `json:"scope"`
RefreshToken string `json:"refresh_token,omitempty"`
}
TokenResponse holds the token endpoint response fields. See: https://www.rfc-editor.org/rfc/rfc6749#section-5.1
func GetClientCredentialsToken ¶
func GetClientCredentialsToken(t *testing.T, tokenEndpoint, clientID, clientSecret string, scopes ...string) TokenResponse
GetClientCredentialsToken acquires a token using the OAuth 2.0 client_credentials grant. Works against any RFC 6749-compliant token endpoint. Calls t.Fatal on any error.
func GetPasswordToken ¶
func GetPasswordToken(t *testing.T, tokenEndpoint, clientID, clientSecret, username, password string) TokenResponse
GetPasswordToken acquires a token using the OAuth 2.0 resource owner password credentials grant. Works against any RFC 6749-compliant token endpoint. Calls t.Fatal on any error.
func PostTokenEndpoint ¶ added in v0.0.73
PostTokenEndpoint sends a form POST to an OAuth token endpoint and decodes the JSON response into a TokenResponse. Use this for any grant type — the convenience functions (GetClientCredentialsToken, GetPasswordToken) delegate here. Calls t.Fatal on HTTP or decode errors.