diff --git a/embedx/config.schema.json b/embedx/config.schema.json index 5fcf826f4c2a..8dd87a299a40 100644 --- a/embedx/config.schema.json +++ b/embedx/config.schema.json @@ -436,7 +436,7 @@ }, "provider": { "title": "Provider", - "description": "Can be one of github, github-app, gitlab, generic, google, microsoft, discord, salesforce, slack, facebook, auth0, vk, yandex, apple, spotify, netid, dingtalk, patreon.", + "description": "Can be one of github, github-app, gitlab, generic, google, microsoft, discord, salesforce, slack, facebook, auth0, vk, yandex, apple, spotify, netid, dingtalk, patreon, riotgames", "type": "string", "enum": [ "github", @@ -460,7 +460,8 @@ "linkedin", "linkedin_v2", "lark", - "x" + "x", + "riotgames" ], "examples": ["google"] }, diff --git a/selfservice/strategy/oidc/provider_config.go b/selfservice/strategy/oidc/provider_config.go index 92b16fdf5f42..a6cb30c13e28 100644 --- a/selfservice/strategy/oidc/provider_config.go +++ b/selfservice/strategy/oidc/provider_config.go @@ -39,6 +39,7 @@ type Configuration struct { // - dingtalk // - linkedin // - patreon + // - riotgames Provider string `json:"provider"` // Label represents an optional label which can be used in the UI generation. @@ -178,6 +179,7 @@ var supportedProviders = map[string]func(config *Configuration, reg Dependencies "lark": NewProviderLark, "x": NewProviderX, "jackson": NewProviderJackson, + "riotgames": NewProviderRiotGames, } func (c ConfigurationCollection) Provider(id string, reg Dependencies) (Provider, error) { diff --git a/selfservice/strategy/oidc/provider_private_net_test.go b/selfservice/strategy/oidc/provider_private_net_test.go index 0505a3e19626..b3280dcb46a7 100644 --- a/selfservice/strategy/oidc/provider_private_net_test.go +++ b/selfservice/strategy/oidc/provider_private_net_test.go @@ -86,6 +86,7 @@ func TestProviderPrivateIP(t *testing.T) { // Yandex uses a fixed token URL and does not use the issuer. // NetID uses a fixed token URL and does not use the issuer. // X uses a fixed token URL and userinfoRL and does not use the issuer value. + // Riot Games uses a fixed token URL and does not use the issuer. } { t.Run(fmt.Sprintf("case=%d", k), func(t *testing.T) { p := tc.p(tc.c) diff --git a/selfservice/strategy/oidc/provider_riotgames.go b/selfservice/strategy/oidc/provider_riotgames.go new file mode 100644 index 000000000000..e21aecc0cd49 --- /dev/null +++ b/selfservice/strategy/oidc/provider_riotgames.go @@ -0,0 +1,101 @@ +// Copyright © 2024 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package oidc + +import ( + "context" + "encoding/json" + "net/url" + + "github.com/hashicorp/go-retryablehttp" + "github.com/pkg/errors" + "golang.org/x/oauth2" + + "github.com/ory/herodot" + "github.com/ory/x/httpx" +) + +type ProviderRiotGames struct { + *ProviderGenericOIDC +} + +var ( + rsoAuthEndpoint = oauth2.Endpoint{ + AuthURL: "https://auth.riotgames.com/authorize", + TokenURL: "https://auth.riotgames.com/token", + AuthStyle: oauth2.AuthStyleInHeader, + } + rsoUserEndpoint = "https://auth.riotgames.com/userinfo" +) + +func NewProviderRiotGames( + config *Configuration, + reg Dependencies, +) Provider { + return &ProviderRiotGames{ + &ProviderGenericOIDC{ + config: config, + reg: reg, + }, + } +} + +func (rs *ProviderRiotGames) Config() *Configuration { + return rs.config +} + +func (rs *ProviderRiotGames) OAuth2(ctx context.Context) (*oauth2.Config, error) { + + return &oauth2.Config{ + ClientID: rs.config.ClientID, + ClientSecret: rs.config.ClientSecret, + Endpoint: rsoAuthEndpoint, + // Riot Games uses fixed scope that can not be configured in runtime + Scopes: rs.config.Scope, + RedirectURL: rs.config.Redir(rs.reg.Config().OIDCRedirectURIBase(ctx)), + }, nil + +} + +func (rs *ProviderRiotGames) Claims(ctx context.Context, exchange *oauth2.Token, query url.Values) (*Claims, error) { + // riotGamesClaim is defined in the https://beta.developer.riotgames.com/sign-on + type riotGamesClaim struct { + Sub string `json:"sub"` + Cpid string `json:"cpid"` + Jti string `json:"jti"` + } + var ( + client = rs.reg.HTTPClient(ctx, httpx.ResilientClientDisallowInternalIPs()) + user riotGamesClaim + ) + + req, err := retryablehttp.NewRequest("GET", rsoUserEndpoint, nil) + if err != nil { + return nil, errors.WithStack(herodot.ErrInternalServerError.WithReasonf("%s", err)) + } + + exchange.SetAuthHeader(req.Request) + res, err := client.Do(req) + if err != nil { + return nil, errors.WithStack(herodot.ErrInternalServerError.WithReasonf("%s", err)) + } + defer res.Body.Close() + + if err := logUpstreamError(rs.reg.Logger(), res); err != nil { + return nil, err + } + + if err := json.NewDecoder(res.Body).Decode(&user); err != nil { + return nil, errors.WithStack(herodot.ErrInternalServerError.WithReasonf("%s", err)) + } + + return &Claims{ + Issuer: rsoUserEndpoint, + Subject: user.Sub, + }, nil +} + +func (rs *ProviderRiotGames) AuthCodeURLOptions(r ider) []oauth2.AuthCodeOption { + return []oauth2.AuthCodeOption{} +} diff --git a/test/e2e/shared/config.d.ts b/test/e2e/shared/config.d.ts index 9f3d60368bc7..63796b69ad4a 100644 --- a/test/e2e/shared/config.d.ts +++ b/test/e2e/shared/config.d.ts @@ -233,7 +233,7 @@ export type SelfServiceOIDCProvider1 = { [k: string]: unknown | undefined } /** - * Can be one of github, github-app, gitlab, generic, google, microsoft, discord, salesforce, slack, facebook, auth0, vk, yandex, apple, spotify, netid, dingtalk, patreon. + * Can be one of github, github-app, gitlab, generic, google, microsoft, discord, salesforce, slack, facebook, auth0, vk, yandex, apple, spotify, netid, dingtalk, patreon, x, riotgames. */ export type Provider = | "github" @@ -258,6 +258,7 @@ export type Provider = | "linkedin_v2" | "lark" | "x" + | "riotgames" export type OptionalStringWhichWillBeUsedWhenGeneratingLabelsForUIButtons = string /**