The OAuth2 "client credentials" flow (2-legged OAuth) for server-to-server authentication where the client acts on its own behalf without user involvement.
import "golang.org/x/oauth2/clientcredentials"The client credentials flow is used when:
This flow does not involve user authorization and is suitable for machine-to-machine authentication.
See: https://tools.ietf.org/html/rfc6749#section-4.4
type Config struct {
// ClientID is the application's ID
ClientID string
// ClientSecret is the application's secret
ClientSecret string
// TokenURL is the resource server's token endpoint URL
TokenURL string
// Scopes specifies optional requested permissions
Scopes []string
// EndpointParams specifies additional parameters for token endpoint requests
EndpointParams url.Values
// AuthStyle optionally specifies how the endpoint wants credentials sent
// Zero value means auto-detect
AuthStyle oauth2.AuthStyle
}Example:
import (
"golang.org/x/oauth2"
"golang.org/x/oauth2/clientcredentials"
)
conf := &clientcredentials.Config{
ClientID: "your-client-id",
ClientSecret: "your-client-secret",
TokenURL: "https://provider.com/oauth/token",
Scopes: []string{"read", "write"},
AuthStyle: oauth2.AuthStyleInHeader,
}func (c *Config) Client(ctx context.Context) *http.ClientReturns an HTTP client that automatically handles token retrieval and refresh. This is the most common method for using client credentials.
The provided context optionally controls which HTTP client is used via the oauth2.HTTPClient context key. The returned client and its Transport should not be modified.
Example:
ctx := context.Background()
client := conf.Client(ctx)
// All requests automatically include authentication
resp, err := client.Get("https://api.example.com/resource")
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()func (c *Config) Token(ctx context.Context) (*oauth2.Token, error)Retrieves a token using client credentials. The provided context optionally controls which HTTP client is used.
Example:
token, err := conf.Token(ctx)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Access Token: %s\n", token.AccessToken)
fmt.Printf("Token Type: %s\n", token.Type())
fmt.Printf("Expires: %s\n", token.Expiry)func (c *Config) TokenSource(ctx context.Context) oauth2.TokenSourceReturns a TokenSource that automatically refreshes tokens as necessary using the client ID and client secret. Most users should use Config.Client instead.
Example:
// Advanced usage with custom token source
ts := conf.TokenSource(ctx)
// Manually get token
token, err := ts.Token()
// Or create custom client
client := oauth2.NewClient(ctx, ts)The EndpointParams field allows sending additional parameters to the token endpoint for providers with non-standard requirements.
Example:
conf := &clientcredentials.Config{
ClientID: "client-id",
ClientSecret: "client-secret",
TokenURL: "https://provider.com/token",
EndpointParams: url.Values{
"resource": {"https://api.example.com"},
"audience": {"https://api.example.com"},
},
}Note: The grant_type parameter can be overridden via EndpointParams for interoperability with non-compliant implementations, but other standard parameters cannot be overwritten.
The AuthStyle field controls how client credentials are sent to the token endpoint:
import "golang.org/x/oauth2"
// Auto-detect the style (default)
conf.AuthStyle = oauth2.AuthStyleAutoDetect
// Send credentials in POST body
conf.AuthStyle = oauth2.AuthStyleInParams
// Send credentials via HTTP Basic Authorization
conf.AuthStyle = oauth2.AuthStyleInHeaderErrors during token retrieval return oauth2.RetrieveError with detailed information:
token, err := conf.Token(ctx)
if err != nil {
if rerr, ok := err.(*oauth2.RetrieveError); ok {
fmt.Printf("Token error: %s - %s\n",
rerr.ErrorCode, rerr.ErrorDescription)
}
return err
}package main
import (
"context"
"fmt"
"io"
"log"
"net/http"
"golang.org/x/oauth2/clientcredentials"
)
func main() {
ctx := context.Background()
// Configure client credentials
conf := &clientcredentials.Config{
ClientID: "your-client-id",
ClientSecret: "your-client-secret",
TokenURL: "https://auth.example.com/oauth/token",
Scopes: []string{"api.read", "api.write"},
}
// Create authenticated HTTP client
client := conf.Client(ctx)
// Make authenticated API request
resp, err := client.Get("https://api.example.com/data")
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
// Read response
body, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Response: %s\n", body)
}| Feature | Client Credentials | Authorization Code |
|---|---|---|
| User involvement | No user authorization required | Requires user to authorize |
| Use case | Machine-to-machine | User-delegated access |
| Refresh tokens | Not issued | Typically issued with offline access |
| Flow type | 2-legged | 3-legged |
| Token lifespan | Usually short-lived, auto-renewed | Can be long-lived with refresh |
To use a custom HTTP client for token requests:
customClient := &http.Client{
Timeout: 10 * time.Second,
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
MinVersion: tls.VersionTLS12,
},
},
}
ctx := context.WithValue(context.Background(), oauth2.HTTPClient, customClient)
client := conf.Client(ctx)