From 9c21d32c37ae298d90a42b6234eb2d2e53eb24d8 Mon Sep 17 00:00:00 2001 From: Craig O'Donnell Date: Thu, 2 Nov 2023 10:31:25 -0400 Subject: [PATCH] support provider device_authorization_endpoint --- oidc/oidc.go | 63 ++++++++++++++++++++++++++--------------------- oidc/oidc_test.go | 16 ++++++++---- 2 files changed, 46 insertions(+), 33 deletions(-) diff --git a/oidc/oidc.go b/oidc/oidc.go index 6e2b0e56..b7db3c73 100644 --- a/oidc/oidc.go +++ b/oidc/oidc.go @@ -94,12 +94,13 @@ func doRequest(ctx context.Context, req *http.Request) (*http.Response, error) { // Provider represents an OpenID Connect server's configuration. type Provider struct { - issuer string - authURL string - tokenURL string - userInfoURL string - jwksURL string - algorithms []string + issuer string + authURL string + tokenURL string + deviceAuthURL string + userInfoURL string + jwksURL string + algorithms []string // Raw claims returned by the server. rawClaims []byte @@ -128,12 +129,13 @@ func (p *Provider) remoteKeySet() KeySet { } type providerJSON struct { - Issuer string `json:"issuer"` - AuthURL string `json:"authorization_endpoint"` - TokenURL string `json:"token_endpoint"` - JWKSURL string `json:"jwks_uri"` - UserInfoURL string `json:"userinfo_endpoint"` - Algorithms []string `json:"id_token_signing_alg_values_supported"` + Issuer string `json:"issuer"` + AuthURL string `json:"authorization_endpoint"` + TokenURL string `json:"token_endpoint"` + DeviceAuthURL string `json:"device_authorization_endpoint"` + JWKSURL string `json:"jwks_uri"` + UserInfoURL string `json:"userinfo_endpoint"` + Algorithms []string `json:"id_token_signing_alg_values_supported"` } // supportedAlgorithms is a list of algorithms explicitly supported by this @@ -165,6 +167,9 @@ type ProviderConfig struct { // TokenURL is the endpoint used by the provider to support the OAuth 2.0 // token endpoint. TokenURL string + // DeviceAuthURL is the endpoint used by the provider to support the OAuth 2.0 + // device authorization endpoint. + DeviceAuthURL string // UserInfoURL is the endpoint used by the provider to support the OpenID // Connect UserInfo flow. // @@ -185,13 +190,14 @@ type ProviderConfig struct { // through discovery. func (p *ProviderConfig) NewProvider(ctx context.Context) *Provider { return &Provider{ - issuer: p.IssuerURL, - authURL: p.AuthURL, - tokenURL: p.TokenURL, - userInfoURL: p.UserInfoURL, - jwksURL: p.JWKSURL, - algorithms: p.Algorithms, - client: getClient(ctx), + issuer: p.IssuerURL, + authURL: p.AuthURL, + tokenURL: p.TokenURL, + deviceAuthURL: p.DeviceAuthURL, + userInfoURL: p.UserInfoURL, + jwksURL: p.JWKSURL, + algorithms: p.Algorithms, + client: getClient(ctx), } } @@ -240,14 +246,15 @@ func NewProvider(ctx context.Context, issuer string) (*Provider, error) { } } return &Provider{ - issuer: issuerURL, - authURL: p.AuthURL, - tokenURL: p.TokenURL, - userInfoURL: p.UserInfoURL, - jwksURL: p.JWKSURL, - algorithms: algs, - rawClaims: body, - client: getClient(ctx), + issuer: issuerURL, + authURL: p.AuthURL, + tokenURL: p.TokenURL, + deviceAuthURL: p.DeviceAuthURL, + userInfoURL: p.UserInfoURL, + jwksURL: p.JWKSURL, + algorithms: algs, + rawClaims: body, + client: getClient(ctx), }, nil } @@ -273,7 +280,7 @@ func (p *Provider) Claims(v interface{}) error { // Endpoint returns the OAuth2 auth and token endpoints for the given provider. func (p *Provider) Endpoint() oauth2.Endpoint { - return oauth2.Endpoint{AuthURL: p.authURL, TokenURL: p.tokenURL} + return oauth2.Endpoint{AuthURL: p.authURL, DeviceAuthURL: p.deviceAuthURL, TokenURL: p.tokenURL} } // UserInfoEndpoint returns the OpenID Connect userinfo endpoint for the given diff --git a/oidc/oidc_test.go b/oidc/oidc_test.go index 8a813e3a..b19cac60 100644 --- a/oidc/oidc_test.go +++ b/oidc/oidc_test.go @@ -116,6 +116,7 @@ func TestNewProvider(t *testing.T) { trailingSlash bool wantAuthURL string wantTokenURL string + wantDeviceAuthURL string wantUserInfoURL string wantIssuerURL string wantAlgorithms []string @@ -205,11 +206,12 @@ func TestNewProvider(t *testing.T) { { // Test case taken directly from: // https://accounts.google.com/.well-known/openid-configuration - name: "google", - wantAuthURL: "https://accounts.google.com/o/oauth2/v2/auth", - wantTokenURL: "https://oauth2.googleapis.com/token", - wantUserInfoURL: "https://openidconnect.googleapis.com/v1/userinfo", - wantAlgorithms: []string{"RS256"}, + name: "google", + wantAuthURL: "https://accounts.google.com/o/oauth2/v2/auth", + wantTokenURL: "https://oauth2.googleapis.com/token", + wantDeviceAuthURL: "https://oauth2.googleapis.com/device/code", + wantUserInfoURL: "https://openidconnect.googleapis.com/v1/userinfo", + wantAlgorithms: []string{"RS256"}, data: `{ "issuer": "ISSUER", "authorization_endpoint": "https://accounts.google.com/o/oauth2/v2/auth", @@ -320,6 +322,10 @@ func TestNewProvider(t *testing.T) { t.Errorf("NewProvider() unexpected tokenURL value, got=%s, want=%s", p.tokenURL, test.wantTokenURL) } + if p.deviceAuthURL != test.wantDeviceAuthURL { + t.Errorf("NewProvider() unexpected deviceAuthURL value, got=%s, want=%s", + p.deviceAuthURL, test.wantDeviceAuthURL) + } if p.userInfoURL != test.wantUserInfoURL { t.Errorf("NewProvider() unexpected userInfoURL value, got=%s, want=%s", p.userInfoURL, test.wantUserInfoURL)