Documentation
¶
Overview ¶
Package oauth provides OAuth2 server functionality for Prefab applications.
The OAuth plugin uses the go-oauth2/oauth2 library to provide a production-ready OAuth2 authorization server with minimal configuration.
Basic Usage ¶
Create an OAuth server with just a few lines:
oauthPlugin := oauth.NewBuilder().
WithClient(oauth.Client{
ID: "my-app",
Secret: "secret",
RedirectURIs: []string{"http://localhost:3000/callback"},
Scopes: []string{"read", "write"},
}).
Build()
server := prefab.New(
prefab.WithPlugin(auth.Plugin()),
prefab.WithPlugin(oauthPlugin),
)
Scope-Based Authorization ¶
OAuth tokens carry scopes that can be used in authorization decisions:
if oauth.HasScope(ctx, "write") {
// Allow write operation
}
if oauth.IsOAuthRequest(ctx) {
clientID := oauth.OAuthClientIDFromContext(ctx)
}
Index ¶
- Constants
- Variables
- func FormatScopes(scopes []string) string
- func HasAllScopes(ctx context.Context, scopes ...string) bool
- func HasAnyScope(ctx context.Context, scopes ...string) bool
- func HasScope(ctx context.Context, scope string) bool
- func IsOAuthRequest(ctx context.Context) bool
- func OAuthClientIDFromContext(ctx context.Context) string
- func OAuthScopesFromContext(ctx context.Context) []string
- func ParseScopes(scopeStr string) []string
- func WithOAuthClientID(ctx context.Context, clientID string) context.Context
- func WithOAuthScopes(ctx context.Context, scopes []string) context.Context
- type Builder
- func (b *Builder) Build() *OAuthPlugin
- func (b *Builder) WithAccessTokenExpiry(d time.Duration) *Builder
- func (b *Builder) WithAuthCodeExpiry(d time.Duration) *Builder
- func (b *Builder) WithClient(client Client) *Builder
- func (b *Builder) WithClientStore(store ClientStore) *Builder
- func (b *Builder) WithEnforcePKCE(enforce bool) *Builder
- func (b *Builder) WithIssuer(issuer string) *Builder
- func (b *Builder) WithRefreshTokenExpiry(d time.Duration) *Builder
- func (b *Builder) WithTokenStore(store TokenStore) *Builder
- func (b *Builder) WithUserAuthorizationHandler(h server.UserAuthorizationHandler) *Builder
- type Client
- type ClientStore
- type OAuthPlugin
- func (p *OAuthPlugin) AddClient(client Client) error
- func (p *OAuthPlugin) Deps() []string
- func (p *OAuthPlugin) GetClientStore() ClientStore
- func (p *OAuthPlugin) GetTokenStore() TokenStore
- func (p *OAuthPlugin) Init(ctx context.Context, r *prefab.Registry) error
- func (p *OAuthPlugin) Name() string
- func (p *OAuthPlugin) ServerOptions() []prefab.ServerOption
- type TokenInfo
- type TokenStore
Constants ¶
const PluginName = "oauth"
PluginName is the identifier for the OAuth plugin.
Variables ¶
var ( ErrInvalidClient = errors.NewC("invalid_client", codes.Unauthenticated) ErrInvalidGrant = errors.NewC("invalid_grant", codes.InvalidArgument) ErrInvalidScope = errors.NewC("invalid_scope", codes.InvalidArgument) ErrAccessDenied = errors.NewC("access_denied", codes.PermissionDenied) ErrPKCERequired = errors.NewC("invalid_request: code_challenge required for public clients", codes.InvalidArgument) ErrPKCEMethodRequired = errors.NewC("invalid_request: code_challenge_method=S256 required for public clients", codes.InvalidArgument) ErrInvalidToken = errors.NewC("invalid_token", codes.Unauthenticated) ErrTokenNotFound = errors.NewC("token_not_found", codes.NotFound) ErrTokenRevoked = errors.NewC("token_revoked", codes.Unauthenticated) )
Standard OAuth2 errors.
Functions ¶
func FormatScopes ¶
FormatScopes formats a slice of scopes into a space-separated string.
func HasAllScopes ¶
HasAllScopes checks if the current context has all of the specified scopes.
func HasAnyScope ¶
HasAnyScope checks if the current context has any of the specified scopes.
func IsOAuthRequest ¶
IsOAuthRequest returns true if the current request is authenticated via OAuth.
func OAuthClientIDFromContext ¶
OAuthClientIDFromContext retrieves the OAuth client ID from the context.
func OAuthScopesFromContext ¶
OAuthScopesFromContext retrieves OAuth scopes from the context.
func ParseScopes ¶
ParseScopes parses a space-separated scope string into a slice.
func WithOAuthClientID ¶
WithOAuthClientID adds the OAuth client ID to the context.
Types ¶
type Builder ¶
type Builder struct {
// contains filtered or unexported fields
}
Builder provides a fluent interface for configuring the OAuth plugin.
func NewBuilder ¶
func NewBuilder() *Builder
NewBuilder creates a new OAuth plugin builder with sensible defaults.
func (*Builder) Build ¶
func (b *Builder) Build() *OAuthPlugin
Build returns the configured OAuth plugin.
func (*Builder) WithAccessTokenExpiry ¶
WithAccessTokenExpiry sets the access token expiration duration.
func (*Builder) WithAuthCodeExpiry ¶
WithAuthCodeExpiry sets the authorization code expiration duration.
func (*Builder) WithClient ¶
WithClient adds a static OAuth client. Panics if the client configuration is invalid (e.g., confidential client with empty secret, redirect URI containing control characters). Misconfigured static clients are programmer errors that should fail loudly at startup rather than at first request.
func (*Builder) WithClientStore ¶
func (b *Builder) WithClientStore(store ClientStore) *Builder
WithClientStore sets a custom client store for persistent/dynamic client management. Use this when you need to store clients in a database or allow users to create clients.
func (*Builder) WithEnforcePKCE ¶
WithEnforcePKCE sets whether PKCE is required for public clients. When true, public clients must provide a code_challenge in authorization requests. If not set, the value is read from config key "oauth.enforcePkce".
func (*Builder) WithIssuer ¶
WithIssuer sets the token issuer.
func (*Builder) WithRefreshTokenExpiry ¶
WithRefreshTokenExpiry sets the refresh token expiration duration.
func (*Builder) WithTokenStore ¶
func (b *Builder) WithTokenStore(store TokenStore) *Builder
WithTokenStore sets a custom token store for persistent token storage. Use this when you need to persist tokens across server restarts or in a distributed environment.
func (*Builder) WithUserAuthorizationHandler ¶
func (b *Builder) WithUserAuthorizationHandler(h server.UserAuthorizationHandler) *Builder
WithUserAuthorizationHandler overrides how the /oauth/authorize endpoint resolves the authenticated user. The default uses auth.IdentityFromContext and conflates authentication with consent: any authenticated user's request is treated as an approval, which is only safe when every registered client is first-party.
For multi-tenant or third-party setups, provide a handler that enforces an explicit consent step. The handler receives the raw request and can:
- Write a redirect to a consent page and return ("", nil) to suppress code issuance for this request while keeping the response valid.
- Verify a consent token (e.g., via prefab.VerifyCSRFToken) and return the user's subject on approval.
- Return an error to produce an OAuth error redirect to the client.
type Client ¶
type Client struct {
// ID is the unique client identifier.
ID string
// Secret is the client secret for confidential clients. Leave empty for public clients.
Secret string
// Name is a human-readable name for the client.
Name string
// RedirectURIs is the list of allowed redirect URIs for authorization code flow.
RedirectURIs []string
// Scopes is the list of allowed scopes for this client.
Scopes []string
// Public indicates if this is a public client (e.g., mobile/SPA apps without a secret).
Public bool
// CreatedBy is the user ID of who created this client (for user-registered clients).
CreatedBy string
// CreatedAt is when the client was registered.
CreatedAt time.Time
}
Client represents an OAuth2 client application.
type ClientStore ¶
type ClientStore interface {
GetClient(ctx context.Context, clientID string) (*Client, error)
CreateClient(ctx context.Context, client *Client) error
UpdateClient(ctx context.Context, client *Client) error
DeleteClient(ctx context.Context, clientID string) error
ListClientsByUser(ctx context.Context, userID string) ([]*Client, error)
}
ClientStore defines the interface for OAuth client storage.
type OAuthPlugin ¶
type OAuthPlugin struct {
// contains filtered or unexported fields
}
OAuthPlugin provides OAuth2 authorization server functionality using go-oauth2.
func (*OAuthPlugin) AddClient ¶
func (p *OAuthPlugin) AddClient(client Client) error
AddClient adds a client dynamically at runtime. Returns an error if the client configuration is invalid or if the store rejects the registration.
func (*OAuthPlugin) Deps ¶
func (p *OAuthPlugin) Deps() []string
Deps returns the plugin dependencies.
func (*OAuthPlugin) GetClientStore ¶
func (p *OAuthPlugin) GetClientStore() ClientStore
GetClientStore returns the client store for external management.
func (*OAuthPlugin) GetTokenStore ¶
func (p *OAuthPlugin) GetTokenStore() TokenStore
GetTokenStore returns the token store for external management.
func (*OAuthPlugin) ServerOptions ¶
func (p *OAuthPlugin) ServerOptions() []prefab.ServerOption
ServerOptions returns the server options for the OAuth plugin.
type TokenInfo ¶
type TokenInfo struct {
ClientID string
UserID string
Scope string
Code string
CodeCreateAt time.Time
CodeExpiresIn time.Duration
CodeChallenge string
CodeChallengeMethod string
Access string
AccessCreateAt time.Time
AccessExpiresIn time.Duration
Refresh string
RefreshCreateAt time.Time
RefreshExpiresIn time.Duration
RedirectURI string
}
TokenInfo represents the data stored for an OAuth token. This is a simplified version of oauth2.TokenInfo for storage purposes.
type TokenStore ¶
type TokenStore interface {
// Create stores a new token. The token may have an access token, refresh token,
// and/or authorization code set. All non-empty values should be indexed for lookup.
Create(ctx context.Context, info TokenInfo) error
// RemoveByCode removes a token by its authorization code.
RemoveByCode(ctx context.Context, code string) error
// RemoveByAccess removes a token by its access token.
RemoveByAccess(ctx context.Context, access string) error
// RemoveByRefresh removes a token by its refresh token.
RemoveByRefresh(ctx context.Context, refresh string) error
// GetByCode retrieves a token by its authorization code.
GetByCode(ctx context.Context, code string) (TokenInfo, error)
// GetByAccess retrieves a token by its access token.
GetByAccess(ctx context.Context, access string) (TokenInfo, error)
// GetByRefresh retrieves a token by its refresh token.
GetByRefresh(ctx context.Context, refresh string) (TokenInfo, error)
}
TokenStore defines the interface for OAuth token storage. Implement this interface to persist tokens in a database or other storage.
func NewMemoryTokenStore ¶
func NewMemoryTokenStore() TokenStore
NewMemoryTokenStore creates a new in-memory token store.