forked from Mirrors/oauth2
Access type and approval prompt should be set at URL generation.
This commit is contained in:
parent
cb029f4c1f
commit
97a89b3be5
|
@ -28,7 +28,7 @@ func Example_config() {
|
|||
|
||||
// Redirect user to consent page to ask for permission
|
||||
// for the scopes specified above.
|
||||
url := conf.AuthCodeURL("")
|
||||
url := conf.AuthCodeURL("state", "online", "auto")
|
||||
fmt.Printf("Visit the URL for the auth dialog: %v", url)
|
||||
|
||||
// Use the authorization code that is pushed to the redirect URL.
|
||||
|
|
|
@ -36,7 +36,7 @@ func Example_webServer() {
|
|||
|
||||
// Redirect user to Google's consent page to ask for permission
|
||||
// for the scopes specified above.
|
||||
url := config.AuthCodeURL("")
|
||||
url := config.AuthCodeURL("state", "online", "auto")
|
||||
fmt.Printf("Visit the URL for the auth dialog: %v", url)
|
||||
|
||||
// Handle the exchange code to initiate a transport
|
||||
|
|
66
oauth2.go
66
oauth2.go
|
@ -10,6 +10,7 @@ package oauth2
|
|||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"mime"
|
||||
"net/http"
|
||||
|
@ -39,15 +40,6 @@ type TokenFetcher interface {
|
|||
|
||||
// Options represents options to provide OAuth 2.0 client credentials
|
||||
// and access level. A sample configuration:
|
||||
//
|
||||
// opts := &oauth2.Options{
|
||||
// ClientID: "<clientID>",
|
||||
// ClientSecret: "ad4364309eff",
|
||||
// RedirectURL: "https://homepage/oauth2callback",
|
||||
// Scopes: []string{"scope1", "scope2"},
|
||||
// AccessType: "offline", // retrieves a refresh token
|
||||
// }
|
||||
//
|
||||
type Options struct {
|
||||
// ClientID is the OAuth client identifier used when communicating with
|
||||
// the configured OAuth provider.
|
||||
|
@ -63,26 +55,6 @@ type Options struct {
|
|||
|
||||
// Scopes optionally specifies a list of requested permission scopes.
|
||||
Scopes []string `json:"scopes,omitempty"`
|
||||
|
||||
// AccessType is an OAuth extension that gets sent as the
|
||||
// "access_type" field in the URL from AuthCodeURL.
|
||||
// See https://developers.google.com/accounts/docs/OAuth2WebServer.
|
||||
// It may be "online" (the default) or "offline".
|
||||
// If your application needs to refresh access tokens when the
|
||||
// user is not present at the browser, then use offline. This
|
||||
// will result in your application obtaining a refresh token
|
||||
// the first time your application exchanges an authorization
|
||||
// code for a user.
|
||||
AccessType string `json:"access_type,omitempty"`
|
||||
|
||||
// ApprovalPrompt indicates whether the user should be
|
||||
// re-prompted for consent. If set to "auto" (default) the
|
||||
// user will be prompted only if they haven't previously
|
||||
// granted consent and the code can only be exchanged for an
|
||||
// access token.
|
||||
// If set to "force" the user will always be prompted, and the
|
||||
// code can be exchanged for a refresh token.
|
||||
ApprovalPrompt string `json:"-"`
|
||||
}
|
||||
|
||||
// NewConfig creates a generic OAuth 2.0 configuration that talks
|
||||
|
@ -127,7 +99,28 @@ type Config struct {
|
|||
|
||||
// AuthCodeURL returns a URL to OAuth 2.0 provider's consent page
|
||||
// that asks for permissions for the required scopes explicitly.
|
||||
func (c *Config) AuthCodeURL(state string) (authURL string) {
|
||||
//
|
||||
// State is a token to protect the user from CSRF attacks. You must
|
||||
// always provide a non-zero string and validate that it matches the
|
||||
// the state query parameter on your redirect callback.
|
||||
// See http://tools.ietf.org/html/rfc6749#section-10.12 for more info.
|
||||
//
|
||||
// Access type is an OAuth extension that gets sent as the
|
||||
// "access_type" field in the URL from AuthCodeURL.
|
||||
// It may be "online" (default) or "offline".
|
||||
// If your application needs to refresh access tokens when the
|
||||
// user is not present at the browser, then use offline. This
|
||||
// will result in your application obtaining a refresh token
|
||||
// the first time your application exchanges an authorization
|
||||
// code for a user.
|
||||
//
|
||||
// Approval prompt indicates whether the user should be
|
||||
// re-prompted for consent. If set to "auto" (default) the
|
||||
// user will be prompted only if they haven't previously
|
||||
// granted consent and the code can only be exchanged for an
|
||||
// access token. If set to "force" the user will always be prompted,
|
||||
// and the code can be exchanged for a refresh token.
|
||||
func (c *Config) AuthCodeURL(state, accessType, prompt string) (authURL string) {
|
||||
u := *c.authURL
|
||||
v := url.Values{
|
||||
"response_type": {"code"},
|
||||
|
@ -135,8 +128,8 @@ func (c *Config) AuthCodeURL(state string) (authURL string) {
|
|||
"redirect_uri": condVal(c.opts.RedirectURL),
|
||||
"scope": condVal(strings.Join(c.opts.Scopes, " ")),
|
||||
"state": condVal(state),
|
||||
"access_type": condVal(c.opts.AccessType),
|
||||
"approval_prompt": condVal(c.opts.ApprovalPrompt),
|
||||
"access_type": condVal(accessType),
|
||||
"approval_prompt": condVal(prompt),
|
||||
}
|
||||
q := v.Encode()
|
||||
if u.RawQuery == "" {
|
||||
|
@ -210,9 +203,12 @@ func (c *Config) retrieveToken(v url.Values) (*Token, error) {
|
|||
return nil, err
|
||||
}
|
||||
defer r.Body.Close()
|
||||
if r.StatusCode != 200 {
|
||||
// TODO(jbd): Add status code or error message
|
||||
return nil, errors.New("oauth2: can't retrieve a new token")
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("oauth2: cannot fetch token: %v", err)
|
||||
}
|
||||
if c := r.StatusCode; c < 200 || c > 299 {
|
||||
return nil, fmt.Errorf("oauth2: cannot fetch token: %v\nResponse: %s", r.Status, body)
|
||||
}
|
||||
|
||||
resp := &tokenRespBody{}
|
||||
|
|
|
@ -29,15 +29,13 @@ func newTestConf(url string) *Config {
|
|||
"scope1",
|
||||
"scope2",
|
||||
},
|
||||
AccessType: "offline",
|
||||
ApprovalPrompt: "force",
|
||||
}, url+"/auth", url+"/token")
|
||||
return conf
|
||||
}
|
||||
|
||||
func TestAuthCodeURL(t *testing.T) {
|
||||
conf := newTestConf("server")
|
||||
url := conf.AuthCodeURL("foo")
|
||||
url := conf.AuthCodeURL("foo", "offline", "force")
|
||||
if url != "server/auth?access_type=offline&approval_prompt=force&client_id=CLIENT_ID&redirect_uri=REDIRECT_URL&response_type=code&scope=scope1+scope2&state=foo" {
|
||||
t.Fatalf("Auth code URL doesn't match the expected, found: %v", url)
|
||||
}
|
||||
|
@ -47,7 +45,7 @@ func TestAuthCodeURL_Optional(t *testing.T) {
|
|||
conf, _ := NewConfig(&Options{
|
||||
ClientID: "CLIENT_ID",
|
||||
}, "auth-url", "token-url")
|
||||
url := conf.AuthCodeURL("")
|
||||
url := conf.AuthCodeURL("", "", "")
|
||||
if url != "auth-url?client_id=CLIENT_ID&response_type=code" {
|
||||
t.Fatalf("Auth code URL doesn't match the expected, found: %v", url)
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ type Token struct {
|
|||
// initialized as needed.
|
||||
Extra map[string]string `json:"extra,omitempty"`
|
||||
|
||||
// JWT related fields
|
||||
// Subject is the user to impersonate.
|
||||
Subject string `json:"subject,omitempty"`
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue