Documentation
¶
Overview ¶
Package authtest installs an authenticated request context without a server, a database, or a ceremony.
It exists because most application tests treat authentication as a precondition rather than as the subject: they need to say which account a request belongs to and then test what the handler does. Running a WebAuthn ceremony to reach that point proves nothing about the handler and costs a port, a database, and an authenticator.
A test may call a bare handler or ServeHTTP against the real middleware chain; the installed value survives both, because the session middleware leaves the context untouched on its unauthenticated path. The same test reads identically under every auth.mode, since this is exactly the value the resolve middleware would have installed.
Why this is not a bypass ¶
The carrier is a context value, which no remote client can set: net/http creates a fresh context for an incoming request, so nothing that arrives over a connection can reach it. A header would be the opposite, which is why plugin/auth reads none.
The package must never appear in an application binary. It cannot forge an identity anywhere it is absent, and pw build rejects it in a dependency graph.
Index ¶
- func Anonymous(ctx context.Context) context.Context
- func Authenticate(client *http.Client, serverURL string, identity Identity) error
- func NewAnonymousRequest(method, target string, body io.Reader) *http.Request
- func NewClient(serverURL string, identity Identity) (*http.Client, error)
- func NewContext(ctx context.Context, identity Identity) context.Context
- func NewRequest(method, target string, body io.Reader, identity Identity) *http.Request
- func SessionCookies(identity Identity) ([]*http.Cookie, error)
- type Identity
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Anonymous ¶
Anonymous returns ctx in the explicitly unauthenticated state, so a test can prove the deny path rather than relying on a value simply being absent.
func Authenticate ¶
Authenticate installs a real session for the identity into the jar of an existing client, which a test uses when it built the client itself.
func NewAnonymousRequest ¶
NewAnonymousRequest returns an httptest request in the explicitly unauthenticated state.
func NewClient ¶
NewClient returns an HTTP client whose jar holds a real login session for the identity, against a server started by testutil.TestRun.
This is the rung above NewRequest: the request travels over a real connection, carries a real session cookie, and passes through every framework middleware including the guard. The session is created by the same session manager a completed login uses, so its rotation, lifetime, and cookie attributes are the production ones.
No ceremony runs. A test that means to prove that authentication itself works must drive the real endpoints with contrib/passkey/passkeytest or a development identity provider instead; this seam assumes authentication works and tests what happens after it.
func NewContext ¶
NewContext returns ctx carrying an authenticated request, exactly as the session middleware would have installed it. auth.User, auth.Session, pw.Authenticated, and pw.RequestAuthentication all read it.
func NewRequest ¶
NewRequest returns an httptest request that already carries the identity. It is the usual entry point: build the request, hand it to a handler, assert on what the handler did.
Types ¶
type Identity ¶
type Identity struct {
// AccountID is the stable application identifier. It also becomes the
// authentication subject, matching what plugin/auth records.
AccountID string
DisplayName string
Email string
// Issuer, Subject, KeyClaim, and Key describe an external identity. They
// are what an OIDC login records and are empty for a passkey session.
Issuer string
Subject string
KeyClaim string
Key string
// Method defaults to auth.MethodOIDC. Use auth.MethodPasskey to model an
// account that logged in with a credential.
Method string
// AuthenticatedAt defaults to now, so a handler gated on recent
// authentication passes unless the test wants it not to.
AuthenticatedAt time.Time
// ExpiresAt defaults to an hour out.
ExpiresAt time.Time
// Scope carries optional tenant, role, or permission values for an
// application authorization check.
Scope []string
}
Identity is what a test says the request is. Only AccountID is required.