...
1
2
3
4
5 package externalaccountauthorizeduser
6
7 import (
8 "context"
9 "errors"
10 "time"
11
12 "golang.org/x/oauth2"
13 "golang.org/x/oauth2/google/internal/stsexchange"
14 )
15
16
17 var now = func() time.Time {
18 return time.Now().UTC()
19 }
20
21 var tokenValid = func(token oauth2.Token) bool {
22 return token.Valid()
23 }
24
25 type Config struct {
26
27
28 Audience string
29
30 RefreshToken string
31
32
33 TokenURL string
34
35 TokenInfoURL string
36
37 ClientID string
38
39
40
41 ClientSecret string
42
43 Token string
44
45 Expiry time.Time
46
47 RevokeURL string
48
49
50 QuotaProjectID string
51 Scopes []string
52 }
53
54 func (c *Config) canRefresh() bool {
55 return c.ClientID != "" && c.ClientSecret != "" && c.RefreshToken != "" && c.TokenURL != ""
56 }
57
58 func (c *Config) TokenSource(ctx context.Context) (oauth2.TokenSource, error) {
59 var token oauth2.Token
60 if c.Token != "" && !c.Expiry.IsZero() {
61 token = oauth2.Token{
62 AccessToken: c.Token,
63 Expiry: c.Expiry,
64 TokenType: "Bearer",
65 }
66 }
67 if !tokenValid(token) && !c.canRefresh() {
68 return nil, errors.New("oauth2/google: Token should be created with fields to make it valid (`token` and `expiry`), or fields to allow it to refresh (`refresh_token`, `token_url`, `client_id`, `client_secret`).")
69 }
70
71 ts := tokenSource{
72 ctx: ctx,
73 conf: c,
74 }
75
76 return oauth2.ReuseTokenSource(&token, ts), nil
77 }
78
79 type tokenSource struct {
80 ctx context.Context
81 conf *Config
82 }
83
84 func (ts tokenSource) Token() (*oauth2.Token, error) {
85 conf := ts.conf
86 if !conf.canRefresh() {
87 return nil, errors.New("oauth2/google: The credentials do not contain the necessary fields need to refresh the access token. You must specify refresh_token, token_url, client_id, and client_secret.")
88 }
89
90 clientAuth := stsexchange.ClientAuthentication{
91 AuthStyle: oauth2.AuthStyleInHeader,
92 ClientID: conf.ClientID,
93 ClientSecret: conf.ClientSecret,
94 }
95
96 stsResponse, err := stsexchange.RefreshAccessToken(ts.ctx, conf.TokenURL, conf.RefreshToken, clientAuth, nil)
97 if err != nil {
98 return nil, err
99 }
100 if stsResponse.ExpiresIn < 0 {
101 return nil, errors.New("oauth2/google: got invalid expiry from security token service")
102 }
103
104 if stsResponse.RefreshToken != "" {
105 conf.RefreshToken = stsResponse.RefreshToken
106 }
107
108 token := &oauth2.Token{
109 AccessToken: stsResponse.AccessToken,
110 Expiry: now().Add(time.Duration(stsResponse.ExpiresIn) * time.Second),
111 TokenType: "Bearer",
112 }
113 return token, nil
114 }
115
View as plain text