| // Copyright 2014 The oauth2 Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| // Package google provides support for making |
| // OAuth2 authorized and authenticated HTTP requests |
| // to Google APIs. It supports Web server, client-side, |
| // service accounts, Google Compute Engine service accounts, |
| // and Google App Engine service accounts authorization |
| // and authentications flows: |
| // |
| // For more information, please read |
| // https://developers.google.com/accounts/docs/OAuth2. |
| package google // import "golang.org/x/oauth2/google" |
| |
| import ( |
| "encoding/json" |
| |
| "fmt" |
| "io/ioutil" |
| "net/http" |
| "net/url" |
| "time" |
| |
| "golang.org/x/oauth2" |
| "golang.org/x/oauth2/internal" |
| ) |
| |
| var ( |
| uriGoogleAuth, _ = url.Parse("https://accounts.google.com/o/oauth2/auth") |
| uriGoogleToken, _ = url.Parse("https://accounts.google.com/o/oauth2/token") |
| ) |
| |
| type metaTokenRespBody struct { |
| AccessToken string `json:"access_token"` |
| ExpiresIn time.Duration `json:"expires_in"` |
| TokenType string `json:"token_type"` |
| } |
| |
| // JWTEndpoint adds the endpoints required to complete the 2-legged service account flow. |
| func JWTEndpoint() oauth2.Option { |
| return func(opts *oauth2.Options) error { |
| opts.AUD = uriGoogleToken |
| return nil |
| } |
| } |
| |
| // Endpoint adds the endpoints required to do the 3-legged Web server flow. |
| func Endpoint() oauth2.Option { |
| return func(opts *oauth2.Options) error { |
| opts.AuthURL = uriGoogleAuth |
| opts.TokenURL = uriGoogleToken |
| return nil |
| } |
| } |
| |
| // ComputeEngineAccount uses the specified account to retrieve an access |
| // token from the Google Compute Engine's metadata server. If no user is |
| // provided, "default" is being used. |
| func ComputeEngineAccount(account string) oauth2.Option { |
| return func(opts *oauth2.Options) error { |
| if account == "" { |
| account = "default" |
| } |
| opts.TokenFetcherFunc = makeComputeFetcher(opts, account) |
| return nil |
| } |
| } |
| |
| // ServiceAccountJSONKey uses the provided Google Developers |
| // JSON key file to authorize the user. See the "Credentials" page under |
| // "APIs & Auth" for your project at https://console.developers.google.com |
| // to download a JSON key file. |
| func ServiceAccountJSONKey(filename string) oauth2.Option { |
| return func(opts *oauth2.Options) error { |
| b, err := ioutil.ReadFile(filename) |
| if err != nil { |
| return err |
| } |
| var key struct { |
| Email string `json:"client_email"` |
| PrivateKey string `json:"private_key"` |
| } |
| if err := json.Unmarshal(b, &key); err != nil { |
| return err |
| } |
| pk, err := internal.ParseKey([]byte(key.PrivateKey)) |
| if err != nil { |
| return err |
| } |
| opts.Email = key.Email |
| opts.PrivateKey = pk |
| opts.AUD = uriGoogleToken |
| return nil |
| } |
| } |
| |
| func makeComputeFetcher(opts *oauth2.Options, account string) func(*oauth2.Token) (*oauth2.Token, error) { |
| return func(t *oauth2.Token) (*oauth2.Token, error) { |
| u := "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/" + account + "/token" |
| req, err := http.NewRequest("GET", u, nil) |
| if err != nil { |
| return nil, err |
| } |
| req.Header.Add("X-Google-Metadata-Request", "True") |
| c := &http.Client{} |
| if opts.Client != nil { |
| c = opts.Client |
| } |
| resp, err := c.Do(req) |
| if err != nil { |
| return nil, err |
| } |
| defer resp.Body.Close() |
| if resp.StatusCode < 200 || resp.StatusCode > 299 { |
| return nil, fmt.Errorf("oauth2: can't retrieve a token from metadata server, status code: %d", resp.StatusCode) |
| } |
| var tokenResp metaTokenRespBody |
| err = json.NewDecoder(resp.Body).Decode(&tokenResp) |
| if err != nil { |
| return nil, err |
| } |
| return &oauth2.Token{ |
| AccessToken: tokenResp.AccessToken, |
| TokenType: tokenResp.TokenType, |
| Expiry: time.Now().Add(tokenResp.ExpiresIn * time.Second), |
| }, nil |
| } |
| } |