forked from Mirrors/oauth2
Allow users to get extra fields from a token response.
This commit is contained in:
parent
2e27b6b6cb
commit
0ae3d4edc9
23
jwt.go
23
jwt.go
|
@ -135,29 +135,28 @@ func (c *JWTConfig) FetchToken(existing *Token) (*Token, error) {
|
||||||
return nil, fmt.Errorf("oauth2: cannot fetch token: %v\nResponse: %s", resp.Status, body)
|
return nil, fmt.Errorf("oauth2: cannot fetch token: %v\nResponse: %s", resp.Status, body)
|
||||||
}
|
}
|
||||||
|
|
||||||
b := &tokenRespBody{}
|
b := make(map[string]interface{})
|
||||||
if err := json.Unmarshal(body, b); err != nil {
|
if err := json.Unmarshal(body, &b); err != nil {
|
||||||
return nil, fmt.Errorf("oauth2: cannot fetch token: %v", err)
|
return nil, fmt.Errorf("oauth2: cannot fetch token: %v", err)
|
||||||
}
|
}
|
||||||
|
token := &Token{}
|
||||||
token := &Token{
|
token.AccessToken, _ = b["access_token"].(string)
|
||||||
AccessToken: b.AccessToken,
|
token.TokenType, _ = b["token_type"].(string)
|
||||||
TokenType: b.TokenType,
|
token.Subject = existing.Subject
|
||||||
Subject: existing.Subject,
|
token.raw = b
|
||||||
|
if e, ok := b["expires_in"].(int); ok {
|
||||||
|
token.Expiry = time.Now().Add(time.Duration(e) * time.Second)
|
||||||
}
|
}
|
||||||
|
if idtoken, ok := b["id_token"].(string); ok {
|
||||||
if b.IdToken != "" {
|
|
||||||
// decode returned id token to get expiry
|
// decode returned id token to get expiry
|
||||||
claimSet := &jws.ClaimSet{}
|
claimSet := &jws.ClaimSet{}
|
||||||
claimSet, err = jws.Decode(b.IdToken)
|
claimSet, err = jws.Decode(idtoken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("oauth2: cannot fetch token: %v", err)
|
return nil, fmt.Errorf("oauth2: cannot fetch token: %v", err)
|
||||||
}
|
}
|
||||||
token.Expiry = time.Unix(claimSet.Exp, 0)
|
token.Expiry = time.Unix(claimSet.Exp, 0)
|
||||||
return token, nil
|
return token, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
token.Expiry = time.Now().Add(time.Duration(b.ExpiresIn) * time.Second)
|
|
||||||
return token, nil
|
return token, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,113 @@
|
||||||
|
// 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 oauth2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
var dummyPrivateKey = []byte(`-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIEpAIBAAKCAQEAx4fm7dngEmOULNmAs1IGZ9Apfzh+BkaQ1dzkmbUgpcoghucE
|
||||||
|
DZRnAGd2aPyB6skGMXUytWQvNYav0WTR00wFtX1ohWTfv68HGXJ8QXCpyoSKSSFY
|
||||||
|
fuP9X36wBSkSX9J5DVgiuzD5VBdzUISSmapjKm+DcbRALjz6OUIPEWi1Tjl6p5RK
|
||||||
|
1w41qdbmt7E5/kGhKLDuT7+M83g4VWhgIvaAXtnhklDAggilPPa8ZJ1IFe31lNlr
|
||||||
|
k4DRk38nc6sEutdf3RL7QoH7FBusI7uXV03DC6dwN1kP4GE7bjJhcRb/7jYt7CQ9
|
||||||
|
/E9Exz3c0yAp0yrTg0Fwh+qxfH9dKwN52S7SBwIDAQABAoIBAQCaCs26K07WY5Jt
|
||||||
|
3a2Cw3y2gPrIgTCqX6hJs7O5ByEhXZ8nBwsWANBUe4vrGaajQHdLj5OKfsIDrOvn
|
||||||
|
2NI1MqflqeAbu/kR32q3tq8/Rl+PPiwUsW3E6Pcf1orGMSNCXxeducF2iySySzh3
|
||||||
|
nSIhCG5uwJDWI7a4+9KiieFgK1pt/Iv30q1SQS8IEntTfXYwANQrfKUVMmVF9aIK
|
||||||
|
6/WZE2yd5+q3wVVIJ6jsmTzoDCX6QQkkJICIYwCkglmVy5AeTckOVwcXL0jqw5Kf
|
||||||
|
5/soZJQwLEyBoQq7Kbpa26QHq+CJONetPP8Ssy8MJJXBT+u/bSseMb3Zsr5cr43e
|
||||||
|
DJOhwsThAoGBAPY6rPKl2NT/K7XfRCGm1sbWjUQyDShscwuWJ5+kD0yudnT/ZEJ1
|
||||||
|
M3+KS/iOOAoHDdEDi9crRvMl0UfNa8MAcDKHflzxg2jg/QI+fTBjPP5GOX0lkZ9g
|
||||||
|
z6VePoVoQw2gpPFVNPPTxKfk27tEzbaffvOLGBEih0Kb7HTINkW8rIlzAoGBAM9y
|
||||||
|
1yr+jvfS1cGFtNU+Gotoihw2eMKtIqR03Yn3n0PK1nVCDKqwdUqCypz4+ml6cxRK
|
||||||
|
J8+Pfdh7D+ZJd4LEG6Y4QRDLuv5OA700tUoSHxMSNn3q9As4+T3MUyYxWKvTeu3U
|
||||||
|
f2NWP9ePU0lV8ttk7YlpVRaPQmc1qwooBA/z/8AdAoGAW9x0HWqmRICWTBnpjyxx
|
||||||
|
QGlW9rQ9mHEtUotIaRSJ6K/F3cxSGUEkX1a3FRnp6kPLcckC6NlqdNgNBd6rb2rA
|
||||||
|
cPl/uSkZP42Als+9YMoFPU/xrrDPbUhu72EDrj3Bllnyb168jKLa4VBOccUvggxr
|
||||||
|
Dm08I1hgYgdN5huzs7y6GeUCgYEAj+AZJSOJ6o1aXS6rfV3mMRve9bQ9yt8jcKXw
|
||||||
|
5HhOCEmMtaSKfnOF1Ziih34Sxsb7O2428DiX0mV/YHtBnPsAJidL0SdLWIapBzeg
|
||||||
|
KHArByIRkwE6IvJvwpGMdaex1PIGhx5i/3VZL9qiq/ElT05PhIb+UXgoWMabCp84
|
||||||
|
OgxDK20CgYAeaFo8BdQ7FmVX2+EEejF+8xSge6WVLtkaon8bqcn6P0O8lLypoOhd
|
||||||
|
mJAYH8WU+UAy9pecUnDZj14LAGNVmYcse8HFX71MoshnvCTFEPVo4rZxIAGwMpeJ
|
||||||
|
5jgQ3slYLpqrGlcbLgUXBUgzEO684Wk/UV9DFPlHALVqCfXQ9dpJPg==
|
||||||
|
-----END RSA PRIVATE KEY-----`)
|
||||||
|
|
||||||
|
func TestJWTFetch_JSONResponse(t *testing.T) {
|
||||||
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
w.Write([]byte(`{"access_token": "90d64460d14870c08c81352a05dedd3465940a7c", "scope": "user", "token_type": "bearer"}`))
|
||||||
|
}))
|
||||||
|
defer ts.Close()
|
||||||
|
conf, err := NewJWTConfig(&JWTOptions{
|
||||||
|
Email: "aaa@xxx.com",
|
||||||
|
PrivateKey: dummyPrivateKey,
|
||||||
|
}, ts.URL)
|
||||||
|
tok, err := conf.FetchToken(nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Failed retrieving token: %s.", err)
|
||||||
|
}
|
||||||
|
if tok.Expired() {
|
||||||
|
t.Errorf("Token shouldn't be expired.")
|
||||||
|
}
|
||||||
|
if tok.AccessToken != "90d64460d14870c08c81352a05dedd3465940a7c" {
|
||||||
|
t.Errorf("Unexpected access token, %#v.", tok.AccessToken)
|
||||||
|
}
|
||||||
|
if tok.TokenType != "bearer" {
|
||||||
|
t.Errorf("Unexpected token type, %#v.", tok.TokenType)
|
||||||
|
}
|
||||||
|
scope := tok.Extra("scope")
|
||||||
|
if scope != "user" {
|
||||||
|
t.Errorf("Unexpected value for scope: %v", scope)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestJWTFetch_BadResponse(t *testing.T) {
|
||||||
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
w.Write([]byte(`{"scope": "user", "token_type": "bearer"}`))
|
||||||
|
}))
|
||||||
|
defer ts.Close()
|
||||||
|
conf, err := NewJWTConfig(&JWTOptions{
|
||||||
|
Email: "aaa@xxx.com",
|
||||||
|
PrivateKey: dummyPrivateKey,
|
||||||
|
}, ts.URL)
|
||||||
|
tok, err := conf.FetchToken(nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Failed retrieving token: %s.", err)
|
||||||
|
}
|
||||||
|
if tok.AccessToken != "" {
|
||||||
|
t.Errorf("Unexpected access token, %#v.", tok.AccessToken)
|
||||||
|
}
|
||||||
|
if tok.TokenType != "bearer" {
|
||||||
|
t.Errorf("Unexpected token type, %#v.", tok.TokenType)
|
||||||
|
}
|
||||||
|
scope := tok.Extra("scope")
|
||||||
|
if scope != "user" {
|
||||||
|
t.Errorf("Unexpected value for scope: %v", scope)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestJWTFetch_BadResponseType(t *testing.T) {
|
||||||
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
w.Write([]byte(`{"access_token":123, "scope": "user", "token_type": "bearer"}`))
|
||||||
|
}))
|
||||||
|
defer ts.Close()
|
||||||
|
conf, err := NewJWTConfig(&JWTOptions{
|
||||||
|
Email: "aaa@xxx.com",
|
||||||
|
PrivateKey: dummyPrivateKey,
|
||||||
|
}, ts.URL)
|
||||||
|
tok, err := conf.FetchToken(nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Failed retrieving token: %s.", err)
|
||||||
|
}
|
||||||
|
if tok.AccessToken != "" {
|
||||||
|
t.Errorf("Unexpected access token, %#v.", tok.AccessToken)
|
||||||
|
}
|
||||||
|
}
|
79
oauth2.go
79
oauth2.go
|
@ -20,15 +20,6 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type tokenRespBody struct {
|
|
||||||
AccessToken string `json:"access_token"`
|
|
||||||
TokenType string `json:"token_type"`
|
|
||||||
RefreshToken string `json:"refresh_token"`
|
|
||||||
ExpiresIn int64 `json:"expires_in"` // in seconds
|
|
||||||
Expires int64 `json:"expires"` // in seconds. Facebook returns expires_in as expires.
|
|
||||||
IdToken string `json:"id_token"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// TokenFetcher refreshes or fetches a new access token from the
|
// TokenFetcher refreshes or fetches a new access token from the
|
||||||
// provider. It should return an error if it's not capable of
|
// provider. It should return an error if it's not capable of
|
||||||
// retrieving a token.
|
// retrieving a token.
|
||||||
|
@ -212,7 +203,8 @@ func (c *Config) retrieveToken(v url.Values) (*Token, error) {
|
||||||
return nil, fmt.Errorf("oauth2: cannot fetch token: %v\nResponse: %s", r.Status, body)
|
return nil, fmt.Errorf("oauth2: cannot fetch token: %v\nResponse: %s", r.Status, body)
|
||||||
}
|
}
|
||||||
|
|
||||||
resp := &tokenRespBody{}
|
token := &Token{}
|
||||||
|
expires := int(0)
|
||||||
content, _, _ := mime.ParseMediaType(r.Header.Get("Content-Type"))
|
content, _, _ := mime.ParseMediaType(r.Header.Get("Content-Type"))
|
||||||
switch content {
|
switch content {
|
||||||
case "application/x-www-form-urlencoded", "text/plain":
|
case "application/x-www-form-urlencoded", "text/plain":
|
||||||
|
@ -220,44 +212,45 @@ func (c *Config) retrieveToken(v url.Values) (*Token, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
resp.AccessToken = vals.Get("access_token")
|
token.AccessToken = vals.Get("access_token")
|
||||||
resp.TokenType = vals.Get("token_type")
|
token.TokenType = vals.Get("token_type")
|
||||||
resp.RefreshToken = vals.Get("refresh_token")
|
token.RefreshToken = vals.Get("refresh_token")
|
||||||
resp.ExpiresIn, _ = strconv.ParseInt(vals.Get("expires_in"), 10, 64)
|
token.raw = vals
|
||||||
resp.Expires, _ = strconv.ParseInt(vals.Get("expires"), 10, 64)
|
e := vals.Get("expires_in")
|
||||||
resp.IdToken = vals.Get("id_token")
|
if e == "" {
|
||||||
default:
|
|
||||||
if err = json.Unmarshal(body, &resp); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
token := &Token{
|
|
||||||
AccessToken: resp.AccessToken,
|
|
||||||
TokenType: resp.TokenType,
|
|
||||||
RefreshToken: resp.RefreshToken,
|
|
||||||
}
|
|
||||||
// Don't overwrite `RefreshToken` with an empty value
|
|
||||||
// if this was a token refreshing request.
|
|
||||||
if resp.RefreshToken == "" {
|
|
||||||
token.RefreshToken = v.Get("refresh_token")
|
|
||||||
}
|
|
||||||
if resp.ExpiresIn == 0 || resp.Expires == 0 {
|
|
||||||
token.Expiry = time.Time{}
|
|
||||||
}
|
|
||||||
if resp.ExpiresIn > 0 {
|
|
||||||
token.Expiry = time.Now().Add(time.Duration(resp.ExpiresIn) * time.Second)
|
|
||||||
}
|
|
||||||
if resp.Expires > 0 {
|
|
||||||
// TODO(jbd): Facebook's OAuth2 implementation is broken and
|
// TODO(jbd): Facebook's OAuth2 implementation is broken and
|
||||||
// returns expires_in field in expires. Remove the fallback to expires,
|
// returns expires_in field in expires. Remove the fallback to expires,
|
||||||
// when Facebook fixes their implementation.
|
// when Facebook fixes their implementation.
|
||||||
token.Expiry = time.Now().Add(time.Duration(resp.Expires) * time.Second)
|
e = vals.Get("expires")
|
||||||
}
|
}
|
||||||
if resp.IdToken != "" {
|
expires, _ = strconv.Atoi(e)
|
||||||
if token.Extra == nil {
|
default:
|
||||||
token.Extra = make(map[string]string)
|
b := make(map[string]interface{})
|
||||||
|
if err = json.Unmarshal(body, &b); err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
token.Extra["id_token"] = resp.IdToken
|
token.AccessToken, _ = b["access_token"].(string)
|
||||||
|
token.TokenType, _ = b["token_type"].(string)
|
||||||
|
token.RefreshToken, _ = b["refresh_token"].(string)
|
||||||
|
token.raw = b
|
||||||
|
e, ok := b["expires_in"].(int)
|
||||||
|
if !ok {
|
||||||
|
// TODO(jbd): Facebook's OAuth2 implementation is broken and
|
||||||
|
// returns expires_in field in expires. Remove the fallback to expires,
|
||||||
|
// when Facebook fixes their implementation.
|
||||||
|
e, _ = b["expires"].(int)
|
||||||
|
}
|
||||||
|
expires = e
|
||||||
|
}
|
||||||
|
// Don't overwrite `RefreshToken` with an empty value
|
||||||
|
// if this was a token refreshing request.
|
||||||
|
if token.RefreshToken == "" {
|
||||||
|
token.RefreshToken = v.Get("refresh_token")
|
||||||
|
}
|
||||||
|
if expires == 0 {
|
||||||
|
token.Expiry = time.Time{}
|
||||||
|
} else {
|
||||||
|
token.Expiry = time.Now().Add(time.Duration(expires) * time.Second)
|
||||||
}
|
}
|
||||||
return token, nil
|
return token, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,14 +84,18 @@ func TestExchangeRequest(t *testing.T) {
|
||||||
t.Errorf("Token shouldn't be expired.")
|
t.Errorf("Token shouldn't be expired.")
|
||||||
}
|
}
|
||||||
if tok.AccessToken != "90d64460d14870c08c81352a05dedd3465940a7c" {
|
if tok.AccessToken != "90d64460d14870c08c81352a05dedd3465940a7c" {
|
||||||
t.Errorf("Wrong access token, %#v.", tok.AccessToken)
|
t.Errorf("Unexpected access token, %#v.", tok.AccessToken)
|
||||||
}
|
}
|
||||||
if tok.TokenType != "bearer" {
|
if tok.TokenType != "bearer" {
|
||||||
t.Errorf("Wrong token type, %#v.", tok.TokenType)
|
t.Errorf("Unexpected token type, %#v.", tok.TokenType)
|
||||||
|
}
|
||||||
|
scope := tok.Extra("scope")
|
||||||
|
if scope != "user" {
|
||||||
|
t.Errorf("Unexpected value for scope: %v", scope)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestExchangeRequest_JsonResponse(t *testing.T) {
|
func TestExchangeRequest_JSONResponse(t *testing.T) {
|
||||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
if r.URL.String() != "/token" {
|
if r.URL.String() != "/token" {
|
||||||
t.Errorf("Unexpected exchange request URL, %v is found.", r.URL)
|
t.Errorf("Unexpected exchange request URL, %v is found.", r.URL)
|
||||||
|
@ -124,10 +128,46 @@ func TestExchangeRequest_JsonResponse(t *testing.T) {
|
||||||
t.Errorf("Token shouldn't be expired.")
|
t.Errorf("Token shouldn't be expired.")
|
||||||
}
|
}
|
||||||
if tok.AccessToken != "90d64460d14870c08c81352a05dedd3465940a7c" {
|
if tok.AccessToken != "90d64460d14870c08c81352a05dedd3465940a7c" {
|
||||||
t.Errorf("Wrong access token, %#v.", tok.AccessToken)
|
t.Errorf("Unexpected access token, %#v.", tok.AccessToken)
|
||||||
}
|
}
|
||||||
if tok.TokenType != "bearer" {
|
if tok.TokenType != "bearer" {
|
||||||
t.Errorf("Wrong token type, %#v.", tok.TokenType)
|
t.Errorf("Unexpected token type, %#v.", tok.TokenType)
|
||||||
|
}
|
||||||
|
scope := tok.Extra("scope")
|
||||||
|
if scope != "user" {
|
||||||
|
t.Errorf("Unexpected value for scope: %v", scope)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExchangeRequest_BadResponse(t *testing.T) {
|
||||||
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
w.Write([]byte(`{"scope": "user", "token_type": "bearer"}`))
|
||||||
|
}))
|
||||||
|
defer ts.Close()
|
||||||
|
conf := newTestConf(ts.URL)
|
||||||
|
tok, err := conf.Exchange("exchange-code")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Failed retrieving token: %s.", err)
|
||||||
|
}
|
||||||
|
if tok.AccessToken != "" {
|
||||||
|
t.Errorf("Unexpected access token, %#v.", tok.AccessToken)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExchangeRequest_BadResponseType(t *testing.T) {
|
||||||
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
w.Write([]byte(`{"access_token":123, "scope": "user", "token_type": "bearer"}`))
|
||||||
|
}))
|
||||||
|
defer ts.Close()
|
||||||
|
conf := newTestConf(ts.URL)
|
||||||
|
tok, err := conf.Exchange("exchange-code")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Failed retrieving token: %s.", err)
|
||||||
|
}
|
||||||
|
if tok.AccessToken != "" {
|
||||||
|
t.Errorf("Unexpected access token, %#v.", tok.AccessToken)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
39
transport.go
39
transport.go
|
@ -6,6 +6,7 @@ package oauth2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
@ -30,14 +31,28 @@ type Token struct {
|
||||||
// The remaining lifetime of the access token.
|
// The remaining lifetime of the access token.
|
||||||
Expiry time.Time `json:"expiry,omitempty"`
|
Expiry time.Time `json:"expiry,omitempty"`
|
||||||
|
|
||||||
// Extra optionally contains extra metadata from the server
|
|
||||||
// when updating a token. The only current key that may be
|
|
||||||
// populated is "id_token". It may be nil and will be
|
|
||||||
// initialized as needed.
|
|
||||||
Extra map[string]string `json:"extra,omitempty"`
|
|
||||||
|
|
||||||
// Subject is the user to impersonate.
|
// Subject is the user to impersonate.
|
||||||
Subject string `json:"subject,omitempty"`
|
Subject string `json:"subject,omitempty"`
|
||||||
|
|
||||||
|
// raw optionally contains extra metadata from the server
|
||||||
|
// when updating a token.
|
||||||
|
raw interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extra returns an extra field returned from the server during token retrieval.
|
||||||
|
// E.g.
|
||||||
|
// idToken := token.Extra("id_token")
|
||||||
|
//
|
||||||
|
func (t *Token) Extra(key string) string {
|
||||||
|
if vals, ok := t.raw.(url.Values); ok {
|
||||||
|
return vals.Get(key)
|
||||||
|
}
|
||||||
|
if raw, ok := t.raw.(map[string]interface{}); ok {
|
||||||
|
if val, ok := raw[key].(string); ok {
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// Expired returns true if there is no access token or the
|
// Expired returns true if there is no access token or the
|
||||||
|
@ -105,17 +120,7 @@ func (t *Transport) RoundTrip(req *http.Request) (resp *http.Response, err error
|
||||||
func (t *Transport) Token() *Token {
|
func (t *Transport) Token() *Token {
|
||||||
t.mu.RLock()
|
t.mu.RLock()
|
||||||
defer t.mu.RUnlock()
|
defer t.mu.RUnlock()
|
||||||
if t.token == nil {
|
return t.token
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return &Token{
|
|
||||||
AccessToken: t.token.AccessToken,
|
|
||||||
TokenType: t.token.TokenType,
|
|
||||||
RefreshToken: t.token.RefreshToken,
|
|
||||||
Expiry: t.token.Expiry,
|
|
||||||
Extra: t.token.Extra,
|
|
||||||
Subject: t.token.Subject,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetToken sets a token to the transport in a thread-safe way.
|
// SetToken sets a token to the transport in a thread-safe way.
|
||||||
|
|
Loading…
Reference in New Issue