From b03c85e56ee3871b819a2ea228a4c81b45d13905 Mon Sep 17 00:00:00 2001 From: Vy-Shane Xie Date: Tue, 23 Jan 2018 21:15:20 +0800 Subject: [PATCH] Add new federated:id scope that causes Dex to add a federated_claims claim containing the connector_id and user_id to the ID token --- Documentation/custom-scopes-claims-clients.md | 11 +++++++++++ server/oauth2.go | 15 ++++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/Documentation/custom-scopes-claims-clients.md b/Documentation/custom-scopes-claims-clients.md index 0c277016..877e7a57 100644 --- a/Documentation/custom-scopes-claims-clients.md +++ b/Documentation/custom-scopes-claims-clients.md @@ -12,6 +12,7 @@ The following is the exhaustive list of scopes supported by dex: | `email` | ID token claims should include the end user's email and if that email was verified by an upstream provider. | | `profile` | ID token claims should include the username of the end user. | | `groups` | ID token claims should include a list of groups the end user is a member of. | +| `federated:id` | ID token claims should include information from the ID provider. The token will contain the connector ID and the user ID assigned at the provider. | | `offline_access` | Token response should include a refresh token. Doesn't work in combinations with some connectors, notability the [SAML connector][saml-connector] ignores this scope. | | `audience:server:client_id:( client-id )` | Dynamic scope indicating that the ID token should be issued on behalf of another client. See the _"Cross-client trust and authorized party"_ section below. | @@ -22,10 +23,20 @@ Beyond the [required OpenID Connect claims][core-claims], and a handful of [stan | Name | Description | | ---- | ------------| | `groups` | A list of strings representing the groups a user is a member of. | +| `federated_claims` | The connector ID and the user ID assigned to the user at the provider. | | `email` | The email of the user. | | `email_verified` | If the upstream provider has verified the email. | | `name` | User's display name. | +The `federated_claims` claim has the following format: + +```json +"federated_claims": { + "connector_id": "github", + "user_id": "110272483197731336751" +} +``` + ## Cross-client trust and authorized party Dex has the ability to issue ID tokens to clients on behalf of other clients. In OpenID Connect terms, this means the ID token's `aud` (audience) claim being a different client ID than the client that performed the login. diff --git a/server/oauth2.go b/server/oauth2.go index 6a0d5eee..7967b1bc 100644 --- a/server/oauth2.go +++ b/server/oauth2.go @@ -107,6 +107,7 @@ const ( scopeGroups = "groups" scopeEmail = "email" scopeProfile = "profile" + scopeFederatedID = "federated:id" scopeCrossClientPrefix = "audience:server:client_id:" ) @@ -255,6 +256,13 @@ type idTokenClaims struct { Groups []string `json:"groups,omitempty"` Name string `json:"name,omitempty"` + + FederatedIDClaims *federatedIDClaims `json:"federated_claims,omitempty"` +} + +type federatedIDClaims struct { + ConnectorID string `json:"connector_id,omitempty"` + UserID string `json:"user_id,omitempty"` } func (s *Server) newIDToken(clientID string, claims storage.Claims, scopes []string, nonce, accessToken, connID string) (idToken string, expiry time.Time, err error) { @@ -313,6 +321,11 @@ func (s *Server) newIDToken(clientID string, claims storage.Claims, scopes []str tok.Groups = claims.Groups case scope == scopeProfile: tok.Name = claims.Username + case scope == scopeFederatedID: + tok.FederatedIDClaims = &federatedIDClaims{ + ConnectorID: connID, + UserID: claims.UserID, + } default: peerID, ok := parseCrossClientScope(scope) if !ok { @@ -405,7 +418,7 @@ func (s *Server) parseAuthorizationRequest(r *http.Request) (req storage.AuthReq switch scope { case scopeOpenID: hasOpenIDScope = true - case scopeOfflineAccess, scopeEmail, scopeProfile, scopeGroups: + case scopeOfflineAccess, scopeEmail, scopeProfile, scopeGroups, scopeFederatedID: default: peerID, ok := parseCrossClientScope(scope) if !ok {