@ -30,6 +30,10 @@ type app struct {
verifier * oidc . IDTokenVerifier
provider * oidc . Provider
// Does the provider use "offline_access" scope to request a refresh token
// or does it use "access_type=offline" (e.g. Google)?
offlineAsScope bool
ctx context . Context
cancel context . CancelFunc
}
@ -102,6 +106,34 @@ func cmd() *cobra.Command {
if err != nil {
return fmt . Errorf ( "Failed to query provider %q: %v" , issuerURL , err )
}
var s struct {
// What scopes does a provider support?
//
// See: https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata
ScopesSupported [ ] string ` json:"scopes_supported" `
}
if err := provider . Claims ( & s ) ; err != nil {
return fmt . Errorf ( "Failed to parse provider scopes_supported: %v" , err )
}
if len ( s . ScopesSupported ) == 0 {
// scopes_supported is a "RECOMMENDED" discovery claim, not a required
// one. If missing, assume that the provider follows the spec and has
// an "offline_access" scope.
a . offlineAsScope = true
} else {
// See if scopes_supported has the "offline_access" scope.
a . offlineAsScope = func ( ) bool {
for _ , scope := range s . ScopesSupported {
if scope == oidc . ScopeOfflineAccess {
return true
}
}
return false
} ( )
}
a . provider = provider
a . verifier = provider . NewVerifier ( a . ctx , oidc . VerifyAudience ( a . clientID ) )
@ -166,10 +198,15 @@ func (a *app) handleLogin(w http.ResponseWriter, r *http.Request) {
scopes = append ( scopes , "audience:server:client_id:" + client )
}
// TODO(ericchiang): Determine if provider does not support "offline_access" or has
// some other mechanism for requesting refresh tokens.
scopes = append ( scopes , "openid" , "profile" , "email" , "offline_access" )
http . Redirect ( w , r , a . oauth2Config ( scopes ) . AuthCodeURL ( "" ) , http . StatusSeeOther )
authCodeURL := ""
scopes = append ( scopes , "openid" , "profile" , "email" )
if a . offlineAsScope {
scopes = append ( scopes , "offline_access" )
authCodeURL = a . oauth2Config ( scopes ) . AuthCodeURL ( "" )
} else {
authCodeURL = a . oauth2Config ( scopes ) . AuthCodeURL ( "" , oauth2 . AccessTypeOffline )
}
http . Redirect ( w , r , authCodeURL , http . StatusSeeOther )
}
func ( a * app ) handleCallback ( w http . ResponseWriter , r * http . Request ) {
@ -195,7 +232,7 @@ func (a *app) handleCallback(w http.ResponseWriter, r *http.Request) {
}
token , err = oauth2Config . TokenSource ( a . ctx , t ) . Token ( )
default :
http . Error ( w , "no code in request" , http . StatusBadRequest )
http . Error ( w , fmt . Sprintf ( "no code in request: %q " , r . Form ) , http . StatusBadRequest )
return
}