oauth

package
v0.3.5 Latest Latest
Warning

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

Go to latest
Published: Feb 17, 2026 License: Apache-2.0 Imports: 9 Imported by: 0

Documentation

Overview

Package oauth provides OAuth2 authorization code flow implementations for common providers.

This package includes a Provider interface and concrete implementations for Google and GitHub. Each provider handles the full OAuth2 flow: generating authorization URLs, exchanging codes for tokens, and fetching verified user information.

Features

  • Provider interface for pluggable OAuth2 implementations
  • Google OAuth2 with email verification
  • GitHub OAuth2 with primary verified email resolution
  • Functional options for custom HTTP clients (testing, custom transports)
  • Configuration structs with env tags for environment-based setup
  • Sentinel errors with "oauth:" prefix for consistent error handling

Usage

Google provider setup:

provider, err := oauth.NewGoogleProvider(oauth.GoogleConfig{
	ClientID:     os.Getenv("GOOGLE_OAUTH_CLIENT_ID"),
	ClientSecret: os.Getenv("GOOGLE_OAUTH_CLIENT_SECRET"),
	RedirectURL:  "https://example.com/auth/google/callback",
})
if err != nil {
	log.Fatal(err)
}

// Generate authorization URL
url := provider.AuthCodeURL("random-state-string")

// Exchange code for token (in callback handler)
token, err := provider.Exchange(ctx, code, "")
if err != nil {
	// handle error
}

// Fetch user info
user, err := provider.FetchUserInfo(ctx, token)
if err != nil {
	// handle error
}

GitHub provider setup:

provider, err := oauth.NewGitHubProvider(oauth.GitHubConfig{
	ClientID:     os.Getenv("GITHUB_OAUTH_CLIENT_ID"),
	ClientSecret: os.Getenv("GITHUB_OAUTH_CLIENT_SECRET"),
	RedirectURL:  "https://example.com/auth/github/callback",
})
if err != nil {
	log.Fatal(err)
}

Custom Providers

Implement the Provider interface to add support for other OAuth2 providers:

type MyProvider struct { /* ... */ }

func (p *MyProvider) Name() string { return "my-provider" }
func (p *MyProvider) AuthCodeURL(state string, opts ...oauth2.AuthCodeOption) string { /* ... */ }
func (p *MyProvider) Exchange(ctx context.Context, code, redirectURI string) (*oauth2.Token, error) { /* ... */ }
func (p *MyProvider) FetchUserInfo(ctx context.Context, token *oauth2.Token) (*oauth.UserInfo, error) { /* ... */ }

Testing

Use WithHTTPClient to inject a test server for unit testing:

ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
	// mock responses
}))
defer ts.Close()

provider, err := oauth.NewGoogleProvider(cfg, oauth.WithHTTPClient(ts.Client()))

Error Handling

The package provides sentinel errors for specific failure modes:

  • ErrMissingClientID: Constructor called without client ID
  • ErrMissingClientSecret: Constructor called without client secret
  • ErrEmailNotVerified: Provider reports unverified email
  • ErrFetchFailed: HTTP request to provider failed
  • ErrNilResponse: Provider returned nil HTTP response
  • ErrRequestFailed: Provider returned non-OK HTTP status
  • ErrDecodeFailed: Failed to decode provider JSON response

Use errors.Is for checking:

if errors.Is(err, oauth.ErrEmailNotVerified) {
	// ask user to verify email
}

Security

  • Always validate the state parameter to prevent CSRF attacks
  • Use HTTPS redirect URIs in production
  • Store tokens securely (encrypted at rest, never in URLs)
  • Both providers enforce email verification before returning user info
  • Keep client secrets out of source control (use environment variables)

Index

Constants

View Source
const (
	// GitHubProviderName is the identifier for GitHub OAuth provider.
	GitHubProviderName = "github"
)
View Source
const (
	// GoogleProviderName is the identifier for Google OAuth provider.
	GoogleProviderName = "google"
)

Variables

View Source
var (
	// ErrMissingClientID is returned when the OAuth client ID is not provided.
	ErrMissingClientID = errors.New("oauth: missing client ID")

	// ErrMissingClientSecret is returned when the OAuth client secret is not provided.
	ErrMissingClientSecret = errors.New("oauth: missing client secret")

	// ErrEmailNotVerified is returned when the OAuth provider reports
	// that the user's email is not verified.
	ErrEmailNotVerified = errors.New("oauth: email not verified")

	// ErrNilResponse is returned when the OAuth provider returns a nil response.
	ErrNilResponse = errors.New("oauth: nil response from provider")

	// ErrFetchFailed is returned when fetching data from the OAuth provider fails.
	ErrFetchFailed = errors.New("oauth: failed to fetch from provider")

	// ErrRequestFailed is returned when the OAuth provider returns a non-OK status.
	ErrRequestFailed = errors.New("oauth: request returned non-OK status")

	// ErrDecodeFailed is returned when decoding the OAuth provider response fails.
	ErrDecodeFailed = errors.New("oauth: failed to decode response")
)

