oauth

package
v1.1.0 Latest Latest
Warning

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

Go to latest
Published: Feb 1, 2026 License: MIT Imports: 40 Imported by: 0

Documentation

Overview

Package oauth provides database migration management for the OAuth plugin.

This file handles parsing and loading migration files from the embedded filesystem, supporting multiple SQL dialects (PostgreSQL, MySQL, SQLite).

Migration Versioning:

  • Version 001: Initial schema (oauth_connections table)
  • Version 002+: Additional migrations (indexes, columns, etc.)

File Naming Convention:

  • Up migrations: 002_add_index.up.sql
  • Down migrations: 002_add_index.down.sql

Package oauth provides OAuth 2.0 / OpenID Connect authentication for Aegis.

This plugin enables "Login with Google", "Login with GitHub", and other OAuth-based authentication flows. It uses the Goth library as the provider implementation while maintaining abstraction for potential alternatives.

OAuth Flow:

  1. User clicks "Login with Google" → GET /auth/oauth/google
  2. Plugin generates CSRF state token and stores it in signed cookie
  3. Plugin redirects to Google's authorization page
  4. User approves → Google redirects to /auth/oauth/google/callback?code=xxx&state=xxx
  5. Plugin validates state token (CSRF protection)
  6. Plugin exchanges authorization code for access token
  7. Plugin fetches user profile from Google
  8. Plugin creates/links Aegis user account and session
  9. User is authenticated with session cookie

Supported Providers (via Goth):

  • google: Google OAuth 2.0
  • github: GitHub OAuth 2.0
  • line: LINE OAuth 2.0 (Japan, Taiwan, Thailand)
  • microsoft: Microsoft Azure AD / Office 365
  • apple: Apple Sign In
  • discord, slack, gitlab, bitbucket, twitter, linkedin, spotify, twitch, amazon
  • generic: Custom OAuth 2.0 / OIDC providers (requires manual configuration)

Multi-Provider Setup: Configure multiple providers to offer users a choice:

cfg := &oauth.Config{
    CallbackURL: "https://example.com/auth",
    Providers: []oauth.ProviderConfig{
        {ProviderID: "google", ProviderType: "google", ClientID: "...", ClientSecret: "..."},
        {ProviderID: "github", ProviderType: "github", ClientID: "...", ClientSecret: "..."},
    },
}
oauthPlugin := oauth.New(cfg, nil)

Security Features:

  • CSRF Protection: State tokens with HMAC signing prevent cross-site request forgery
  • Secure Cookies: HTTPOnly, Secure, SameSite settings via CookieManager
  • State Expiration: OAuth states expire after 15 minutes
  • Token Storage: Access/refresh tokens stored in database (not cookies)

Account Linking: Users can link multiple OAuth providers to a single Aegis account:

  • Same email: Automatically linked on first sign-in
  • Different emails: Manual linking via LinkAccount API
  • Multiple providers: One user can have Google + GitHub + Apple linked

Database Schema:

  • oauth_connections table: Stores provider links (user_id, provider, provider_user_id, tokens)
  • Foreign key to auth.users: Ensures referential integrity

Index

Constants

View Source
const (
	// SchemaLinkAccountRequest is the OpenAPI schema name for account linking.
	// Request Body:
	//   {
	//     "provider": "google"
	//   }
	SchemaLinkAccountRequest = "LinkAccountRequest"
)

Schema names for OpenAPI specification generation.

These constants define the OpenAPI schema names for OAuth request types. They are used in route metadata to generate accurate API documentation.

View Source
const SecretPurposeOAuthState = "aegis:oauth-state"

SecretPurposeOAuthState is the purpose string for deriving OAuth state secrets. Aegis's secret derivation system uses this to generate a unique secret for signing OAuth state cookies, // SecretPurposeOAuthState is the purpose for OAuth state tokens #nosec G101

View Source
const StateCookieName = "_aegis_oauth_state"

StateCookieName is the cookie name used for OAuth state storage. This cookie is separate from the session cookie and is only used during the OAuth flow (created on BeginAuth, validated on callback, then deleted).

Variables

This section is empty.

Functions

func CreateGothProvider

func CreateGothProvider(cfg ProviderConfig, callbackURL string) (goth.Provider, error)

CreateGothProvider creates a goth.Provider from ProviderConfig.

