oauthclient

package
v0.12.0 Latest Latest
Warning

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

Go to latest
Published: Oct 6, 2026 License: MIT Imports: 15 Imported by: 0

Documentation

Overview

Package oauthclient is SystemForge's single sanctioned package for talking to upstream social-login providers (GitHub, Google) and to SystemAuth as an OAuth client. It provides provider configuration, authorization-code exchange, normalized user-profile fetching (including verified-email detection), and CSRF state handling (cookie-bound StateManager and a pluggable server-side StateStore).

The SystemAuth server builds its GitHub/Google login on top of this package; applications should federate to SystemAuth rather than wiring social login themselves.

Index

Constants

View Source
const (
	// ProviderGitHub identifies GitHub.
	ProviderGitHub = "github"
	// ProviderGoogle identifies Google.
	ProviderGoogle = "google"
	// ProviderSystemAuth identifies a SystemAuth server.
	ProviderSystemAuth = "systemauth"
)

Provider names used in User.Provider and StateData.Provider.

View Source
const (
	// DefaultGitHubAPIURL is the GitHub REST API base URL.
	DefaultGitHubAPIURL = "https://api.github.com"
	// DefaultGoogleUserInfoURL is Google's OpenID Connect userinfo endpoint.
	DefaultGoogleUserInfoURL = "https://www.googleapis.com/oauth2/v3/userinfo"
)
View Source
const (
	// StateCookieName is the default name for the OAuth state cookie.
	StateCookieName = "oauth_state"
	// StateCookieMaxAge is the default max age for the state cookie (5 minutes).
	StateCookieMaxAge = 5 * 60
)

Variables

View Source
var ErrInvalidState = errors.New("oauthclient: invalid or expired state")

ErrInvalidState is returned when an OAuth state value is unknown, already used, or expired.

View Source
var ErrUnsupportedProvider = errors.New("oauthclient: unsupported provider")

ErrUnsupportedProvider is returned when a Connector names a provider this package cannot fetch profiles from.

Functions

func GenerateState

func GenerateState() (string, error)

GenerateState generates a cryptographically secure random state string.

func GitHubConfig

func GitHubConfig(cfg ProviderConfig) *oauth2.Config

GitHubConfig creates an OAuth2 config for GitHub.

func GoogleConfig

func GoogleConfig(cfg ProviderConfig) *oauth2.Config

GoogleConfig creates an OAuth2 config for Google.

Types

type Connector added in v0.12.0

type Connector struct {
	// Provider is ProviderGitHub or ProviderGoogle.
	Provider string

	// OAuth2 is the client configuration (endpoints, credentials, scopes).
	OAuth2 *oauth2.Config

	// APIURL is the GitHub API base URL (for ProviderGitHub) or the userinfo
	// endpoint URL (for ProviderGoogle).
	APIURL string

	// HTTPClient, if set, is used for the token exchange and profile calls.
	HTTPClient *http.Client
}

Connector bundles everything needed to run an authorization-code login against one upstream provider: the OAuth2 client config, the profile API location, and the HTTP client used for both. Endpoints are fields so tests (and GitHub Enterprise / alternate Google hosts) can point them elsewhere.

func NewGitHubConnector added in v0.12.0

func NewGitHubConnector(cfg ProviderConfig) *Connector

NewGitHubConnector returns a Connector for github.com.

func NewGoogleConnector added in v0.12.0

func NewGoogleConnector(cfg ProviderConfig) *Connector

NewGoogleConnector returns a Connector for Google.

func (*Connector) AuthCodeURL added in v0.12.0

func (c *Connector) AuthCodeURL(state string, opts ...oauth2.AuthCodeOption) string

AuthCodeURL returns the provider authorization URL for state.

func (*Connector) Exchange added in v0.12.0

func (c *Connector) Exchange(ctx context.Context, code string, opts ...oauth2.AuthCodeOption) (*oauth2.Token, error)

Exchange trades an authorization code for a token.

func (*Connector) FetchUser added in v0.12.0

func (c *Connector) FetchUser(ctx context.Context, token *oauth2.Token) (*User, error)

FetchUser fetches and normalizes the user's profile with token.

type MemoryStateStore added in v0.12.0

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

MemoryStateStore is a concurrency-safe, in-memory StateStore.

func NewMemoryStateStore added in v0.12.0

func NewMemoryStateStore() *MemoryStateStore

NewMemoryStateStore creates an empty in-memory state store.

func (*MemoryStateStore) Put added in v0.12.0

func (s *MemoryStateStore) Put(_ context.Context, state string, data StateData, ttl time.Duration) error

Put implements StateStore. Expired entries are pruned on each call.

func (*MemoryStateStore) Take added in v0.12.0

func (s *MemoryStateStore) Take(_ context.Context, state string) (StateData, error)

Take implements StateStore.

type ProviderConfig

type ProviderConfig struct {
	ClientID     string
	ClientSecret string //nolint:gosec // G117: config field, not a hardcoded secret
	RedirectURL  string
	Scopes       []string
}

ProviderConfig holds OAuth configuration for a provider.

func (ProviderConfig) Enabled

