oauth

package module
v0.1.10 Latest Latest
Warning

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

Go to latest
Published: Jun 8, 2026 License: MIT Imports: 17 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrOAuthStateInvalid                     = limen.NewLimenError("invalid or expired OAuth state", http.StatusBadRequest, nil)
	ErrMissingStateCookie                    = limen.NewLimenError("missing OAuth state cookie; ensure cookies are enabled", http.StatusBadRequest, nil)
	ErrAccountNotFound                       = limen.NewLimenError("account not found", http.StatusNotFound, nil)
	ErrProviderRequired                      = limen.NewLimenError("provider is required", http.StatusUnprocessableEntity, nil)
	ErrCannotUnlinkOnlyAccount               = limen.NewLimenError("cannot unlink the only account", http.StatusConflict, nil)
	ErrProviderNotFound                      = limen.NewLimenError("oauth provider not found", http.StatusNotFound, nil)
	ErrOAuthProviderMismatch                 = limen.NewLimenError("oauth provider does not match state", http.StatusBadRequest, nil)
	ErrPKCEVerifierNotFound                  = limen.NewLimenError("PKCE verifier not found", http.StatusBadRequest, nil)
	ErrAccountAlreadyLinkedToAnotherUser     = limen.NewLimenError("this provider account is already linked to another user", http.StatusConflict, nil)
	ErrAccountCannotBeLinkedToDifferentEmail = limen.NewLimenError("user cannot be linked to this provider account because the email does not match", http.StatusConflict, nil)
	ErrOAuthEmailNotVerified                 = limen.NewLimenError("provider email is not verified", http.StatusUnauthorized, nil)
	ErrOAuthLocalEmailNotVerified            = limen.NewLimenError("local email must be verified before account linking", http.StatusUnauthorized, nil)
	ErrNoRefreshToken                        = limen.NewLimenError("no refresh token available for this account", http.StatusBadRequest, nil)
)

Functions

func BuildAuthCodeURL

func BuildAuthCodeURL(config *oauth2.Config, state, verifier string, authOpts ...oauth2.AuthCodeOption) string

BuildAuthCodeURL builds the OAuth2 authorization URL using the provider's config. state and verifier are required for CSRF and PKCE; authOpts add provider-specific params (e.g. AccessTypeOffline).

func CallbackParams

func CallbackParams(ctx context.Context) url.Values

CallbackParams retrieves the callback query parameters stored in ctx, or nil.

func ContextWithCallbackParams

func ContextWithCallbackParams(ctx context.Context, params url.Values) context.Context

