1// Copyright 2014 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// Package clientcredentials implements the OAuth2.0 "client credentials" token flow,
6// also known as the "two-legged OAuth 2.0".
7//
8// This should be used when the client is acting on its own behalf or when the client
9// is the resource owner. It may also be used when requesting access to protected
10// resources based on an authorization previously arranged with the authorization
11// server.
12//
13// See https://tools.ietf.org/html/rfc6749#section-4.4
14package clientcredentials // import "golang.org/x/oauth2/clientcredentials"
15
16import (
17	"context"
18	"fmt"
19	"net/http"
20	"net/url"
21	"strings"
22
23	"golang.org/x/oauth2"
24	"golang.org/x/oauth2/internal"
25)
26
27// Config describes a 2-legged OAuth2 flow, with both the
28// client application information and the server's endpoint URLs.
29type Config struct {
30	// ClientID is the application's ID.
31	ClientID string
32
33	// ClientSecret is the application's secret.
34	ClientSecret string
35
36	// TokenURL is the resource server's token endpoint
37	// URL. This is a constant specific to each server.
38	TokenURL string
39
40	// Scope specifies optional requested permissions.
41	Scopes []string
42
43	// EndpointParams specifies additional parameters for requests to the token endpoint.
44	EndpointParams url.Values
45
46	// AuthStyle optionally specifies how the endpoint wants the
47	// client ID & client secret sent. The zero value means to
48	// auto-detect.
49	AuthStyle oauth2.AuthStyle
50}
51
52// Token uses client credentials to retrieve a token.
53//
54// The provided context optionally controls which HTTP client is used. See the oauth2.HTTPClient variable.
55func (c *Config) Token(ctx context.Context) (*oauth2.Token, error) {
56	return c.TokenSource(ctx).Token()
57}
58
59// Client returns an HTTP client using the provided token.
60// The token will auto-refresh as necessary.
61//
62// The provided context optionally controls which HTTP client
63// is returned. See the oauth2.HTTPClient variable.
64//
65// The returned Client and its Transport should not be modified.
66func (c *Config) Client(ctx context.Context) *http.Client {
67	return oauth2.NewClient(ctx, c.TokenSource(ctx))
68}
69
70// TokenSource returns a TokenSource that returns t until t expires,
71// automatically refreshing it as necessary using the provided context and the
72// client ID and client secret.
73//
74// Most users will use Config.Client instead.
75func (c *Config) TokenSource(ctx context.Context) oauth2.TokenSource {
76	source := &tokenSource{
77		ctx:  ctx,
78		conf: c,
79	}
80	return oauth2.ReuseTokenSource(nil, source)
81}
82
83type tokenSource struct {
84	ctx  context.Context
85	conf *Config
86}
87
88// Token refreshes the token by using a new client credentials request.
89// tokens received this way do not include a refresh token
90func (c *tokenSource) Token() (*oauth2.Token, error) {
91	v := url.Values{
92		"grant_type": {"client_credentials"},
93	}
94	if len(c.conf.Scopes) > 0 {
95		v.Set("scope", strings.Join(c.conf.Scopes, " "))
96	}
97	for k, p := range c.conf.EndpointParams {
98		// Allow grant_type to be overridden to allow interoperability with
99		// non-compliant implementations.
100		if _, ok := v[k]; ok && k != "grant_type" {
101			return nil, fmt.Errorf("oauth2: cannot overwrite parameter %q", k)
102		}
103		v[k] = p
104	}
105
106	tk, err := internal.RetrieveToken(c.ctx, c.conf.ClientID, c.conf.ClientSecret, c.conf.TokenURL, v, internal.AuthStyle(c.conf.AuthStyle))
107	if err != nil {
108		if rErr, ok := err.(*internal.RetrieveError); ok {
109			return nil, (*oauth2.RetrieveError)(rErr)
110		}
111		return nil, err
112	}
113	t := &oauth2.Token{
114		AccessToken:  tk.AccessToken,
115		TokenType:    tk.TokenType,
116		RefreshToken: tk.RefreshToken,
117		Expiry:       tk.Expiry,
118	}
119	return t.WithExtra(tk.Raw), nil
120}
121