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
This commit is contained in:
		| @@ -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. | | | `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. | | | `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. | | | `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. | | | `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. | | | `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 | | | Name | Description | | ||||||
| | ---- | ------------| | | ---- | ------------| | ||||||
| | `groups` | A list of strings representing the groups a user is a member of. | | | `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` | The email of the user. | | ||||||
| | `email_verified` | If the upstream provider has verified the email. | | | `email_verified` | If the upstream provider has verified the email. | | ||||||
| | `name` | User's display name. | | | `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 | ## 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. | 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. | ||||||
|   | |||||||
| @@ -107,6 +107,7 @@ const ( | |||||||
| 	scopeGroups            = "groups" | 	scopeGroups            = "groups" | ||||||
| 	scopeEmail             = "email" | 	scopeEmail             = "email" | ||||||
| 	scopeProfile           = "profile" | 	scopeProfile           = "profile" | ||||||
|  | 	scopeFederatedID       = "federated:id" | ||||||
| 	scopeCrossClientPrefix = "audience:server:client_id:" | 	scopeCrossClientPrefix = "audience:server:client_id:" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @@ -255,6 +256,13 @@ type idTokenClaims struct { | |||||||
| 	Groups []string `json:"groups,omitempty"` | 	Groups []string `json:"groups,omitempty"` | ||||||
|  |  | ||||||
| 	Name string `json:"name,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) { | 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 | 			tok.Groups = claims.Groups | ||||||
| 		case scope == scopeProfile: | 		case scope == scopeProfile: | ||||||
| 			tok.Name = claims.Username | 			tok.Name = claims.Username | ||||||
|  | 		case scope == scopeFederatedID: | ||||||
|  | 			tok.FederatedIDClaims = &federatedIDClaims{ | ||||||
|  | 				ConnectorID: connID, | ||||||
|  | 				UserID:      claims.UserID, | ||||||
|  | 			} | ||||||
| 		default: | 		default: | ||||||
| 			peerID, ok := parseCrossClientScope(scope) | 			peerID, ok := parseCrossClientScope(scope) | ||||||
| 			if !ok { | 			if !ok { | ||||||
| @@ -405,7 +418,7 @@ func (s *Server) parseAuthorizationRequest(r *http.Request) (req storage.AuthReq | |||||||
| 		switch scope { | 		switch scope { | ||||||
| 		case scopeOpenID: | 		case scopeOpenID: | ||||||
| 			hasOpenIDScope = true | 			hasOpenIDScope = true | ||||||
| 		case scopeOfflineAccess, scopeEmail, scopeProfile, scopeGroups: | 		case scopeOfflineAccess, scopeEmail, scopeProfile, scopeGroups, scopeFederatedID: | ||||||
| 		default: | 		default: | ||||||
| 			peerID, ok := parseCrossClientScope(scope) | 			peerID, ok := parseCrossClientScope(scope) | ||||||
| 			if !ok { | 			if !ok { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user