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:
parent
1dbecefadf
commit
b03c85e56e
2 changed files with 25 additions and 1 deletions
|
@ -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 a new issue