Documentation
¶
Overview ¶
Package plugin is the public extension surface of Auth-All.
A plugin contributes HTTP routes, schema tables, lifecycle hooks, and OpenAPI operations. A plugin reaches Auth-All only through the Services interface. The official Magic Link plugin uses this package and nothing else, so a third-party plugin has the same capabilities.
Index ¶
- type CreateUserInput
- type HTTPService
- type IssueTokenInput
- type MFAService
- type Plugin
- type Registry
- func (r *Registry) ComponentSchemas() map[string]*openapi.Schema
- func (r *Registry) Hooks() *hook.Hooks
- func (r *Registry) OpenAPISchema(name string, s *openapi.Schema)
- func (r *Registry) PluginID() string
- func (r *Registry) Route(rt Route)
- func (r *Registry) Routes() []Route
- func (r *Registry) Schema(t schema.Table)
- func (r *Registry) Services() Services
- func (r *Registry) Tables() []schema.Table
- type Route
- type Services
- type SessionService
- type TokenService
- type UserService
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type CreateUserInput ¶
type CreateUserInput struct {
Email string
DisplayName string
ImageURL string
// EmailVerified marks the address as proven by the calling flow.
EmailVerified bool
}
CreateUserInput describes a new user.
type HTTPService ¶
type HTTPService interface {
// CheckOrigin rejects a state-changing request from an untrusted origin.
CheckOrigin(r *http.Request) error
// DecodeJSON reads a JSON request body.
DecodeJSON(r *http.Request, dst any) error
// WriteJSON writes a JSON response.
WriteJSON(w http.ResponseWriter, status int, body any)
// WriteError writes the public error envelope.
WriteError(w http.ResponseWriter, err error)
// SafeRedirect returns candidate when it points at a trusted origin, and
// fallback otherwise.
SafeRedirect(candidate, fallback string) string
// ClientIP returns the request IP for rate-limit keys.
ClientIP(r *http.Request) string
}
HTTPService exposes the request helpers of Auth-All.
type IssueTokenInput ¶
type IssueTokenInput struct {
// Kind separates token namespaces, for example "magic-link".
Kind string
// UserID is optional. A flow for an unknown address leaves it nil.
UserID *string
// Identifier is the subject of the token, normally a normalized email.
Identifier string
// TTL is the token lifetime.
TTL time.Duration
// ReplaceExisting removes outstanding tokens of the same kind and
// identifier before it issues the new token.
ReplaceExisting bool
}
IssueTokenInput describes a one-time token.
type MFAService ¶ added in v0.2.0
type MFAService interface {
// Challenge reports whether the user must pass a second factor, and
// returns a single-use challenge token when so. The caller must issue no
// session while required is true.
Challenge(ctx context.Context, user *store.User) (token string, required bool, err error)
// SetCookie writes the challenge into the short-lived challenge cookie. A
// redirect flow uses it, because a token in a query parameter reaches the
// browser history, the server log, and any leaked Referer header.
SetCookie(w http.ResponseWriter, token string)
// MarkRedirect adds the marker that tells the application to ask for a
// code. The marker names no token, so it is safe in a URL.
MarkRedirect(target string) string
}
MFAService is the second-factor gate.
A plugin that authenticates a user calls Challenge before it issues a session. A user with a live second factor must reach no session until they prove one code, so a plugin that skips this leaves a bypass of the gate.
type Plugin ¶
type Plugin interface {
// ID returns the stable plugin identifier.
ID() string
// Register contributes routes, schema, hooks, and OpenAPI operations.
Register(r *Registry) error
}
Plugin is one Auth-All extension.
type Registry ¶
type Registry struct {
// contains filtered or unexported fields
}
Registry receives the contributions of one plugin.
func NewRegistry ¶
NewRegistry returns a registry for one plugin. Auth-All calls this during construction.
func (*Registry) ComponentSchemas ¶
ComponentSchemas returns the contributed component schemas.
func (*Registry) OpenAPISchema ¶
OpenAPISchema contributes one reusable component schema.
type Route ¶
type Route struct {
// Method is the HTTP method.
Method string
// Path is relative to the configured Auth-All base path and starts with /.
Path string
// Handler serves the route.
Handler http.Handler
// Operation documents the route. A route without an operation stays out of
// the OpenAPI document and out of the generated client.
Operation *openapi.Operation
}
Route is one HTTP route contributed by a plugin.
type Services ¶
type Services interface {
// Store returns the configured storage adapter.
Store() store.Store
// Email returns the configured email sender.
Email() email.Sender
// Events returns the observability emitter.
Events() *events.Emitter
// Now returns the configured clock.
Now() time.Time
// BasePath returns the mounted base path, for example /api/auth.
BasePath() string
// BaseURL returns the absolute public base URL of the application.
BaseURL() string
// RateLimiter returns the configured limiter. It is never nil.
RateLimiter() ratelimit.Limiter
// Logger returns the configured logger.
Logger() *slog.Logger
// Users exposes user operations that run the configured hooks.
Users() UserService
// Sessions exposes session operations.
Sessions() SessionService
// Tokens exposes one-time token operations.
Tokens() TokenService
// HTTP exposes the request helpers Auth-All uses for its own routes.
HTTP() HTTPService
// MFA exposes the second-factor gate. A plugin that authenticates a user
// must consult it before it issues a session.
MFA() MFAService
}
Services is everything Auth-All exposes to a plugin. A plugin gets no other access to Auth-All internals.
type SessionService ¶
type SessionService interface {
// Issue creates a session for the user and writes the session cookie.
// Method names the authentication method for hooks and events.
Issue(ctx context.Context, w http.ResponseWriter, r *http.Request, user *store.User, method string) (*store.Session, error)
// Current resolves the session of a request. It returns nil values when no
// valid session exists.
Current(ctx context.Context, r *http.Request) (*store.Session, *store.User, error)
// Revoke deletes one session.
Revoke(ctx context.Context, sessionID string) error
// RevokeAll deletes every session of one user and returns the count.
RevokeAll(ctx context.Context, userID string) (int, error)
// Clear removes the session cookie.
Clear(w http.ResponseWriter)
}
SessionService exposes session operations.
type TokenService ¶
type TokenService interface {
Issue(ctx context.Context, in IssueTokenInput) (plaintext string, token *store.Token, err error)
// Consume atomically consumes a token. Two concurrent calls for the same
// token produce at most one success.
Consume(ctx context.Context, kind, plaintext string) (*store.Token, error)
// Peek returns a token and consumes nothing. It reports an invalid token
// for a value that is missing, expired, or already consumed.
//
// A confirmation page calls Peek, so a repeated page load and a mail
// scanner that pre-fetches a link do not destroy the token.
Peek(ctx context.Context, kind, plaintext string) (*store.Token, error)
}
TokenService exposes one-time token operations. The plaintext token exists only in the return value of Issue. Auth-All stores only its hash.
type UserService ¶
type UserService interface {
ByID(ctx context.Context, id string) (*store.User, error)
// ByEmail looks a user up by the normalized form of the address.
ByEmail(ctx context.Context, address string) (*store.User, error)
// Create inserts a user and runs the user creation hooks.
Create(ctx context.Context, in CreateUserInput) (*store.User, error)
// MarkEmailVerified records proven ownership of the user email address. It
// changes no other row. A passwordless flow calls ProveEmailOwnership
// instead.
MarkEmailVerified(ctx context.Context, userID string) error
// DeleteCredential removes the password credential of a user. It succeeds
// for a user that has no password credential.
DeleteCredential(ctx context.Context, userID string) error
// ProveEmailOwnership records proven control of the address of a user.
//
// A passwordless flow calls it after the flow proves that the person
// controls the address. When the address was not verified yet, somebody can
// have set a password and started a session before the proof. The method
// therefore deletes the password credential of the user, revokes every
// session of the user, and marks the address verified. It performs the
// three steps in one transaction.
//
// The method does nothing for a user whose address is already verified, so
// a normal repeat sign-in keeps its password and its sessions.
//
// A plugin that proves control of an address must call this method before
// it issues a session.
ProveEmailOwnership(ctx context.Context, userID string) error
}
UserService exposes user operations.