This factory function instantiates the correct Goth provider based on the ProviderType, applying scopes and callback URL. It handles provider-specific initialization quirks (e.g., Apple's JWT client secret).

Supported Providers:

  • google, github, line, microsoft, apple
  • discord, slack, gitlab, bitbucket, twitter
  • linkedin, spotify, twitch, amazon
  • generic (manual endpoint configuration)

Parameters:

  • cfg: Provider configuration with type, credentials, and options
  • callbackURL: OAuth callback URL for this provider

Returns:

  • goth.Provider: Initialized Goth provider
  • error: Unsupported provider type or missing configuration

Example:

cfg := oauth.ProviderConfig{
    ProviderType: "google",
    ClientID:     "...",
    ClientSecret: "...",
    Scopes:       []string{"email", "profile"},
}
provider, _ := oauth.CreateGothProvider(cfg, "https://example.com/auth/oauth/google/callback")

func GetMigrations

func GetMigrations(dialect plugins.Dialect) ([]plugins.Migration, error)

GetMigrations returns all database migrations for the specified SQL dialect.

This function combines the initial schema (version 001) with any additional migrations (version 002+) to produce a complete, ordered list of migrations.

Parameters:

  • dialect: SQL dialect (DialectPostgres, DialectMySQL, DialectSQLite)

Returns:

  • []plugins.Migration: Ordered list of migrations (version ASC)
  • error: File read error or unsupported dialect

func GetSchema

func GetSchema(dialect plugins.Dialect) (*plugins.Schema, error)

GetSchema returns the initial database schema for the OAuth plugin.

This function provides the CREATE TABLE statement for oauth_connections, formatted for the specified SQL dialect. For PostgreSQL, it includes both the auth schema prerequisite and the OAuth schema.

Parameters:

  • dialect: SQL dialect (DialectPostgres or DialectMySQL)

Returns:

  • *plugins.Schema: Schema metadata with SQL and version info
  • error: Unsupported dialect error

func UserToGothUser

func UserToGothUser(oauthUser *User, provider string) goth.User

UserToGothUser converts Aegis User to goth.User.

This helper function transforms Aegis's User struct back into Goth's representation, useful for interacting with Goth's provider APIs.

Parameters:

  • oauthUser: Aegis OAuth user
  • provider: Provider name ("google", "github", etc.)

Returns:

  • goth.User: Goth user model

Types

type Config

type Config struct {
	// Providers configures which OAuth providers to enable.
	// Each provider needs a client ID, client secret from the provider's developer console.
	Providers []ProviderConfig

	// CallbackURL is the base URL for OAuth callbacks (e.g., "https://example.com/auth").
	// The plugin appends "/oauth/:provider/callback" to this base.
	// Example: CallbackURL="https://example.com/auth" → callback at "https://example.com/auth/oauth/google/callback"
	CallbackURL string

	// StateSecret is deprecated - Aegis now derives state secrets from master secret.
	// This field is kept for backward compatibility but is ignored.
	StateSecret []byte
}

Config holds OAuth plugin configuration.

This structure defines all OAuth providers to enable and their settings. Multiple providers can be configured to offer users authentication choices.

Example:

cfg := &oauth.Config{
    CallbackURL: "https://example.com/auth",
    Providers: []oauth.ProviderConfig{
        {
            ProviderID:   "google",
            ProviderType: "google",
            ClientID:     os.Getenv("GOOGLE_CLIENT_ID"),
            ClientSecret: os.Getenv("GOOGLE_CLIENT_SECRET"),
            Scopes:       []string{"email", "profile"},
        },
    },
}

type Connection

type Connection struct {
	// Aegis fields
	ID        string    // Unique connection ID (generated by Aegis)
	UserID    string    // Aegis user ID (foreign key to auth.users)
	CreatedAt time.Time // When the connection was first created
	UpdatedAt time.Time // Last updated (token refresh, profile update)

	// OAuth provider fields
	Provider       string // Provider name ("google", "github", etc.)
	ProviderUserID string // Provider's user ID (Google: "108...", GitHub: "12345")

	// User profile from provider
	Email     string // User's email from provider
	Name      string // User's name from provider
	AvatarURL string // User's avatar URL from provider

	// OAuth tokens
	AccessToken  string    // OAuth access token for API calls
	RefreshToken string    // OAuth refresh token for renewing access
	ExpiresAt    time.Time // When the access token expires

	// Provider-specific data (JSON)
	ProviderData map[string]any // Additional fields from provider
}

Connection represents an OAuth connection stored in the database.

This is the persistent storage model linking an Aegis user to an OAuth provider. Each connection stores the provider's user ID, tokens, and metadata for account linking and token refresh.

Database Table: oauth_connections Primary Key: (provider, provider_user_id) Foreign Key: user_id → auth.users.id

Example Row:

  • ID: "conn_abc123"
  • UserID: "user_xyz789"
  • Provider: "google"
  • ProviderUserID: "108234567890123456789" (Google's user ID)
  • Email: "user@gmail.com"
  • Name: "John Doe"
  • AccessToken: "ya29.a0AfH6SMB..." (Google access token)
  • RefreshToken: "1//0gZ..." (Google refresh token)
  • ExpiresAt: 2024-01-01T13:00:00Z

type DefaultOAuthStore

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

DefaultOAuthStore implements Store using a SQL database backend.

This implementation uses sqlc-generated type-safe queries to manage OAuth connections in PostgreSQL, MySQL, or SQLite. It stores connections in the oauth_connections table with foreign key constraints to auth.users.

Database Table: oauth_connections Columns:

  • id (TEXT PRIMARY KEY): Connection identifier
  • user_id (TEXT NOT NULL): Foreign key to auth.users.id
  • provider (TEXT NOT NULL): Provider name ("google", "github", etc.)
  • provider_user_id (TEXT NOT NULL): Provider's user ID
  • email, name, avatar_url: User profile from provider
  • access_token, refresh_token: OAuth tokens
  • expires_at: Token expiration timestamp
  • provider_data (TEXT): JSON-encoded provider-specific fields
  • created_at, updated_at: Timestamps

Unique Constraint: (provider, provider_user_id) Foreign Key: user_id → auth.users.id ON DELETE CASCADE

func NewDefaultOAuthStore

func NewDefaultOAuthStore(db *sql.DB) *DefaultOAuthStore

NewDefaultOAuthStore creates a new DefaultOAuthStore backed by a SQL database.

The provided database connection must be configured for the correct dialect and have the oauth_connections table schema applied.

Parameters:

  • db: Active SQL database connection

Returns:

  • *DefaultOAuthStore: Configured store ready for use

func (*DefaultOAuthStore) CreateConnection

func (s *DefaultOAuthStore) CreateConnection(ctx context.Context, conn Connection) (*Connection, error)

CreateConnection creates a new OAuth connection

func (*DefaultOAuthStore) DeleteConnection

func (s *DefaultOAuthStore) DeleteConnection(ctx context.Context, provider, userID string) error

DeleteConnection deletes an OAuth connection by provider and user ID

func (*DefaultOAuthStore) GetConnectionByProviderUserID

func (s *DefaultOAuthStore) GetConnectionByProviderUserID(ctx context.Context, provider, providerUserID string) (*Connection, error)

GetConnectionByProviderUserID retrieves a connection by provider and provider user ID

func (*DefaultOAuthStore) GetConnectionsByUserID

func (s *DefaultOAuthStore) GetConnectionsByUserID(ctx context.Context, userID string) ([]Connection, error)

GetConnectionsByUserID retrieves all connections for a user

func (*DefaultOAuthStore) UpdateConnection

func (s *DefaultOAuthStore) UpdateConnection(ctx context.Context, conn Connection) error

UpdateConnection updates an OAuth connection

type GothAdapter

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

GothAdapter adapts goth.Provider to Aegis's Provider interface.

This adapter makes Goth the default/recommended OAuth provider implementation while keeping it technically optional through abstraction. If you want to use a different OAuth library, you can implement the Provider interface without Goth.

Goth Benefits:

  • 50+ pre-configured OAuth providers (Google, GitHub, Apple, etc.)
  • Battle-tested OAuth 2.0 / OIDC implementation
  • Active maintenance and security updates
  • Provider-specific quirks handled (Apple's JWT client secret, etc.)

Abstraction Benefits:

  • Aegis core doesn't depend on Goth directly
  • Easier testing with mock providers
  • Future flexibility if Goth is discontinued

func NewGothAdapter

func NewGothAdapter(provider goth.Provider) *GothAdapter

NewGothAdapter creates a new Goth adapter wrapping a Goth provider.

This function wraps any Goth provider to work with Aegis's OAuth plugin. Most users won't call this directly - the plugin creates adapters automatically from ProviderConfig using CreateGothProvider.

Parameters:

  • provider: Goth provider instance (google.New, github.New, etc.)

Returns:

  • *GothAdapter: Adapter implementing Provider interface

Example:

googleProvider := google.New(clientID, clientSecret, callbackURL)
adapter := oauth.NewGothAdapter(googleProvider)

func (*GothAdapter) Exchange

func (g *GothAdapter) Exchange(_ string) (*User, error)

Exchange exchanges authorization code for user information.

Note: This is a simplified interface. In practice, Aegis uses the full gothic.CompleteUserAuth flow which handles the complete OAuth callback processing (code exchange, token retrieval, user info fetch).

This method is currently not used - instead, the plugin uses Goth's session-based flow directly for more flexibility.

func (*GothAdapter) GetAuthURL

func (g *GothAdapter) GetAuthURL(state string) (string, error)

GetAuthURL returns the provider's authorization URL with CSRF state.

This method starts the OAuth session and returns the URL to redirect the user to for authorization (e.g., https://accounts.google.com/o/oauth2/auth).

Parameters:

  • state: CSRF state token (random string for security)

Returns:

  • string: Authorization URL to redirect user to
  • error: OAuth session creation error

func (*GothAdapter) Name

func (g *GothAdapter) Name() string

Name returns the provider identifier (e.g., "google", "github").

type Handlers

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

Handlers provides HTTP endpoint handlers for OAuth authentication.

All handlers have been made private (lowercase) to encourage programmatic use of the underlying Plugin methods. This struct serves as a mounting point for the router.

func NewHandlers

func NewHandlers(plugin *Plugin) *Handlers

NewHandlers creates OAuth plugin HTTP handlers.

type LinkAccountRequest

type LinkAccountRequest struct {
	Provider string `json:"provider"`
}

LinkAccountRequest represents a request to link an OAuth account.

type Plugin

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

Plugin provides OAuth 2.0 authentication integration for Aegis.

This plugin manages multiple OAuth providers simultaneously, allowing users to authenticate with Google, GitHub, Apple, and other services. It integrates with Aegis's user and session management to create unified accounts.

Components:

  • providerConfigs: Plugin configuration for each provider (client ID, secret, scopes)
  • gothProviders: Goth provider instances for OAuth protocol handling
  • stateStore: CSRF protection via signed cookies (state parameter)
  • store: Database persistence for OAuth connections
  • sessionService: Creates Aegis sessions after successful OAuth

Thread Safety: Plugin is safe for concurrent use after initialization (Init called).

func New

func New(cfg *Config, store Store, dialect ...plugins.Dialect) *Plugin

New creates a new OAuth plugin with configured providers.

This function initializes the plugin with provider configurations and creates Goth provider instances for each configured provider. Providers that fail to initialize are logged but don't prevent other providers from working.

Provider Configuration: Each provider needs:

  • ProviderID: Unique identifier (used in URLs like /oauth/google)
  • ProviderType: Provider implementation type ("google", "github", etc.)
  • ClientID: OAuth client ID from provider's developer console
  • ClientSecret: OAuth client secret from provider's developer console

Parameters:

  • cfg: Plugin configuration with providers and callback URL
  • store: OAuth connection storage (nil = use DefaultOAuthStore)
  • dialect: Database dialect (optional, defaults to PostgreSQL)

Returns:

  • *Plugin: Initialized plugin ready for Init() call

Example:

cfg := &oauth.Config{
    CallbackURL: "https://example.com/auth",
    Providers: []oauth.ProviderConfig{
        {ProviderID: "google", ProviderType: "google", ClientID: "...", ClientSecret: "..."},
        {ProviderID: "github", ProviderType: "github", ClientID: "...", ClientSecret: "..."},
    },
}
plugin := oauth.New(cfg, nil, plugins.DialectPostgres)

func (*Plugin) BeginAuth

func (p *Plugin) BeginAuth(w http.ResponseWriter, r *http.Request, providerName string) error

BeginAuth starts the OAuth authentication flow with CSRF protection.

This method initiates the OAuth flow by:

  1. Generating a cryptographically secure CSRF state token
  2. Starting the OAuth session with the provider
  3. Obtaining the provider's authorization URL
  4. Storing state and session data in a signed cookie
  5. Redirecting the user to the provider's authorization page

OAuth Flow (Step 1-3):

  1. User → GET /auth/oauth/google
  2. Plugin → Generate state="abc123", store in cookie
  3. Plugin → Redirect to https://accounts.google.com/authorize?state=abc123&...

State Cookie: The state cookie contains:

  • CSRF state token (random 32 bytes, base64-encoded)
  • Provider name ("google", "github", etc.)
  • Marshaled OAuth session data (for completing the flow)
  • HMAC signature (prevents tampering)
  • Expiration: 15 minutes (short-lived for security)

Parameters:

  • w: HTTP response writer for setting cookies and redirecting
  • r: HTTP request (currently unused)
  • providerName: Provider identifier ("google", "github", etc.)

Returns:

  • error: Provider not found, state generation failed, or redirect failed

Security:

  • State token is cryptographically random (32 bytes from crypto/rand)
  • State cookie is HMAC-signed to prevent tampering
  • Cookie uses Secure, HTTPOnly, SameSite settings from SessionConfig

func (*Plugin) CompleteAuth

func (p *Plugin) CompleteAuth(ctx context.Context, w http.ResponseWriter, r *http.Request) (*User, *auth.Session, error)

CompleteAuth completes the OAuth authentication flow after provider callback.

This method handles the OAuth callback by:

  1. Validating the CSRF state token from the callback
  2. Exchanging the authorization code for an access token
  3. Fetching the user's profile from the provider
  4. Creating or linking an Aegis user account
  5. Creating an Aegis session for the authenticated user

OAuth Flow (Step 4-9):

  1. Provider → Redirect to /auth/oauth/google/callback?code=xyz&state=abc123
  2. Plugin → Validate state=abc123 matches cookie
  3. Plugin → Exchange code=xyz for access token
  4. Plugin → Fetch user profile from provider
  5. Plugin → Create/link user account in Aegis
  6. Plugin → Create session and set cookie

User Account Matching:

  • Existing OAuth connection: Retrieve linked user
  • New OAuth connection with known email: Link to existing user
  • New OAuth connection with unknown email: Create new user
  • OAuth without email: Create user without email (uses provider name)

Parameters:

  • ctx: Request context for database operations
  • w: HTTP response writer for clearing state cookie
  • r: HTTP request with OAuth callback parameters (code, state)

Returns:

  • *User: Authenticated user with OAuth data
  • *auth.Session: New Aegis session for the user
  • error: State validation, token exchange, or user creation error

Security:

  • State validation prevents CSRF attacks
  • State cookie is cleared after validation (one-time use)
  • Access tokens stored in database (not cookies)

func (*Plugin) Dependencies

func (p *Plugin) Dependencies() []plugins.Dependency

Dependencies returns external package dependencies

func (*Plugin) Description

func (p *Plugin) Description() string

Description returns a human-readable description

func (*Plugin) GetMigrations

func (p *Plugin) GetMigrations() []plugins.Migration

GetMigrations returns the plugin migrations

func (*Plugin) GetSchemas

func (p *Plugin) GetSchemas() []plugins.Schema

GetSchemas returns all schemas for all supported dialects

func (*Plugin) GetStateStore

func (p *Plugin) GetStateStore() *StateStore

GetStateStore returns the OAuth state store

func (*Plugin) GetUserConnections

func (p *Plugin) GetUserConnections(ctx context.Context, userID string) ([]*Connection, error)

GetUserConnections retrieves all OAuth provider connections for a user.

This method returns all linked OAuth providers, including access tokens, refresh tokens, and provider-specific data. Useful for displaying linked accounts in user settings or managing provider connections.

Parameters:

  • ctx: Request context
  • userID: Aegis user ID

Returns:

  • []*Connection: List of OAuth connections (may be empty)
  • error: Database query error

Example:

connections, _ := plugin.GetUserConnections(ctx, user.ID)
for _, conn := range connections {
    fmt.Printf("Linked: %s (%s)\n", conn.Provider, conn.Email)
}

func (*Plugin) Init

func (p *Plugin) Init(_ context.Context, a plugins.Aegis) error

Init initializes the OAuth plugin with Aegis services.

This method is called during Aegis startup to inject dependencies and set up the state store. It retrieves services from the Aegis interface and derives the OAuth state secret from the master secret.

Initialization Steps:

  1. Get user, session, and account services from Aegis
  2. Initialize OAuth store if not provided
  3. Derive state secret from master secret ("aegis:oauth-state" purpose)
  4. Create StateStore with derived secret for CSRF protection

Parameters:

  • ctx: Initialization context (currently unused)
  • a: Aegis interface providing services and configuration

Returns:

  • error: Initialization error (currently always nil)

func (*Plugin) LinkAccount

func (p *Plugin) LinkAccount(ctx context.Context, userID string, oauthUser *User, provider string) error

LinkAccount links an OAuth provider to an existing authenticated user account.

This method allows users to add additional OAuth providers to their account. For example, a user who signed up with email/password can later link their Google account for easier login.

Use Cases:

  • Link Google to existing email/password account
  • Link multiple providers to one account (Google + GitHub + Apple)
  • Re-link provider after unlinking

Parameters:

  • ctx: Request context
  • userID: Aegis user ID to link provider to
  • oauthUser: OAuth user data from provider
  • provider: Provider name ("google", "github", etc.)

Returns:

  • error: Database error or duplicate connection error

Example:

// User already authenticated via session
user, _ := core.GetUser(r.Context())
err := plugin.LinkAccount(ctx, user.ID, oauthUser, "google")

func (*Plugin) MountRoutes

func (p *Plugin) MountRoutes(router router.Router, prefix string)

MountRoutes registers HTTP routes for the OAuth plugin

func (*Plugin) Name

func (p *Plugin) Name() string

Name returns the plugin identifier

func (*Plugin) ProvidesAuthMethods

func (p *Plugin) ProvidesAuthMethods() []string

ProvidesAuthMethods returns authentication methods provided

func (*Plugin) RequiresTables

func (p *Plugin) RequiresTables() []string

RequiresTables returns core tables this plugin depends on

func (*Plugin) UnlinkAccount

func (p *Plugin) UnlinkAccount(ctx context.Context, userID, provider string) error

UnlinkAccount removes an OAuth provider link from a user account.

This method allows users to disconnect OAuth providers from their account. The user's Aegis account remains active, but they can no longer sign in using the unlinked provider.

Safety: This method does NOT check if the user has other authentication methods. You should verify the user has email/password or other OAuth providers before allowing unlinking to prevent account lockout.

Parameters:

  • ctx: Request context
  • userID: Aegis user ID
  • provider: Provider name to unlink ("google", "github", etc.)

Returns:

  • error: Database error or connection not found

Example:

// Unlink Google from user's account
err := plugin.UnlinkAccount(ctx, user.ID, "google")

func (*Plugin) Version

func (p *Plugin) Version() string

Version returns the plugin version

type ProviderConfig

type ProviderConfig struct {
	// Identity
	ProviderID   string // Unique ID (e.g., "google", "github", "line-jp")
	ProviderType string // Provider type (e.g., "google", "github", "generic")

	// OAuth Credentials
	ClientID     string // OAuth client ID from provider's developer console
	ClientSecret string // OAuth client secret from provider's developer console

	// OAuth Endpoints (for generic providers)
	AuthURL     string // Authorization endpoint
	TokenURL    string // Token endpoint
	UserInfoURL string // User info endpoint

	// Discovery (alternative to manual endpoints)
	DiscoveryURL string // OIDC discovery URL

	// OAuth Options
	Scopes      []string // OAuth scopes (e.g., ["email", "profile"])
	RedirectURI string   // Custom redirect URI (optional)

	// Advanced Options
	PKCE         bool   // Enable PKCE (recommended for mobile apps)
	ResponseType string // OAuth response type (default: "code")
	ResponseMode string // Response mode (query/form_post)
	Prompt       string // Auth prompt (login/consent/etc)
	AccessType   string // Access type (offline for refresh tokens)

	// User Sign Up Control
	DisableImplicitSignUp bool // Require explicit sign-up
	DisableSignUp         bool // Disable sign-up entirely
	OverrideUserInfo      bool // Update user info on each sign-in

	// Custom Functions (optional)
	GetUserInfo func(*Tokens) (*User, error)        // Custom user info fetcher
	MapProfile  func(map[string]any) (*User, error) // Profile mapper
}

ProviderConfig defines configuration for a single OAuth provider.

This struct configures how Aegis integrates with an OAuth 2.0 or OpenID Connect provider. It supports both pre-built providers (Google, GitHub) and generic OAuth 2.0 providers with manual endpoint configuration.

Pre-Built Providers: For well-known providers, only set ProviderType, ClientID, and ClientSecret:

{ProviderID: "google", ProviderType: "google", ClientID: "...", ClientSecret: "..."}

Generic Providers: For custom OAuth providers, set endpoints manually or use DiscoveryURL:

{ProviderID: "custom", ProviderType: "generic", ClientID: "...", ClientSecret: "...",
 AuthURL: "https://provider.com/oauth/authorize",
 TokenURL: "https://provider.com/oauth/token",
 UserInfoURL: "https://provider.com/oauth/userinfo"}

func Apple

func Apple(clientID, clientSecret string, opts ...ProviderOption) ProviderConfig

Apple creates an Apple Sign In provider configuration.

Apple requires special setup:

  • Client Secret: Not a simple string, but a JWT signed with your private key
  • Team ID: Your Apple Developer Team ID

Default Scopes: ["name", "email"] Discovery: https://appleid.apple.com/.well-known/openid-configuration

Note: Apple's "client secret" is actually a JWT that you must generate and sign with your private key. See Apple's documentation for details.

Parameters:

  • clientID: Apple Service ID
  • clientSecret: JWT signed with your private key
  • teamID: Apple Developer Team ID (currently unused)
  • opts: Optional customization

Returns:

  • ProviderConfig: Apple provider configuration

func Bitbucket

func Bitbucket(clientID, clientSecret string, opts ...ProviderOption) ProviderConfig

Bitbucket creates a Bitbucket OAuth provider configuration.

Default Scopes: ["account", "email"]

func Discord

func Discord(clientID, clientSecret string, opts ...ProviderOption) ProviderConfig

Discord creates a Discord OAuth provider configuration.

Default Scopes: ["identify", "email"]

Parameters:

  • clientID: Discord Application client ID
  • clientSecret: Discord Application client secret
  • opts: Optional customization

func Generic

func Generic(providerID, clientID, clientSecret string, opts ...ProviderOption) ProviderConfig

Generic creates a custom OAuth provider configuration.

Use this for OAuth providers not included in the pre-configured helpers. You must provide either:

  • Discovery URL (OIDC providers): Automatic endpoint discovery
  • Manual endpoints: AuthURL, TokenURL, UserInfoURL

Parameters:

  • providerID: Unique provider identifier (used in URLs)
  • clientID: OAuth client ID from provider
  • clientSecret: OAuth client secret from provider
  • opts: Required configuration (scopes, endpoints, etc.)

Returns:

  • ProviderConfig: Generic provider configuration

Example (OIDC Discovery):

custom := oauth.Generic("keycloak", clientID, clientSecret,
    oauth.WithDiscoveryURL("https://auth.example.com/realms/master/.well-known/openid-configuration"),
    oauth.WithScopes("openid", "email", "profile"),
)

Example (Manual Endpoints):

custom := oauth.Generic("custom", clientID, clientSecret,
    oauth.WithScopes("email"),
)
custom.AuthURL = "https://provider.com/oauth/authorize"
custom.TokenURL = "https://provider.com/oauth/token"
custom.UserInfoURL = "https://provider.com/oauth/userinfo"

func GitHub

func GitHub(clientID, clientSecret string, opts ...ProviderOption) ProviderConfig

GitHub creates a GitHub OAuth provider configuration.

Default Scopes: ["user:email"] No discovery URL (GitHub uses fixed endpoints)

Parameters:

  • clientID: GitHub OAuth App client ID
  • clientSecret: GitHub OAuth App client secret
  • opts: Optional customization

Returns:

  • ProviderConfig: GitHub provider configuration

func GitLab

func GitLab(clientID, clientSecret string, opts ...ProviderOption) ProviderConfig

GitLab creates a GitLab OAuth provider configuration.

Default Scopes: ["read_user", "openid", "profile", "email"]

Supports both GitLab.com and self-hosted instances.

func Google

func Google(clientID, clientSecret string, opts ...ProviderOption) ProviderConfig

Google creates a Google OAuth provider configuration.

Default Scopes: ["openid", "email", "profile"] Discovery: https://accounts.google.com/.well-known/openid-configuration

Parameters:

  • clientID: Google OAuth client ID (from Google Cloud Console)
  • clientSecret: Google OAuth client secret
  • opts: Optional customization (scopes, prompt, etc.)

Returns:

  • ProviderConfig: Google provider configuration

Example:

googleCfg := oauth.Google("123456.apps.googleusercontent.com", "secret",
    oauth.WithScopes("email", "profile", "calendar.readonly"),
    oauth.WithAccessType("offline"), // Request refresh token
    oauth.WithPrompt("consent"),      // Force consent to get refresh token
)

func LINE

func LINE(clientID, clientSecret string, opts ...ProviderOption) ProviderConfig

LINE creates a LINE OAuth provider configuration.

LINE supports multiple channels for different countries:

  • Japan: Regular LINE Login
  • Thailand, Taiwan, Indonesia: Country-specific configurations

Default Scopes: ["profile", "openid", "email"] Discovery: https://access.line.me/.well-known/openid-configuration

For multiple LINE channels:

lineJP := oauth.LINE(clientID_JP, clientSecret_JP,
    oauth.WithProviderID("line-jp"),
)
lineTW := oauth.LINE(clientID_TW, clientSecret_TW,
    oauth.WithProviderID("line-tw"),
)

Parameters:

  • clientID: LINE Channel ID
  • clientSecret: LINE Channel Secret
  • opts: Optional customization

Returns:

  • ProviderConfig: LINE provider configuration

func LinkedIn

func LinkedIn(clientID, clientSecret string, opts ...ProviderOption) ProviderConfig

LinkedIn creates a LinkedIn OAuth provider configuration.

Default Scopes: ["r_liteprofile", "r_emailaddress"]

Note: LinkedIn's API and scopes change frequently. Verify current scopes in LinkedIn's docs.

func Microsoft

func Microsoft(clientID, clientSecret, tenantID string, opts ...ProviderOption) ProviderConfig

Microsoft creates a Microsoft/Azure AD OAuth provider configuration.

Default Scopes: ["openid", "email", "profile"] Discovery: Uses tenant-specific discovery URL

Parameters:

  • clientID: Azure AD App client ID
  • clientSecret: Azure AD App client secret
  • tenantID: Azure AD tenant ID (or "common" for multi-tenant)
  • opts: Optional customization

Returns:

  • ProviderConfig: Microsoft provider configuration

func Slack

func Slack(clientID, clientSecret string, opts ...ProviderOption) ProviderConfig

Slack creates a Slack OAuth provider configuration.

Default Scopes: ["openid", "profile", "email"] Discovery: https://slack.com/.well-known/openid-configuration

func Spotify

func Spotify(clientID, clientSecret string, opts ...ProviderOption) ProviderConfig

Spotify creates a Spotify OAuth provider configuration.

Default Scopes: ["user-read-email", "user-read-private"]

func Twitch

func Twitch(clientID, clientSecret string, opts ...ProviderOption) ProviderConfig

Twitch creates a Twitch OAuth provider configuration.

Default Scopes: ["user:read:email"] Discovery: https://id.twitch.tv/oauth2/.well-known/openid-configuration

func Twitter

func Twitter(clientID, clientSecret string, opts ...ProviderOption) ProviderConfig

Twitter (X) creates a Twitter/X OAuth provider configuration.

Default Scopes: ["tweet.read", "users.read"]

Note: Twitter's OAuth implementation has changed over time. This uses OAuth 2.0.

type ProviderOption

type ProviderOption func(*ProviderConfig)

ProviderOption is a functional option for customizing provider configuration.

This pattern allows flexible provider configuration with sensible defaults. Options can be chained to customize scopes, PKCE, sign-up behavior, etc.

Example:

cfg := oauth.Google(clientID, clientSecret,
    oauth.WithScopes("email", "profile", "calendar"),
    oauth.WithPKCE(),
    oauth.WithDisableImplicitSignUp(),
)

func WithAccessType

func WithAccessType(accessType string) ProviderOption

WithAccessType sets the access type (e.g., "offline" for refresh tokens).

Setting access_type="offline" requests a refresh token from the provider, allowing token renewal without re-authentication. This is provider-specific:

  • Google: access_type=offline
  • Microsoft: access_type=offline (or prompt=consent)

Example:

oauth.Google(clientID, clientSecret,
    oauth.WithAccessType("offline"), // Request refresh token
    oauth.WithPrompt("consent"),     // Force consent to get refresh token
)

func WithDisableImplicitSignUp

func WithDisableImplicitSignUp() ProviderOption

WithDisableImplicitSignUp disables automatic sign-up for new OAuth users.

When enabled, users must be explicitly invited or pre-created before they can sign in via OAuth. Useful for enterprise applications with controlled user provisioning.

Behavior:

  • Existing user + OAuth: Link OAuth to existing account (allowed)
  • New OAuth user: Return error "Sign-up not allowed" (blocked)

Example:

oauth.Google(clientID, clientSecret,
    oauth.WithDisableImplicitSignUp(), // Require pre-existing accounts
)

func WithDisableSignUp

func WithDisableSignUp() ProviderOption

WithDisableSignUp disables sign-up entirely (only existing users can sign in).

This is stricter than WithDisableImplicitSignUp - it prevents both new user creation and OAuth linking to existing accounts.

Behavior:

  • Existing user with OAuth already linked: Sign-in allowed
  • Existing user without OAuth: Linking blocked
  • New user: Sign-up blocked

Use Case: Read-only OAuth for authentication of pre-provisioned users only.

func WithDiscoveryURL

func WithDiscoveryURL(url string) ProviderOption

WithDiscoveryURL sets the OIDC discovery URL for automatic endpoint configuration.

For OpenID Connect providers, the discovery URL provides all OAuth endpoints (authorization, token, userinfo, JWKS) automatically via a JSON document.

Example:

oauth.Generic("custom", clientID, clientSecret,
    oauth.WithDiscoveryURL("https://auth.example.com/.well-known/openid-configuration"),
)

func WithOverrideUserInfo

func WithOverrideUserInfo() ProviderOption

WithOverrideUserInfo enables updating user info on each sign-in.

By default, user profile data (name, email, avatar) is only saved on first sign-up. Enabling this option updates the user profile every time they sign in via OAuth, keeping data synchronized with the provider.

Use Cases:

  • Keep user names/avatars up-to-date from provider
  • Sync email changes from provider
  • Corporate directory synchronization

Caution:

  • May overwrite user-edited profile data
  • Consider allowing users to opt out of sync

func WithPKCE

func WithPKCE() ProviderOption

WithPKCE enables PKCE (Proof Key for Code Exchange) for enhanced security.

PKCE protects against authorization code interception attacks, especially important for mobile apps and public clients that can't securely store secrets.

Recommended for:

  • Mobile apps (iOS, Android)
  • Single-page applications (SPAs)
  • Any public OAuth client

func WithProfileMapper

func WithProfileMapper(fn func(map[string]any) (*User, error)) ProviderOption

WithProfileMapper sets a custom profile mapper function.

Use this to transform provider-specific profile data into Aegis User format. Useful for extracting custom fields or handling non-standard profile structures.

Example:

mapProfile := func(profile map[string]any) (*oauth.User, error) {
    return &oauth.User{
        User: auth.User{
            ID:     profile["sub"].(string),
            Email:  profile["email"].(string),
            Name:   profile["display_name"].(string),
            Avatar: profile["picture_url"].(string),
        },
        ProviderData: profile,
    }, nil
}

oauth.Generic("custom", clientID, clientSecret,
    oauth.WithProfileMapper(mapProfile),
)

func WithPrompt

func WithPrompt(prompt string) ProviderOption

WithPrompt sets the OAuth prompt parameter.

The prompt parameter controls how the provider asks for user consent:

  • "none": No UI shown (silent auth, may fail if interaction required)
  • "login": Always show login screen (even if logged in)
  • "consent": Always show consent screen
  • "select_account": Show account picker

Example:

oauth.Google(clientID, clientSecret,
    oauth.WithPrompt("select_account"), // Always show account picker
)

func WithProviderID

func WithProviderID(id string) ProviderOption

WithProviderID sets a custom provider ID.

Useful for having multiple instances of the same provider with different configurations (e.g., LINE for Japan vs Taiwan, Google for different tenants).

Example:

// LINE for Japan
lineJP := oauth.LINE(clientID_JP, clientSecret_JP,
    oauth.WithProviderID("line-jp"),
)

// LINE for Taiwan
lineTW := oauth.LINE(clientID_TW, clientSecret_TW,
    oauth.WithProviderID("line-tw"),
)

func WithRedirectURI

func WithRedirectURI(uri string) ProviderOption

WithRedirectURI sets a custom redirect URI for the provider.

By default, the plugin constructs redirect URIs as:

{CallbackURL}/oauth/{provider}/callback

Use this to override with a provider-specific redirect URI, for example if you've registered a different callback URL in the provider's console.

Example:

oauth.Google(clientID, clientSecret,
    oauth.WithRedirectURI("https://example.com/custom/google/callback"),
)

func WithScopes

func WithScopes(scopes ...string) ProviderOption

WithScopes sets custom OAuth scopes for the provider.

Scopes determine what user data the provider will share. Each provider has different scope names and defaults.

Example:

oauth.Google(clientID, clientSecret,
    oauth.WithScopes("email", "profile", "calendar.readonly"),
)

func WithUserInfoFetcher

func WithUserInfoFetcher(fn func(*Tokens) (*User, error)) ProviderOption

WithUserInfoFetcher sets a custom user info fetcher function.

Use this to customize how user data is retrieved from the provider, for example to call additional API endpoints or parse non-standard responses.

Example:

fetchUser := func(tokens *oauth.Tokens) (*oauth.User, error) {
    // Call custom API with access token
    resp, _ := http.Get("https://api.example.com/user?access_token=" + tokens.AccessToken)
    // Parse custom response format
    var data map[string]any
    json.NewDecoder(resp.Body).Decode(&data)
    return &oauth.User{...}, nil
}

oauth.Generic("custom", clientID, clientSecret,
    oauth.WithUserInfoFetcher(fetchUser),
)

type StateData

type StateData struct {
	State       string // CSRF state token (32 random bytes, base64)
	Provider    string // OAuth provider name ("google", "github", etc.)
	SessionData string // Marshaled goth.Session (provider-specific OAuth state)
}

StateData holds the OAuth state data stored during the OAuth flow.

This data is serialized, compressed, signed, and stored in a cookie during BeginAuth, then retrieved and validated during the callback.

Cookie Format (with signature):

<hmac-signature>.<base64(state|provider|base64(gzip(sessionData)))>

Example:

"a8f3d..." (HMAC) + "." + "YWJjMTIzfGdvb2dsZXxINHNJQUFBLi4u" (payload)

type StateStore

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

StateStore manages OAuth state cookies for CSRF protection during OAuth flows.

OAuth CSRF Attack Without State:

  1. Attacker initiates OAuth flow → gets callback URL with auth code
  2. Attacker tricks victim into visiting callback URL
  3. Victim's browser exchanges code → victim's account linked to attacker's provider
  4. Attacker can now access victim's account via OAuth

CSRF Protection With State:

  1. Plugin generates random state token before redirect
  2. State stored in signed cookie (attacker can't forge)
  3. Provider includes state in callback URL
  4. Plugin validates callback state matches cookie
  5. If mismatch → reject (CSRF attempt)

State Cookie Contents:

  • CSRF state token (32 random bytes, base64-encoded)
  • Provider name ("google", "github", etc.)
  • Marshaled OAuth session (for resuming flow)
  • HMAC signature (prevents tampering)

Security Features:

  • HMAC-SHA256 signing with derived secret (prevents cookie tampering)
  • Gzip compression (session data can be large)
  • Short expiration (15 minutes default)
  • HTTPOnly, Secure, SameSite settings from CookieManager

Integration: This store integrates with Aegis's core CookieManager for consistent cookie settings (domain, secure flag, SameSite policy) across all cookies.

func NewStateStore

func NewStateStore(cfg *StateStoreConfig) *StateStore

NewStateStore creates a new StateStore for managing OAuth state with CSRF protection.

The secret should be at least 32 bytes for cryptographic security. Aegis derives this from the master secret using the purpose "aegis:oauth-state".

Parameters:

  • cfg: Configuration with session settings, secret, and max age

Returns:

  • *StateStore: Initialized store ready for use

Example:

secret := aegis.DeriveSecret("aegis:oauth-state")
store := oauth.NewStateStore(&oauth.StateStoreConfig{
    SessionConfig: aegis.GetSessionConfig(),
    Secret: secret,
    MaxAge: 15 * 60, // 15 minutes
})

func (*StateStore) ClearState

func (s *StateStore) ClearState(w http.ResponseWriter)

ClearState clears the OAuth state cookie.

This method is called after successful callback validation to delete the one-time-use state cookie. It sets MaxAge=-1 to instruct the browser to delete the cookie immediately.

Parameters:

  • w: HTTP response writer for clearing cookie

func (*StateStore) GenerateState

func (s *StateStore) GenerateState() (string, error)

GenerateState generates a cryptographically secure random state string.

The state is a 32-byte random value base64-encoded for use as a CSRF token. This is the value included in the OAuth authorization URL and validated in the callback.

Returns:

  • string: Base64-encoded random state (44 characters)
  • error: Crypto random generation error (extremely rare)

func (*StateStore) GetMaxAge

func (s *StateStore) GetMaxAge() time.Duration

GetMaxAge returns the max age for state cookies

func (*StateStore) GetState

func (s *StateStore) GetState(r *http.Request) (*StateData, error)

GetState retrieves and validates the OAuth state data from the cookie.

This method is called during the OAuth callback to retrieve the stored state data for validation. It verifies the HMAC signature to ensure the cookie wasn't tampered with.

Processing:

  1. Read cookie value
  2. Base64-decode payload
  3. Verify HMAC signature (if secret is set)
  4. Parse: state|provider|compressedSession
  5. Decompress SessionData with gzip

Parameters:

  • r: HTTP request with state cookie

Returns:

  • *StateData: Decoded state data
  • error: Cookie not found, invalid signature, or decoding error

func (*StateStore) SetMaxAge

func (s *StateStore) SetMaxAge(age time.Duration)

SetMaxAge sets the max age for state cookies

func (*StateStore) StoreState

func (s *StateStore) StoreState(w http.ResponseWriter, data *StateData) error

StoreState stores OAuth state data in a signed, compressed cookie.

This method is called at the start of the OAuth flow (BeginAuth) to save the state data for validation during the callback. The cookie is HTTPOnly and Secure (if configured) to prevent JavaScript access and MITM attacks.

Processing:

  1. Compress SessionData with gzip (can be large ~1-2KB)
  2. Concatenate: state|provider|compressedSession
  3. Sign with HMAC-SHA256 if secret is set
  4. Base64-encode payload
  5. Store in cookie with configured expiration (15 minutes default)

Parameters:

  • w: HTTP response writer for setting cookie
  • data: State data to store

Returns:

  • error: Compression or encoding error

func (*StateStore) ValidateState

func (s *StateStore) ValidateState(r *http.Request, callbackState string) (*StateData, error)

ValidateState checks if the callback state matches the stored state.

This is the critical CSRF protection check. It ensures the OAuth callback originated from a legitimate authorization flow initiated by this server.

Validation:

  1. Retrieve state data from cookie
  2. Compare stored.State with callbackState from query parameter
  3. If mismatch → return error (possible CSRF attack)

Parameters:

  • r: HTTP request with state cookie
  • callbackState: State parameter from OAuth callback URL

Returns:

  • *StateData: Validated state data (if state matches)
  • error: State mismatch (CSRF) or cookie retrieval error

type StateStoreConfig

type StateStoreConfig struct {
	// SessionConfig contains cookie settings (Domain, Secure, HTTPOnly, SameSite)
	SessionConfig *core.SessionConfig
	// Secret is the key used for signing cookies (should be at least 32 bytes)
	Secret []byte
	// MaxAge overrides the default OAuth state cookie max age in seconds (default: 15 minutes)
	MaxAge int
}

StateStoreConfig holds configuration for creating a StateStore.

Example:

cfg := &oauth.StateStoreConfig{
    SessionConfig: aegis.GetSessionConfig(), // Domain, Secure, HTTPOnly, SameSite
    Secret: aegis.DeriveSecret("aegis:oauth-state"), // 32+ bytes
    MaxAge: 15 * 60, // 15 minutes
}
store := oauth.NewStateStore(cfg)

type Store

type Store interface {
	// CreateConnection creates a new OAuth provider connection.
	//
	// This method links an OAuth provider to an Aegis user account. It stores
	// the provider's user ID, access tokens, and user profile data.
	//
	// Constraints:
	//   - (provider, provider_user_id) must be unique
	//   - user_id must reference a valid auth.users.id
	//
	// Parameters:
	//   - ctx: Request context
	//   - conn: Connection data (ID, UserID, Provider, tokens, etc.)
	//
	// Returns:
	//   - *Connection: Created connection with generated ID
	//   - error: Duplicate connection or foreign key violation
	CreateConnection(ctx context.Context, conn Connection) (*Connection, error)

	// GetConnectionByProviderUserID retrieves a connection by provider and provider user ID.
	//
	// This method is used during OAuth login to check if a provider account is
	// already linked to an Aegis user. The provider user ID is the unique identifier
	// from the OAuth provider (e.g., Google's "108...", GitHub's "12345").
	//
	// Parameters:
	//   - ctx: Request context
	//   - provider: Provider name ("google", "github", etc.)
	//   - providerUserID: Provider's unique user ID
	//
	// Returns:
	//   - *Connection: Existing connection if found
	//   - error: ErrNotFound if no connection exists
	GetConnectionByProviderUserID(ctx context.Context, provider, providerUserID string) (*Connection, error)

	// GetConnectionsByUserID retrieves all OAuth connections for a user.
	//
	// This method returns all linked provider accounts for a user, useful for
	// displaying connected accounts in user settings.
	//
	// Parameters:
	//   - ctx: Request context
	//   - userID: Aegis user ID
	//
	// Returns:
	//   - []Connection: List of connections (may be empty)
	//   - error: Database query error
	GetConnectionsByUserID(ctx context.Context, userID string) ([]Connection, error)

	// UpdateConnection updates an existing OAuth connection.
	//
	// This method refreshes tokens or updates user profile data from the provider.
	// It updates the updated_at timestamp automatically.
	//
	// Parameters:
	//   - ctx: Request context
	//   - conn: Updated connection data (must have matching ID)
	//
	// Returns:
	//   - error: Connection not found or database error
	UpdateConnection(ctx context.Context, conn Connection) error

	// DeleteConnection removes an OAuth provider link from a user account.
	//
	// This method unlinks the specified provider from the user's account. The
	// user's Aegis account remains active.
	//
	// Parameters:
	//   - ctx: Request context
	//   - provider: Provider name ("google", "github", etc.)
	//   - userID: Aegis user ID
	//
	// Returns:
	//   - error: Connection not found or database error
	DeleteConnection(ctx context.Context, provider, userID string) error
}

Store defines the interface for OAuth connection storage operations.

This interface abstracts database operations for managing OAuth provider connections. Implementations should use transactions for consistency and handle duplicate connection errors appropriately.

Thread Safety: Implementations must be safe for concurrent use from multiple goroutines.

type Tokens

type Tokens struct {
	AccessToken  string         // OAuth access token
	RefreshToken string         // OAuth refresh token
	ExpiresAt    time.Time      // Token expiration time
	Scopes       []string       // Granted scopes
	Raw          map[string]any // Provider-specific fields
}

Tokens represents OAuth token response.

This struct holds the tokens returned by the provider after successful authorization code exchange. It's used for custom user info fetching.

type User

type User struct {
	auth.User
	AccessToken  string
	RefreshToken string
	ExpiresAt    time.Time
	ProviderData map[string]any
}

User represents an OAuth-authenticated user with provider tokens.

This struct extends auth.User with OAuth-specific fields like access tokens and provider-specific data. It's used during the OAuth flow to transfer user information from the provider to Aegis.

Fields:

  • User: Base user fields (ID, Email, Name, Avatar from auth.User)
  • AccessToken: OAuth access token for API calls to the provider
  • RefreshToken: OAuth refresh token for renewing access tokens
  • ExpiresAt: When the access token expires
  • ProviderData: Provider-specific fields (e.g., Google's "locale", GitHub's "company")

func GothUserToUser

func GothUserToUser(gothUser goth.User) *User

GothUserToUser converts goth.User to Aegis's User model.

This helper function transforms Goth's OAuth user representation into Aegis's User struct, preserving OAuth tokens and provider-specific data.

Field Mapping:

  • goth.UserID → User.ID (provider's user ID)
  • goth.Email → User.Email
  • goth.Name → User.Name
  • goth.AvatarURL → User.Avatar
  • goth.AccessToken, RefreshToken, ExpiresAt preserved

Parameters:

  • gothUser: User data from Goth provider

Returns:

  • *User: Aegis user model

Directories

Path Synopsis
internal

Jump to

Keyboard shortcuts

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