Complete documentation for the main golang.org/x/oauth2 package covering authorization code flow, token management, device authorization, PKCE, and HTTP transport.
import "golang.org/x/oauth2"The standard 3-legged OAuth2 flow for web and mobile applications where users grant permission via a browser.
type Config struct {
// ClientID is the application's ID
ClientID string
// ClientSecret is the application's secret
ClientSecret string
// Endpoint contains the authorization server's token endpoint URLs
Endpoint Endpoint
// RedirectURL is the URL to redirect users going through the OAuth flow
RedirectURL string
// Scopes specifies optional requested permissions
Scopes []string
}func (c *Config) AuthCodeURL(state string, opts ...AuthCodeOption) stringGenerates a URL to the OAuth 2.0 provider's consent page. The state parameter is an opaque value used to maintain state between request and callback for CSRF protection.
Example:
conf := &oauth2.Config{
ClientID: "your-client-id",
ClientSecret: "your-client-secret",
Scopes: []string{"profile", "email"},
Endpoint: google.Endpoint,
RedirectURL: "http://localhost:8080/callback",
}
// With PKCE (recommended for CSRF protection)
verifier := oauth2.GenerateVerifier()
url := conf.AuthCodeURL("random-state", oauth2.S256ChallengeOption(verifier))
// With access type for refresh tokens
url := conf.AuthCodeURL("state", oauth2.AccessTypeOffline)
// Force consent dialog
url := conf.AuthCodeURL("state", oauth2.ApprovalForce)func (c *Config) Exchange(ctx context.Context, code string, opts ...AuthCodeOption) (*Token, error)Converts an authorization code into a token. Used after the provider redirects the user back to your redirect URI with a code parameter.
Example:
// After user authorizes, extract code from callback
code := r.URL.Query().Get("code")
state := r.URL.Query().Get("state")
// Validate state parameter
if state != expectedState {
return errors.New("invalid state")
}
// Exchange code for token (with PKCE verifier if used)
token, err := conf.Exchange(ctx, code, oauth2.VerifierOption(verifier))
if err != nil {
return err
}func (c *Config) Client(ctx context.Context, t *Token) *http.ClientReturns an HTTP client that automatically adds authentication and refreshes tokens as needed.
func (c *Config) TokenSource(ctx context.Context, t *Token) TokenSourceReturns a TokenSource for more granular control. Most users should use Client instead.
Example:
client := conf.Client(ctx, token)
// All requests automatically include authentication
resp, err := client.Get("https://api.example.com/user")func (c *Config) PasswordCredentialsToken(ctx context.Context, username, password string) (*Token, error)Converts a username/password pair into a token. Only use when there is high trust between resource owner and client (e.g., native OS applications).
OAuth2 flow for devices with limited input capabilities (smart TVs, IoT devices, CLI tools) following RFC 8628.
type DeviceAuthResponse struct {
// DeviceCode is the device verification code
DeviceCode string `json:"device_code"`
// UserCode is the code the user should enter at the verification URI
UserCode string `json:"user_code"`
// VerificationURI is where the user should enter the user code
VerificationURI string `json:"verification_uri"`
// VerificationURIComplete includes the user code in the URI (e.g., for QR codes)
VerificationURIComplete string `json:"verification_uri_complete,omitempty"`
// Expiry is when the device code and user code expire
Expiry time.Time `json:"expires_in,omitempty"`
// Interval is the duration in seconds between polling requests
Interval int64 `json:"interval,omitempty"`
}
func (d DeviceAuthResponse) MarshalJSON() ([]byte, error)
func (c *DeviceAuthResponse) UnmarshalJSON(data []byte) errorfunc (c *Config) DeviceAuth(ctx context.Context, opts ...AuthCodeOption) (*DeviceAuthResponse, error)Returns device authorization information for the user to complete on another device.
func (c *Config) DeviceAccessToken(ctx context.Context, da *DeviceAuthResponse, opts ...AuthCodeOption) (*Token, error)Polls the authorization server to exchange a device code for an access token. Automatically handles polling intervals and continues until authorization is granted, denied, or expired.
Example:
// Initiate device authorization
deviceAuth, err := conf.DeviceAuth(ctx)
if err != nil {
return err
}
// Display instructions to user
fmt.Printf("Visit %s and enter code: %s\n",
deviceAuth.VerificationURI, deviceAuth.UserCode)
// Poll for access token (blocks until user authorizes or timeout)
token, err := conf.DeviceAccessToken(ctx, deviceAuth)
if err != nil {
return err
}
// Use token
client := conf.Client(ctx, token)Proof Key for Code Exchange (PKCE) provides additional security against authorization code interception attacks.
func GenerateVerifier() stringGenerates a PKCE code verifier with 32 octets of randomness following RFC 7636. A fresh verifier should be generated for each authorization flow.
func S256ChallengeOption(verifier string) AuthCodeOptionDerives a PKCE code challenge from the verifier using the S256 method. Pass to AuthCodeURL or DeviceAuth.
func S256ChallengeFromVerifier(verifier string) stringReturns the S256 challenge string. Prefer S256ChallengeOption for most use cases.
func VerifierOption(verifier string) AuthCodeOptionReturns the verifier as an AuthCodeOption. Pass to Exchange or DeviceAccessToken.
Example:
// Generate verifier
verifier := oauth2.GenerateVerifier()
// Use challenge when generating auth URL
authURL := conf.AuthCodeURL("state", oauth2.S256ChallengeOption(verifier))
// Use verifier when exchanging code
token, err := conf.Exchange(ctx, code, oauth2.VerifierOption(verifier))type Token struct {
// AccessToken is the token that authorizes and authenticates requests
AccessToken string `json:"access_token"`
// TokenType is the type of token (default: Bearer)
TokenType string `json:"token_type,omitempty"`
// RefreshToken is used to refresh the access token when it expires
RefreshToken string `json:"refresh_token,omitempty"`
// Expiry is the optional expiration time of the access token
Expiry time.Time `json:"expiry,omitempty"`
// ExpiresIn is the OAuth2 wire format field (seconds until expiration)
ExpiresIn int64 `json:"expires_in,omitempty"`
}func (t *Token) Valid() boolReports whether the token is non-nil, has an AccessToken, and is not expired.
func (t *Token) Type() stringReturns the token type if set, otherwise "Bearer".
func (t *Token) SetAuthHeader(r *http.Request)Sets the Authorization header on an HTTP request. Unnecessary when using Transport or Config.Client.
func (t *Token) Extra(key string) anyReturns extra fields from the token retrieval response.
func (t *Token) WithExtra(extra any) *TokenReturns a clone of the token with the provided raw extra map. For implementing derivative OAuth2 flows.
Example:
// Check token validity
if !token.Valid() {
// Token needs refresh
}
// Access extra fields
idToken := token.Extra("id_token").(string)
// Manual authorization header (rarely needed)
req, _ := http.NewRequest("GET", url, nil)
token.SetAuthHeader(req)type TokenSource interface {
// Token returns a token or an error
// Must be safe for concurrent use
// The returned Token must not be modified
Token() (*Token, error)
}func StaticTokenSource(t *Token) TokenSourceReturns a TokenSource that always returns the same token. Only useful for tokens that never expire.
func ReuseTokenSource(t *Token, src TokenSource) TokenSourceReturns a TokenSource that reuses the same token while valid, automatically refreshing from src when expired. Typically used to cache tokens between program runs.
func ReuseTokenSourceWithExpiry(t *Token, src TokenSource, earlyExpiry time.Duration) TokenSourceLike ReuseTokenSource but with configurable expiry buffer. The token is considered expired at t.Expiry.Add(-earlyExpiry).
Example:
// Static token (no refresh)
src := oauth2.StaticTokenSource(&oauth2.Token{
AccessToken: "permanent-token",
})
// Cached token with automatic refresh
cached := oauth2.ReuseTokenSource(cachedToken, conf.TokenSource(ctx, cachedToken))
// With custom expiry buffer (refresh 1 minute early)
src := oauth2.ReuseTokenSourceWithExpiry(token, conf.TokenSource(ctx, token), time.Minute)
// Create client from token source
client := oauth2.NewClient(ctx, src)Low-level HTTP transport for OAuth2 authentication.
type Transport struct {
// Source supplies the token to add to outgoing requests
Source TokenSource
// Base is the base RoundTripper (defaults to http.DefaultTransport)
Base http.RoundTripper
}func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error)Authorizes and authenticates the request with an access token from the Transport's Source.
func (t *Transport) CancelRequest(req *http.Request)Deprecated: No-op. Use contexts for cancellation instead.
func NewClient(ctx context.Context, src TokenSource) *http.ClientCreates an HTTP client from a TokenSource. The returned client is not valid beyond the lifetime of the context. Most users should use Config.Client instead.
Example:
// Low-level transport usage
transport := &oauth2.Transport{
Source: oauth2.StaticTokenSource(token),
Base: http.DefaultTransport,
}
client := &http.Client{Transport: transport}
// Or use NewClient helper
client := oauth2.NewClient(ctx, tokenSource)type Endpoint struct {
// AuthURL is the authorization endpoint URL
AuthURL string
// DeviceAuthURL is the device authorization endpoint URL (optional)
DeviceAuthURL string
// TokenURL is the token endpoint URL
TokenURL string
// AuthStyle specifies how to send client credentials (auto-detect if zero)
AuthStyle AuthStyle
}type AuthStyle int
const (
// AuthStyleAutoDetect tries both methods and caches the successful one
AuthStyleAutoDetect AuthStyle = 0
// AuthStyleInParams sends client_id and client_secret in POST body
AuthStyleInParams AuthStyle = 1
// AuthStyleInHeader sends credentials via HTTP Basic Authorization
AuthStyleInHeader AuthStyle = 2
)Example:
// Custom endpoint
endpoint := oauth2.Endpoint{
AuthURL: "https://provider.com/oauth/authorize",
TokenURL: "https://provider.com/oauth/token",
AuthStyle: oauth2.AuthStyleInHeader,
}
// Using predefined endpoints
import "golang.org/x/oauth2/google"
endpoint := google.Endpointtype AuthCodeOption interface {
// Has unexported methods
}var AccessTypeOnline AuthCodeOption
var AccessTypeOffline AuthCodeOption
var ApprovalForce AuthCodeOptionfunc SetAuthURLParam(key, value string) AuthCodeOptionBuilds an AuthCodeOption that passes custom key/value parameters to the provider's authorization endpoint.
Example:
// Request refresh token
url := conf.AuthCodeURL("state", oauth2.AccessTypeOffline)
// Custom parameters
url := conf.AuthCodeURL("state",
oauth2.SetAuthURLParam("prompt", "select_account"),
oauth2.SetAuthURLParam("login_hint", "user@example.com"))type RetrieveError struct {
// Response is the HTTP response
Response *http.Response
// Body is the response body (may be truncated)
Body []byte
// ErrorCode is RFC 6749's 'error' parameter
ErrorCode string
// ErrorDescription is RFC 6749's 'error_description' parameter
ErrorDescription string
// ErrorURI is RFC 6749's 'error_uri' parameter
ErrorURI string
}
func (r *RetrieveError) Error() stringError returned when the token endpoint returns a non-2XX status or populates the 'error' parameter.
Example:
token, err := conf.Exchange(ctx, code)
if err != nil {
if rerr, ok := err.(*oauth2.RetrieveError); ok {
fmt.Printf("OAuth error: %s - %s\n",
rerr.ErrorCode, rerr.ErrorDescription)
}
return err
}var HTTPClient internal.ContextKeyContext key to associate a custom *http.Client with a context for token acquisition.
Example:
// Use custom HTTP client for token requests
customClient := &http.Client{Timeout: 10 * time.Second}
ctx := context.WithValue(ctx, oauth2.HTTPClient, customClient)
token, err := conf.Exchange(ctx, code)var NoContext = context.TODO()Deprecated: Use context.Background() or context.TODO() instead.
func RegisterBrokenAuthHeaderProvider(tokenURL string)Deprecated: No-op function. Set Endpoint.AuthStyle instead to avoid auto-probing.
package main
import (
"context"
"fmt"
"log"
"net/http"
"golang.org/x/oauth2"
"golang.org/x/oauth2/google"
)
func main() {
ctx := context.Background()
// Configure OAuth2
conf := &oauth2.Config{
ClientID: "your-client-id",
ClientSecret: "your-client-secret",
Scopes: []string{
"https://www.googleapis.com/auth/userinfo.email",
"https://www.googleapis.com/auth/userinfo.profile",
},
Endpoint: google.Endpoint,
RedirectURL: "http://localhost:8080/callback",
}
// Generate PKCE verifier
verifier := oauth2.GenerateVerifier()
// Generate authorization URL
url := conf.AuthCodeURL("state-token",
oauth2.AccessTypeOffline,
oauth2.S256ChallengeOption(verifier))
fmt.Printf("Visit this URL: %s\n", url)
// Start callback server
http.HandleFunc("/callback", func(w http.ResponseWriter, r *http.Request) {
// Verify state
if r.URL.Query().Get("state") != "state-token" {
http.Error(w, "State mismatch", http.StatusBadRequest)
return
}
// Exchange code for token
code := r.URL.Query().Get("code")
token, err := conf.Exchange(ctx, code, oauth2.VerifierOption(verifier))
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// Create authenticated client
client := conf.Client(ctx, token)
// Make API request
resp, err := client.Get("https://www.googleapis.com/oauth2/v2/userinfo")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
defer resp.Body.Close()
// Process response...
fmt.Fprintf(w, "Authentication successful!")
})
log.Fatal(http.ListenAndServe(":8080", nil))
}