func (c ProviderConfig) Enabled() bool

Enabled returns true if the provider is configured.

type StateData added in v0.12.0

type StateData struct {
	// Provider is the provider the flow was started for.
	Provider string `json:"provider"`

	// RedirectURL is the (already validated) post-login destination.
	RedirectURL string `json:"redirect_url,omitempty"`

	// Nonce is an optional OpenID Connect nonce.
	Nonce string `json:"nonce,omitempty"`

	// PKCEVerifier is the PKCE code verifier for the token exchange.
	PKCEVerifier string `json:"pkce_verifier,omitempty"`
}

StateData is the server-side record associated with an OAuth state value.

type StateManager

type StateManager struct {
	CookieName string
	MaxAge     int
	Secure     bool // Secure flag for cookies (default: true, requires HTTPS)
	SameSite   http.SameSite
}

StateManager handles OAuth state cookie management.

func NewStateManager

func NewStateManager() *StateManager

NewStateManager creates a state manager with secure defaults. Cookies are set with Secure: true, requiring HTTPS. For local development over HTTP, use NewStateManagerInsecure().

func NewStateManagerInsecure

func NewStateManagerInsecure() *StateManager

NewStateManagerInsecure creates a state manager for local development over HTTP. WARNING: Only use this for local development. Never use in production.

func (*StateManager) SetStateCookie

func (m *StateManager) SetStateCookie(w http.ResponseWriter, state string)

SetStateCookie sets the OAuth state cookie.

func (*StateManager) ValidateState

func (m *StateManager) ValidateState(w http.ResponseWriter, r *http.Request, state string) bool

ValidateState validates the OAuth state against the cookie and clears it. Returns true if valid, false otherwise.

type StateStore added in v0.12.0

type StateStore interface {
	// Put stores data under state for ttl.
	Put(ctx context.Context, state string, data StateData, ttl time.Duration) error

	// Take returns and deletes the data for state. It returns ErrInvalidState
	// when the state is unknown or expired.
	Take(ctx context.Context, state string) (StateData, error)
}

StateStore persists OAuth state server-side between the login redirect and the callback. Implementations must make Take single-use.

The in-memory implementation only works for a single server instance; use a shared store (Redis, database) when running more than one replica.

type SystemAuthConfig added in v0.11.0

type SystemAuthConfig struct {
	ProviderConfig
	BaseURL string // SystemAuth server base URL
}

SystemAuthConfig holds SystemAuth OAuth configuration.

func (SystemAuthConfig) AuthorizationURL added in v0.11.0

func (c SystemAuthConfig) AuthorizationURL() string

AuthorizationURL returns the SystemAuth authorization endpoint.

func (SystemAuthConfig) OAuth2Config added in v0.11.0

func (c SystemAuthConfig) OAuth2Config() *oauth2.Config

OAuth2Config creates an OAuth2 config for SystemAuth.

func (SystemAuthConfig) TokenURL added in v0.11.0

func (c SystemAuthConfig) TokenURL() string

TokenURL returns the SystemAuth token endpoint.

func (SystemAuthConfig) UserInfoURL added in v0.11.0

func (c SystemAuthConfig) UserInfoURL() string

UserInfoURL returns the SystemAuth userinfo endpoint.

type User

type User struct {
	// ProviderID is the unique identifier from the OAuth provider.
	ProviderID string `json:"provider_id"`

	// Provider is the name of the OAuth provider (google, github, etc.).
	Provider string `json:"provider"`

	// Email is the user's email address.
	Email string `json:"email"`

	// EmailVerified reports whether the provider asserts that the user
	// controls Email. Only a verified email may be used to link an upstream
	// identity to an existing account.
	EmailVerified bool `json:"email_verified"`

	// Name is the user's display name.
	Name string `json:"name"`

	// AvatarURL is the URL to the user's profile picture.
	AvatarURL string `json:"avatar_url,omitempty"`

	// Username is the user's username (primarily for GitHub).
	Username string `json:"username,omitempty"`

	// AccessToken is the OAuth access token.
	AccessToken string `json:"-"`

	// RefreshToken is the OAuth refresh token (if provided).
	RefreshToken string `json:"-"`

	// TokenExpiry is when the access token expires.
	TokenExpiry time.Time `json:"-"`

	// Raw contains the raw user data from the provider.
	Raw map[string]any `json:"raw,omitempty"`
}

User represents user information from an OAuth provider.

func FetchGitHubUser

func FetchGitHubUser(ctx context.Context, cfg *oauth2.Config, code string) (*User, error)

FetchGitHubUser fetches user info from GitHub using an authorization code.

func FetchGoogleUser

func FetchGoogleUser(ctx context.Context, cfg *oauth2.Config, code string) (*User, error)

FetchGoogleUser fetches user info from Google using an authorization code.

func FetchSystemAuthUser added in v0.11.0

func FetchSystemAuthUser(ctx context.Context, cfg SystemAuthConfig, accessToken string) (*User, error)

FetchSystemAuthUser fetches user info from SystemAuth using an access token.

Jump to

Keyboard shortcuts

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