passport

package
v1.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 16, 2026 License: MIT Imports: 21 Imported by: 0

Documentation

Overview

Package passport is an OAuth2 authorization server for Nimbus, modeled on Laravel Passport. It lets your app issue OAuth2 tokens to third-party (and first-party) clients, supporting the authorization_code (with PKCE), client_credentials, and refresh_token grants, plus token introspection and revocation.

app.Use(passport.NewPlugin(db, passport.Config{}))

Then protect resource routes with the access-token middleware:

srv := app.Container.MustMake("passport").(*passport.Server)
api := app.Router.Group("/api", passport.RequireAccessToken(srv))
api.Use(passport.RequireScope("read:profile"))

Layout:

passport.go   – plugin + wiring      config.go   – Config
server.go     – OAuth2 core          routes.go   – authorize/token/introspect/revoke
middleware.go – resource server      models/     – clients, codes, tokens
views/        – consent screen

Index

Constants

View Source
const (
	GrantAuthorizationCode = "authorization_code"
	GrantClientCredentials = "client_credentials"
	GrantRefreshToken      = "refresh_token"
)

Grant type constants (RFC 6749 + PKCE).

Variables

View Source
var (
	ErrInvalidClient    = errors.New("invalid_client")
	ErrInvalidGrant     = errors.New("invalid_grant")
	ErrInvalidScope     = errors.New("invalid_scope")
	ErrUnauthorized     = errors.New("unauthorized_client")
	ErrUnsupportedGrant = errors.New("unsupported_grant_type")
	ErrInvalidRequest   = errors.New("invalid_request")
)

OAuth errors surfaced to callers and mapped to RFC 6749 error codes by routes.go.

Functions

func AccessTokenFrom

func AccessTokenFrom(ctx context.Context) *models.OAuthAccessToken

AccessTokenFrom returns the validated access token from a context, or nil.

func RequireAccessToken

func RequireAccessToken(s *Server) router.Middleware

RequireAccessToken returns middleware that authenticates the request via an OAuth2 Bearer access token and stores the token record on the context. Returns 401 with a WWW-Authenticate header when the token is missing or invalid.

func RequireScope

func RequireScope(scope string) router.Middleware

RequireScope returns middleware that enforces the current access token was granted a scope. Must be chained after RequireAccessToken. Returns 403 otherwise.

func WithAccessToken

func WithAccessToken(ctx context.Context, at *models.OAuthAccessToken) context.Context

WithAccessToken stores the validated access token on a context.

Types

type AuthorizeRequest

type AuthorizeRequest struct {
	Client              *models.OAuthClient
	RedirectURI         string
	Scopes              []string
	State               string
	CodeChallenge       string
	CodeChallengeMethod string
}

AuthorizeRequest captures a validated /oauth/authorize request.

type Config

type Config struct {
	// RoutePrefix is where the OAuth endpoints mount. Default "/oauth".
	RoutePrefix string

	// AccessTokenTTL is how long issued access tokens live. Default 1h.
	AccessTokenTTL time.Duration
	// RefreshTokenTTL is how long refresh tokens live. Default 30 days.
	RefreshTokenTTL time.Duration
	// AuthCodeTTL is how long an authorization code is valid. Default 10m.
	AuthCodeTTL time.Duration

	// ConsentView is the .nimbus template rendered on the consent screen.
	// Default "oauth-authorize" (bundled). It receives: client_name, scopes
	// ([]string), and the raw authorize query params for the approve form.
	ConsentView string

	// AllowPublicClientsWithoutPKCE, when true, lets public clients run the
	// authorization_code grant without a code_challenge. The default (false)
	// enforces PKCE for public clients, matching OAuth 2.1.
	AllowPublicClientsWithoutPKCE bool
}

Config tunes the OAuth2 server. Zero values fall back to sane defaults.

type NewClientResult

type NewClientResult struct {
	PlainSecret string             `json:"secret"`
	Client      models.OAuthClient `json:"client"`
}

NewClientResult carries the plaintext secret (shown once) plus the record.

type Plugin

type Plugin struct {
	nimbus.BasePlugin
	// contains filtered or unexported fields
}

Plugin wires the OAuth2 server into Nimbus.

func NewPlugin

func NewPlugin(db *lucid.DB, cfg Config) *Plugin

NewPlugin builds the Passport plugin over the given database.

func (*Plugin) Boot

func (p *Plugin) Boot(app *nimbus.App) error