ContextWithCallbackParams returns a child context carrying the raw callback query parameters. Providers can retrieve them via CallbackParams inside GetUserInfo to access IdP-specific extras (e.g. Apple's first-login user payload).

func ContextWithIDTokenNonce

func ContextWithIDTokenNonce(ctx context.Context, nonce string) context.Context

ContextWithIDTokenNonce returns a child context carrying the expected OIDC nonce.

func DecodeIDTokenClaims

func DecodeIDTokenClaims(idToken string) (map[string]any, error)

DecodeIDTokenClaims decodes the payload segment of a JWT without verification.

NOTE: This does not verify the token, so it is not safe to use for any purpose other than to get the claims from the id_token returned by the provider.

func FetchUserInfoJSON

func FetchUserInfoJSON(ctx context.Context, client *http.Client, providerName, endpointURL, accessToken string, extraHeaders map[string]string) (map[string]any, error)

FetchUserInfoJSON performs a GET request to the given URL with a Bearer token and decodes the JSON response into a map. Shared by REST-based OAuth providers.

func IDTokenNonce

func IDTokenNonce(ctx context.Context) string

IDTokenNonce retrieves the expected OIDC nonce stored in ctx, or an empty string.

func New

func New(opts ...ConfigOption) *oauthPlugin

func VerifyIDTokenClaims

func VerifyIDTokenClaims(ctx context.Context, issuer, clientID, idToken string) (map[string]any, error)

func VerifyIDTokenNonce

func VerifyIDTokenNonce(claims map[string]any, expected string) error

VerifyIDTokenNonce verifies the nonce claim against the expected OAuth state nonce. Apple may return the SHA-256 hex digest of the sent nonce; raw equality is accepted too.

Types

type API

type API interface {
	GetAuthorizationURL(ctx context.Context, providerName string, request *OAuthAuthorizeURLData) (string, string, error)

	ExchangeAuthorizationCodeForTokens(ctx context.Context, provider Provider, stateData map[string]any, code string) (*TokenResponse, error)

	GetUserInfoWithTokens(ctx context.Context, provider Provider, token *TokenResponse) (*limen.OAuthAccountProfile, error)

	HandleOAuthCallback(ctx context.Context, providerName, code, state, cookieNonce string, callbackErr *CallbackError) (*limen.OAuthAccountProfile, map[string]any, error)

	AuthenticateWithProvider(ctx context.Context, providerName, code, state, cookieNonce string, callbackErr *CallbackError) (*limen.AuthenticationResult, map[string]any, error)

	CreateOrLinkAccount(ctx context.Context, info *limen.OAuthAccountProfile) (*limen.AuthenticationResult, error)

	LinkAccountToCurrentUser(ctx context.Context, user *limen.User, info *limen.OAuthAccountProfile) (*limen.AuthenticationResult, error)

	ListAccountsForUser(ctx context.Context, userID any) ([]*limen.Account, error)

	UnlinkAccount(ctx context.Context, user *limen.User, providerName string) error

	GetAccessToken(ctx context.Context, userID any, providerName string) (*ActiveTokens, error)

	RefreshAccessToken(ctx context.Context, userID any, providerName string) (*ActiveTokens, error)
}

API is the public interface for the OAuth plugin. Use the Use function to obtain a type-safe reference from a Limen instance.

func Use

func Use(a *limen.Limen) API

Use returns a type-safe API for the OAuth plugin. Panics if the plugin was not registered in Config.Plugins, making it suitable for method chaining.

type ActiveTokens

type ActiveTokens struct {
	AccessToken          string     `json:"access_token"`
	RefreshToken         string     `json:"refresh_token,omitempty"`
	IDToken              string     `json:"id_token,omitempty"`
	AccessTokenExpiresAt *time.Time `json:"access_token_expires_at,omitempty"`
	Scope                string     `json:"scope,omitempty"`
}

ActiveTokens holds the decrypted OAuth tokens for a user's provider account.

type CallbackError

type CallbackError struct {
	Code        string // required – e.g. "access_denied", "invalid_scope"
	Description string // optional – human-readable explanation
}

CallbackError represents a structured OAuth error returned by the authorization server in the callback query string (RFC 6749 Section 4.1.2.1).

func (*CallbackError) Error

func (e *CallbackError) Error() string

func (*CallbackError) ToLimenError

func (e *CallbackError) ToLimenError() *limen.LimenError

ToLimenError converts the provider callback error into an LimenError that carries the structured OAuth fields in its Details so the handler layer can forward them in redirects or JSON responses.

type ConfigOption

type ConfigOption func(*config)

func WithAllowLinkingDifferentEmails

func WithAllowLinkingDifferentEmails() ConfigOption

WithAllowLinkingDifferentEmails allows linking user with a different email to the one in the OAuth profile.

Be careful with this option as it can lead to account takeover if not used correctly.

func WithCookieName

func WithCookieName(name string) ConfigOption

WithCookieName sets the name of the cookie used to store the OAuth state.

func WithCookieTTL

func WithCookieTTL(ttl time.Duration) ConfigOption

WithCookieTTL sets the TTL of the cookie used to store the OAuth state.

func WithDatabaseState

func WithDatabaseState() ConfigOption

WithDatabaseState uses the database to store the OAuth state tokens.

func WithDecryptTokens

func WithDecryptTokens(decryptTokens func(secret []byte, tokens *OAuthTokens) (*OAuthTokens, error)) ConfigOption

WithDecryptTokens sets the function to decrypt the OAuth tokens. The secret passed to the function is the same as the secret passed to WithSecret.

func WithDisableRedirect

func WithDisableRedirect() ConfigOption

WithDisableRedirect disables the redirect to the redirect URI after the OAuth callback.

func WithDisableTokensEncryption

func WithDisableTokensEncryption() ConfigOption

WithDisableTokensEncryption disables the encryption of OAuth tokens. When enabled, tokens are not encrypted and are stored in plain text.

func WithEncryptTokens

func WithEncryptTokens(encryptTokens func(secret []byte, tokens *OAuthTokens) (*OAuthTokens, error)) ConfigOption

WithEncryptTokens sets the function to encrypt the OAuth tokens. The secret passed to the function is the same as the secret passed to WithSecret.

func WithGetUserInfo

func WithGetUserInfo(getUserInfo func(ctx context.Context, provider string, token *TokenResponse) (*ProviderUserInfo, error)) ConfigOption

WithGetUserInfo sets the function to get the user info from the provider. The function is called with the provider name and token and should return the user info.

func WithMapProfileToUser

func WithMapProfileToUser(mapProfileToUser func(info *limen.OAuthAccountProfile) map[string]any) ConfigOption

WithMapProfileToUser sets the function to map the OAuth profile to a user additional fields.

func WithProviders

func WithProviders(providers ...Provider) ConfigOption

WithProviders registers one or more OAuth providers (e.g. Google, GitHub).

func WithRequireExplicitSignUp

func WithRequireExplicitSignUp() ConfigOption

WithRequireExplicitSignUp disables new users signing in via OAuth and error if the user is not found.

func WithSecret

func WithSecret(key string) ConfigOption

WithSecret sets the 32-byte secret used for encrypting OAuth tokens at rest and stateless state tokens. The key must be exactly 32 bytes (e.g. 32 ASCII characters). If not set, the plugin uses Config.Secret when available.

type IDTokenNonceProvider

type IDTokenNonceProvider interface {
	IDTokenNonceEnabled() bool
}

IDTokenNonceProvider is optional. If a Provider implements it and returns true, the base module sends a nonce authorization parameter and exposes the expected nonce to GetUserInfo for provider-side ID token claim validation.

type IDTokenVerifier

type IDTokenVerifier func(ctx context.Context, idToken string) (map[string]any, error)

func NewIDTokenVerifier

func NewIDTokenVerifier(issuer, clientID string) IDTokenVerifier

type OAuthAuthorizeURLData

type OAuthAuthorizeURLData struct {
	AdditionalData   map[string]any
	RedirectURI      string
	ErrorRedirectURI string
}

type OAuthTokens

type OAuthTokens struct {
	AccessToken  string
	RefreshToken string
	IDToken      string
}

type PKCEEnabledProvider

type PKCEEnabledProvider interface {
	PKCEEnabled() bool
}

PKCEEnabledProvider is optional. If a Provider implements it and PKCEEnabled() returns false, the authorization URL is built without code_challenge and the token exchange is performed without code_verifier (for providers like LinkedIn that do not support PKCE).

type Provider

type Provider interface {
	// Name returns the provider identifier (e.g., "google", "github").
	Name() string
	// OAuth2Config returns the OAuth2 client config and optional auth-code options
	// (e.g. AccessTypeOffline for Google). The base module uses these for
	// BuildAuthCodeURL and ExchangeCode.
	OAuth2Config() (*oauth2.Config, []oauth2.AuthCodeOption)
	// GetUserInfo fetches the user's profile from the provider using the access token.
	GetUserInfo(ctx context.Context, token *TokenResponse) (*ProviderUserInfo, error)
}

Provider is implemented by each OAuth provider plugin (Google, GitHub, etc.). The base module uses OAuth2Config for standard authorization URL and token exchange; GetUserInfo is the only provider-specific call.

type ProviderUserInfo

type ProviderUserInfo struct {
	ID            string
	Email         string
	EmailVerified bool
	Name          string
	AvatarURL     string
	Raw           map[string]any
}

ProviderUserInfo holds the user profile returned by an OAuth provider.

type ResponseMode

type ResponseMode string

ResponseMode represents the OAuth 2.0 response_mode parameter that controls how the authorization server returns result parameters to the client.

const (
	ResponseModeQuery    ResponseMode = "query"
	ResponseModeFormPost ResponseMode = "form_post"
)

type ResponseModeProvider

type ResponseModeProvider interface {
	ResponseMode() ResponseMode
}

ResponseModeProvider is optional. If a Provider implements it and returns a non-default mode, the base module adds the response_mode parameter to the authorization URL and registers a POST callback route to handle form_post responses from the IdP.

type StateStore

type StateStore interface {
	// Generate creates a new state token and a cookie value (nonce for database store,
	// encrypted payload for stateless store).
	Generate(ctx context.Context, data map[string]any) (stateToken string, cookieValue string, err error)

	// Validate verifies the state token and cookie value, ensures the token has not
	// expired, and returns the data map that was passed to Generate.
	Validate(ctx context.Context, stateToken string, cookieValue string) (map[string]any, error)
}

type TokenExchanger

type TokenExchanger interface {
	ExchangeAuthorizationCode(ctx context.Context, code, codeVerifier, redirectURI string) (*TokenResponse, error)
}

TokenExchanger is optional. If a Provider also implements TokenExchanger, the base module uses it for code-for-token exchange instead of ExchangeCode.

type TokenRefresher

type TokenRefresher interface {
	RefreshToken(ctx context.Context, refreshToken string) (*TokenResponse, error)
}

TokenRefresher is optional. If a Provider also implements TokenRefresher, the base module uses it to refresh an access token instead of the standard oauth2 refresh flow.

type TokenResponse

type TokenResponse struct {
	AccessToken    string
	RefreshToken   string
	ExpiresAt      time.Time
	TokenType      string
	Scope          string
	IDToken        string
	AdditionalData map[string]any
}

TokenResponse holds the OAuth2 token exchange response.

func ExchangeCode

func ExchangeCode(ctx context.Context, config *oauth2.Config, code, codeVerifier string) (*TokenResponse, error)

ExchangeCode exchanges an authorization code for tokens using the provider's config. codeVerifier is required when PKCE was used on the authorization URL.

func RefreshToken

func RefreshToken(ctx context.Context, config *oauth2.Config, refreshToken string) (*TokenResponse, error)

RefreshToken uses the standard oauth2.TokenSource to exchange a refresh token for a new access token via the provider's token endpoint.

Jump to

Keyboard shortcuts

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