Functions

func GitHubDefaultScopes

func GitHubDefaultScopes() []string

GitHubDefaultScopes returns the default scopes for GitHub OAuth.

func GoogleDefaultScopes

func GoogleDefaultScopes() []string

GoogleDefaultScopes returns the default scopes for Google OAuth.

Types

type GitHubConfig

type GitHubConfig struct {
	ClientID     string   `env:"CLIENT_ID,required"`
	ClientSecret string   `env:"CLIENT_SECRET,required"`
	RedirectURL  string   `env:"REDIRECT_URL"`
	Scopes       []string `env:"SCOPES" envSeparator:","`
}

GitHubConfig holds GitHub OAuth configuration.

type GitHubProvider

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

GitHubProvider implements Provider for GitHub OAuth.

func NewGitHubProvider

func NewGitHubProvider(cfg GitHubConfig, opts ...Option) (*GitHubProvider, error)

NewGitHubProvider creates a new GitHub OAuth provider. Returns an error if ClientID or ClientSecret is empty.

func (*GitHubProvider) AuthCodeURL

func (p *GitHubProvider) AuthCodeURL(state string, opts ...oauth2.AuthCodeOption) string

AuthCodeURL generates the authorization URL.

func (*GitHubProvider) Exchange

func (p *GitHubProvider) Exchange(ctx context.Context, code, redirectURI string) (*oauth2.Token, error)

Exchange trades an authorization code for tokens.

func (*GitHubProvider) FetchUserInfo

func (p *GitHubProvider) FetchUserInfo(ctx context.Context, token *oauth2.Token) (*UserInfo, error)

FetchUserInfo retrieves user information from GitHub. Returns ErrEmailNotVerified if no verified primary email is found.

func (*GitHubProvider) Name

func (p *GitHubProvider) Name() string

Name returns the provider identifier.

type GoogleConfig

type GoogleConfig struct {
	ClientID     string   `env:"CLIENT_ID,required"`
	ClientSecret string   `env:"CLIENT_SECRET,required"`
	RedirectURL  string   `env:"REDIRECT_URL"`
	Scopes       []string `env:"SCOPES" envSeparator:","`
}

GoogleConfig holds Google OAuth configuration.

type GoogleProvider

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

GoogleProvider implements Provider for Google OAuth.

func NewGoogleProvider

func NewGoogleProvider(cfg GoogleConfig, opts ...Option) (*GoogleProvider, error)

NewGoogleProvider creates a new Google OAuth provider. Returns an error if ClientID or ClientSecret is empty.

func (*GoogleProvider) AuthCodeURL

func (p *GoogleProvider) AuthCodeURL(state string, opts ...oauth2.AuthCodeOption) string

AuthCodeURL generates the authorization URL.

func (*GoogleProvider) Exchange

func (p *GoogleProvider) Exchange(ctx context.Context, code, redirectURI string) (*oauth2.Token, error)

Exchange trades an authorization code for tokens.

func (*GoogleProvider) FetchUserInfo

func (p *GoogleProvider) FetchUserInfo(ctx context.Context, token *oauth2.Token) (*UserInfo, error)

FetchUserInfo retrieves user information from Google. Returns ErrEmailNotVerified if the user's email is not verified.

func (*GoogleProvider) Name

func (p *GoogleProvider) Name() string

Name returns the provider identifier.

type Option

type Option func(*options)

Option configures an OAuth provider.

func WithHTTPClient

func WithHTTPClient(client *http.Client) Option

WithHTTPClient sets a custom HTTP client for OAuth requests. This is useful for testing with httptest servers or injecting custom transports (e.g., logging, retries).

type Provider

type Provider interface {
	// Name returns the provider identifier (e.g., "google", "github").
	Name() string

	// AuthCodeURL generates the authorization URL for the OAuth flow.
	AuthCodeURL(state string, opts ...oauth2.AuthCodeOption) string

	// Exchange trades an authorization code for tokens.
	Exchange(ctx context.Context, code, redirectURI string) (*oauth2.Token, error)

	// FetchUserInfo retrieves user information using the access token.
	// Implementations must verify the user's email and return ErrEmailNotVerified
	// if the email is not verified.
	FetchUserInfo(ctx context.Context, token *oauth2.Token) (*UserInfo, error)
}

Provider abstracts provider-specific OAuth operations. Each provider (Google, GitHub, etc.) implements this interface. Provider implementations handle all provider-specific details internally, including email verification checks.

type UserInfo

type UserInfo struct {
	ID      string // Provider's unique user identifier
	Email   string
	Name    string
	Picture string
}

UserInfo represents provider-agnostic user information retrieved from an OAuth provider's userinfo endpoint.

Jump to

Keyboard shortcuts

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