func (*Plugin) DefaultConfig

func (p *Plugin) DefaultConfig() map[string]any

func (*Plugin) Migrations

func (p *Plugin) Migrations() []database.Migration

Migrations creates the OAuth tables (clients, codes, access/refresh tokens).

func (*Plugin) Register

func (p *Plugin) Register(app *nimbus.App) error

func (*Plugin) RegisterRoutes

func (p *Plugin) RegisterRoutes(r *router.Router)

RegisterRoutes mounts the OAuth2 endpoints under the configured prefix:

GET  /oauth/authorize   consent screen (user must be logged in)
POST /oauth/authorize   approve/deny → redirect back with ?code=
POST /oauth/token       exchange grant for tokens
POST /oauth/introspect  RFC 7662 token introspection (client-authenticated)
POST /oauth/revoke      RFC 7009 token revocation

func (*Plugin) Server

func (p *Plugin) Server() *Server

Server exposes the underlying OAuth2 server (client creation, validation).

func (*Plugin) ViewsFS

func (p *Plugin) ViewsFS() fs.FS

ViewsFS returns the embedded consent screen for the view engine.

type Server

type Server struct {
	// contains filtered or unexported fields
}

Server is the OAuth2 authorization server. Resolve it from the container ("passport") or hold the plugin's instance.

func NewServer

func NewServer(db *lucid.DB, cfg Config) *Server

NewServer builds an OAuth2 server over the given database.

func (*Server) ClientCredentials

func (s *Server) ClientCredentials(ctx context.Context, clientID, clientSecret, scope string) (*TokenResponse, error)

ClientCredentials runs the client_credentials grant (machine-to-machine).

func (*Server) CreateClient

func (s *Server) CreateClient(ctx context.Context, name, ownerUserID string, redirects, grants, scopes []string, confidential bool) (*NewClientResult, error)

CreateClient registers an OAuth client. For a confidential client a random secret is generated and returned once (stored hashed). Pass confidential=false for public clients (no secret; PKCE required on the auth-code grant).

func (*Server) ExchangeAuthCode

func (s *Server) ExchangeAuthCode(ctx context.Context, clientID, clientSecret, code, redirectURI, codeVerifier string) (*TokenResponse, error)

ExchangeAuthCode runs the authorization_code grant: validates the code, client, redirect, and PKCE verifier, then issues access + refresh tokens.

func (*Server) IssueAuthCode

func (s *Server) IssueAuthCode(ctx context.Context, req *AuthorizeRequest, userID string) (string, error)

IssueAuthCode persists a single-use authorization code for an approved request and returns the plaintext code to redirect back to the client.

func (*Server) Refresh

func (s *Server) Refresh(ctx context.Context, clientID, clientSecret, refreshToken, scope string) (*TokenResponse, error)

Refresh runs the refresh_token grant, rotating the refresh token.

func (*Server) RevokeAccessToken

func (s *Server) RevokeAccessToken(ctx context.Context, plain string) error

RevokeAccessToken revokes a token by its plaintext value (RFC 7009).

func (*Server) ValidateAccessToken

func (s *Server) ValidateAccessToken(ctx context.Context, plain string) (*models.OAuthAccessToken, error)

ValidateAccessToken resolves a plaintext bearer token to a live, non-revoked, non-expired access-token record. Returns ErrInvalidGrant otherwise.

func (*Server) ValidateAuthorize

func (s *Server) ValidateAuthorize(ctx context.Context, clientID, responseType, redirectURI, scope, state, challenge, method string) (*AuthorizeRequest, error)

ValidateAuthorize checks an incoming authorization request: client exists, response_type=code, redirect is allowlisted, scopes are permitted, and PKCE is present when required. It does NOT issue a code (the user must approve first).

type TokenResponse

type TokenResponse struct {
	AccessToken  string `json:"access_token"`
	TokenType    string `json:"token_type"` // always "Bearer"
	ExpiresIn    int    `json:"expires_in"` // seconds
	RefreshToken string `json:"refresh_token,omitempty"`
	Scope        string `json:"scope,omitempty"`
}

TokenResponse is the RFC 6749 token endpoint success body.

Directories

Path Synopsis
Package models holds the persisted Passport (OAuth2 server) tables: clients, authorization codes, access tokens, and refresh tokens.
Package models holds the persisted Passport (OAuth2 server) tables: clients, authorization codes, access tokens, and refresh tokens.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL