social

package
v0.3.4 Latest Latest
Warning

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

Go to latest
Published: Sep 23, 2026 License: Apache-2.0 Imports: 21 Imported by: 0

Documentation

Overview

Package social signs people in with Google, Apple (ADR-0046) and GitHub (ADR-0059): the web authorization code flow with state, nonce and PKCE, ID tokens from native apps checked against the app's client IDs, Apple's client secret, token revocation and server-to-server notifications, and GitHub's user and email API for a provider without OpenID Connect. It wraps golang.org/x/oauth2 and github.com/coreos/go-oidc, so apps never import their types.

The app keeps the state, nonce and PKCE verifier of a web sign-in on the server, and resolves the returned Identity to an account.

Stability: stable (ADR-0015, ADR-0054).

Index

Constants

View Source
const (
	NotificationEmailDisabled  = "email-disabled"
	NotificationEmailEnabled   = "email-enabled"
	NotificationConsentRevoked = "consent-revoked"
	NotificationAccountDelete  = "account-delete"
)

Apple server-to-server notification types.

View Source
const (
	Google = "google"
	Apple  = "apple"
	GitHub = "github"
)

Provider names.

View Source
const MaxNotificationAge = time.Hour

MaxNotificationAge is how old an Apple notification can be when it's verified, so an old payload can't be replayed later.

View Source
const (
	// MaxTokenAge is how old an ID token can be when it's verified.
	MaxTokenAge = 10 * time.Minute
)

Variables

View Source
var (
	// ErrInvalidConfig reports a configuration that can't be used.
	ErrInvalidConfig = errors.New("social: invalid configuration")
	// ErrInvalidToken reports an ID token or notification that fails
	// verification: signature, issuer, audience, nonce, age or claims.
	ErrInvalidToken = errors.New("social: invalid ID token")
	// ErrExchange reports an authorization code the provider refused, or a
	// provider that couldn't be reached.
	ErrExchange = errors.New("social: authorization code exchange failed")
	// ErrWebUnavailable reports a provider configured only for native apps.
	ErrWebUnavailable = errors.New("social: web sign-in is not configured")
	// ErrNotSupported reports an operation the provider doesn't offer, such
	// as verifying an ID token from GitHub, which issues none.
	ErrNotSupported = errors.New("social: not supported by this provider")
)

Errors returned by the package. Check them with errors.Is.

Functions

func NewPKCEVerifier

func NewPKCEVerifier() string

NewPKCEVerifier returns a random PKCE code verifier to keep with a web sign-in's state.

func ParseApplePrivateKey

func ParseApplePrivateKey(pemBytes []byte) (*ecdsa.PrivateKey, error)

ParseApplePrivateKey reads a Sign in with Apple .p8 key: a PEM PKCS #8 P-256 private key. It returns ErrInvalidConfig.

Types

type AppleConfig

type AppleConfig struct {
	// TeamID, KeyID and PrivateKey sign client secrets: the Team ID, and the
	// ID and .p8 key of a Sign in with Apple key.
	TeamID     string
	KeyID      string
	PrivateKey *ecdsa.PrivateKey
	// ServicesID is the web client; empty for native apps only.
	ServicesID string
	// BundleIDs are the iOS apps ID tokens may be issued for.
	BundleIDs  []string
	Endpoints  Endpoints
	HTTPClient *http.Client
	Now        func() time.Time
}

AppleConfig configures Sign in with Apple.

type Endpoints

type Endpoints struct {
	AuthURL   string
	TokenURL  string
	KeysURL   string
	RevokeURL string
	// Issuers are the accepted "iss" values of ID tokens.
	Issuers []string
	// APIURL is the base URL of GitHub's REST API, which returns the person
	// and their email addresses; unused by other providers.
	APIURL string
}

Endpoints are a provider's URLs. Zero values use Google's, Apple's or GitHub's; tests point them at socialtest.

func AppleEndpoints

func AppleEndpoints() Endpoints

AppleEndpoints returns Apple's endpoints.

func GitHubEndpoints

func GitHubEndpoints() Endpoints

GitHubEndpoints returns GitHub's endpoints.

func GoogleEndpoints

func GoogleEndpoints() Endpoints

GoogleEndpoints returns Google's endpoints.

type GitHubConfig

type GitHubConfig struct {
	// ClientID and ClientSecret are the OAuth app's.
	ClientID     string
	ClientSecret string
	Endpoints    Endpoints
	HTTPClient   *http.Client
}

GitHubConfig configures GitHub sign-in with an OAuth app.

type GoogleConfig

type GoogleConfig struct {
	// ClientID and ClientSecret are the Web application client. Android apps
	// use ClientID too.
	ClientID     string
	ClientSecret string
	// NativeClientIDs are the iOS and Android client IDs ID tokens may be
	// issued for.
	NativeClientIDs []string
	Endpoints       Endpoints
	HTTPClient      *http.Client
	Now             func() time.Time
}

GoogleConfig configures Google sign-in.

type Identity

type Identity struct {
	// Provider is Google, Apple or GitHub.
	Provider string
	// Subject identifies the person at the provider; it never changes. For
	// GitHub it is the numeric user ID in decimal, not the login, which
	// people can rename.
	Subject string
	Email   string
	// EmailVerified reports that the provider checked the person owns Email.
	EmailVerified bool
	// PrivateEmail reports an Apple relay address.
	PrivateEmail bool
	// HostedDomain is the Google Workspace domain of the account ("hd"),
	// empty for personal Google accounts and Apple.
	HostedDomain string
	// Name is the person's name, when the provider sends it; for GitHub, the
	// login when the profile has no name.
	Name string
	// Audience is the client ID the token was issued for (for GitHub, the
	// OAuth app's client ID).
	Audience string
}

