diff --git a/selfservice/strategy/oidc/provider_google.go b/selfservice/strategy/oidc/provider_google.go index 117471b9379b..cb98696484ca 100644 --- a/selfservice/strategy/oidc/provider_google.go +++ b/selfservice/strategy/oidc/provider_google.go @@ -3,6 +3,15 @@ package oidc +import ( + "context" + + gooidc "github.com/coreos/go-oidc" + "golang.org/x/oauth2" + + "github.com/ory/x/stringslice" +) + type ProviderGoogle struct { *ProviderGenericOIDC } @@ -19,3 +28,41 @@ func NewProviderGoogle( }, } } + +func (g *ProviderGoogle) oauth2ConfigFromEndpoint(ctx context.Context, endpoint oauth2.Endpoint) *oauth2.Config { + scope := g.config.Scope + if !stringslice.Has(scope, gooidc.ScopeOpenID) { + scope = append(scope, gooidc.ScopeOpenID) + } + + scope = stringslice.Filter(scope, func(s string) bool { return s == gooidc.ScopeOfflineAccess }) + + return &oauth2.Config{ + ClientID: g.config.ClientID, + ClientSecret: g.config.ClientSecret, + Endpoint: endpoint, + Scopes: scope, + RedirectURL: g.config.Redir(g.reg.Config().OIDCRedirectURIBase(ctx)), + } +} + +func (g *ProviderGoogle) OAuth2(ctx context.Context) (*oauth2.Config, error) { + p, err := g.provider(ctx) + if err != nil { + return nil, err + } + + endpoint := p.Endpoint() + return g.oauth2ConfigFromEndpoint(ctx, endpoint), nil +} + +func (g *ProviderGoogle) AuthCodeURLOptions(r ider) []oauth2.AuthCodeOption { + scope := g.config.Scope + options := g.ProviderGenericOIDC.AuthCodeURLOptions(r) + + if stringslice.Has(scope, gooidc.ScopeOfflineAccess) { + options = append(options, oauth2.AccessTypeOffline) + } + + return options +} diff --git a/selfservice/strategy/oidc/provider_google_test.go b/selfservice/strategy/oidc/provider_google_test.go new file mode 100644 index 000000000000..f7cd21d77819 --- /dev/null +++ b/selfservice/strategy/oidc/provider_google_test.go @@ -0,0 +1,55 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package oidc_test + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" + "golang.org/x/oauth2" + + "github.com/ory/kratos/internal" + "github.com/ory/kratos/selfservice/flow/login" + "github.com/ory/kratos/selfservice/strategy/oidc" + "github.com/ory/kratos/x" +) + +func TestProviderGoogle_Scope(t *testing.T) { + _, reg := internal.NewFastRegistryWithMocks(t) + + p := oidc.NewProviderGoogle(&oidc.Configuration{ + Provider: "google", + ID: "valid", + ClientID: "client", + ClientSecret: "secret", + Mapper: "file://./stub/hydra.schema.json", + RequestedClaims: nil, + Scope: []string{"email", "profile", "offline_access"}, + }, reg) + + c, _ := p.OAuth2(context.Background()) + assert.NotContains(t, c.Scopes, "offline_access") +} + +func TestProviderGoogle_AccessType(t *testing.T) { + _, reg := internal.NewFastRegistryWithMocks(t) + + p := oidc.NewProviderGoogle(&oidc.Configuration{ + Provider: "google", + ID: "valid", + ClientID: "client", + ClientSecret: "secret", + Mapper: "file://./stub/hydra.schema.json", + RequestedClaims: nil, + Scope: []string{"email", "profile", "offline_access"}, + }, reg) + + r := &login.Flow{ + ID: x.NewUUID(), + } + + options := p.AuthCodeURLOptions(r) + assert.Contains(t, options, oauth2.AccessTypeOffline) +}