Identity is a person as a verified ID token, or GitHub's API, describes them.

func (Identity) AuthoritativeEmail

func (id Identity) AuthoritativeEmail() bool

AuthoritativeEmail reports whether the provider manages Email's domain, so a verified Email still belongs to the person: Google for gmail.com, googlemail.com and the account's own Workspace domain, Apple for relay addresses and iCloud (icloud.com, me.com, mac.com). For other addresses, EmailVerified only says the person controlled the address when they added it to their provider account, possibly years ago; don't link such an identity to an existing account without the account's owner (security review AUTH-M-1). GitHub hosts no one's email, so it is never authoritative (ADR-0059).

type Notification

type Notification struct {
	// ID identifies the notification ("jti", or a hash of the payload when
	// Apple sends none). Remember it until IssuedAt plus
	// [MaxNotificationAge] and ignore a notification seen before: a replayed
	// payload carries the same ID.
	ID string
	// Type is one of the Notification constants.
	Type    string
	Subject string
	Email   string
	// PrivateEmail reports an Apple relay address.
	PrivateEmail bool
	// At is when the event happened; IssuedAt when Apple signed the
	// notification.
	At       time.Time
	IssuedAt time.Time
}

Notification is an Apple server-to-server notification about a person who signed in with Apple.

type Provider

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

Provider runs one provider's sign-ins. It is safe for concurrent use.

func NewApple

func NewApple(c AppleConfig) (*Provider, error)

NewApple returns the Apple provider. It returns ErrInvalidConfig.

func NewGitHub

func NewGitHub(c GitHubConfig) (*Provider, error)

NewGitHub returns the GitHub provider (ADR-0059). GitHub has no OpenID Connect: Provider.Exchange trades the code (with state and PKCE, like Google) for an access token, reads the person from GET /user and their primary email from GET /user/emails with the scopes read:user and user:email, and forgets the token. It offers the web flow only: ID tokens, native codes and revocation return ErrNotSupported. It returns ErrInvalidConfig.

func NewGoogle

func NewGoogle(c GoogleConfig) (*Provider, error)

NewGoogle returns the Google provider. It returns ErrInvalidConfig.

func (*Provider) AppleNotification

func (p *Provider) AppleNotification(ctx context.Context, payload string) (Notification, error)

AppleNotification verifies the payload Apple posts to the notification endpoint: Apple's signature, issuer, a configured audience, and an issue time within MaxNotificationAge. It returns ErrInvalidToken, or ErrInvalidConfig on a provider other than Apple.

func (*Provider) AuthCodeURL

func (p *Provider) AuthCodeURL(redirectURL, state, nonce, verifier string) string

AuthCodeURL returns the provider URL that starts a web sign-in returning to redirectURL. state and nonce are single-use random values the app keeps; verifier is from NewPKCEVerifier (Apple ignores it). GitHub, which issues no ID token, ignores nonce: state and PKCE protect its flow.

func (*Provider) Exchange

func (p *Provider) Exchange(ctx context.Context, redirectURL, code, verifier, nonce string) (Token, error)

Exchange trades a web sign-in's authorization code for tokens and verifies the ID token against the web client and nonce. For GitHub, it reads the person from GitHub's API with the access token instead, which it then forgets (nonce is unused). It returns ErrWebUnavailable, ErrExchange or ErrInvalidToken.

func (*Provider) ExchangeNativeCode

func (p *Provider) ExchangeNativeCode(ctx context.Context, code, clientID string) (string, error)

ExchangeNativeCode trades an authorization code a native app received for clientID, such as Apple's authorizationCode on iOS, and returns the refresh token (empty when the provider sends none). It returns ErrExchange, ErrInvalidConfig for a client ID that isn't configured, or ErrNotSupported for GitHub.

func (*Provider) Name

func (p *Provider) Name() string

Name returns the provider's name: Google, Apple or GitHub.

func (*Provider) NativeClients

func (p *Provider) NativeClients() []string

NativeClients returns the client IDs native apps' tokens may be issued for, other than the web client.

func (*Provider) Revoke

func (p *Provider) Revoke(ctx context.Context, refreshToken, clientID string) error

Revoke revokes a refresh token issued for clientID, as Apple requires when an account is deleted. It returns ErrNotSupported for GitHub, whose tokens are never kept.

func (*Provider) VerifyIDToken

func (p *Provider) VerifyIDToken(ctx context.Context, rawIDToken, nonce string) (Identity, error)

VerifyIDToken verifies an ID token a native app obtained: signature, issuer, an audience among the configured client IDs, expiry, an age under MaxTokenAge, and nonce. It returns ErrInvalidToken, wrapping ErrNotSupported for GitHub, which issues no ID tokens.

func (*Provider) Web

func (p *Provider) Web() bool

Web reports whether the web flow is configured.

type Token

type Token struct {
	Identity Identity
	// RefreshToken is set when the provider returns one (Apple); store it
	// encrypted to revoke it later.
	RefreshToken string
}

Token is the result of a code exchange.

Directories

Path Synopsis
Package socialtest runs an in-process OpenID Connect provider standing in for Google or Apple in tests: it serves signing keys, a token endpoint and a revocation endpoint, and issues signed ID tokens, authorization codes and Apple notifications.
Package socialtest runs an in-process OpenID Connect provider standing in for Google or Apple in tests: it serves signing keys, a token endpoint and a revocation endpoint, and issues signed ID tokens, authorization codes and Apple notifications.

Jump to

Keyboard shortcuts

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