Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UserInfo endpoint #376

Closed
NobodysNightmare opened this issue Mar 16, 2016 · 26 comments · Fixed by #1473
Closed

UserInfo endpoint #376

NobodysNightmare opened this issue Mar 16, 2016 · 26 comments · Fixed by #1473

Comments

@NobodysNightmare
Copy link

I am currently trying to get dex working in a ruby environment. On the RP side I am currently working with omniauth-openid-connect, which has some issues of its own.

However: Working around some of those initial issues, I am now stuck with omniauth-openid-connect trying to get additional claims from the userinfo endpoint, which is not implemented by dex.

In reading the OIDC specification, I failed to recognize whether this is a mandatory endpoint or an optional endpoint, but since it appears right away in section 1.3 of the spec, I would assume it is mandatory.

Are there any plans on implementing this endpoint?

If not, I might start working on it, but that depends on a number of other factors and it would be my first larger golang contribution anywhere, not to mention that I have barely read enough of the specs...

@ericchiang
Copy link
Contributor

It's recommended, not mandatory:

userinfo_endpoint
RECOMMENDED. URL of the OP's UserInfo Endpoint [OpenID.Core]. This URL MUST use the https scheme and MAY contain port, path, and query parameter components.

https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata

We currently add additional claims to the ID Token. For example:

{
  "aud": "example-app",
  "email": "elroy77@example.com",
  "exp": 1458191394,
  "iat": 1458148194,
  "iss": "http://127.0.0.1:5556",
  "name": "Elroy Jonez",
  "sub": "elroy-id"
}

But yes, we should absolutely have a userinfo endpoint.

@chancez
Copy link
Contributor

chancez commented Mar 31, 2016

I was just thinking today how the UserInfo endpoint would be useful for some integrations on account.tectonic.com. Particularly for syncing user accounts to other services.

@ericchiang
Copy link
Contributor

This would actually be really easy, since we currently use the ID Token as the access token[0]. We'd just decode that for the user.

[0] https://github.com/coreos/dex/blob/2d5fb0b47a3150d4fb2696f0736c12ee57d72ba7/server/http.go#L495-L500

@ghost
Copy link

ghost commented Nov 23, 2016

Is this still planned? I would like to see this implemented before 2.0 gets final.

@ericchiang
Copy link
Contributor

ericchiang commented Nov 23, 2016

Is this still planned?

This isn't since all information we'd return with a userinfo endpoint is already returned in the id_token.

Also, right now nothing uses the access_token returned by dex v2 (it's actually just a random string), so implementing this requires some design around what an access_token is internally to dex.

I understand that their are clients that require this optional endpoint, but it's not a high priority for us.

@ericchiang
Copy link
Contributor

Proposal:

Let's backpack off the proto types add for refresh tokens in #757 to implement an access token. The token will look like:

message AccessToken {
    string subject = 1;
    string name = 2;
    string email = 3;
    bool email_verified = 4;

    // Time at which the access token expires, represented as a unix time.
    //
    // This is the same value as the id_token.
    int64 expiry_unix = 5;
}

The access token fields will be filled out by the Claims in the AuthCode struct[0].

The access token struct will be serialized, then signed as a JWS using the signing keys maintained by dex, and returned as the "access_token" payload. When a user hits the userinfo_endpoint the key ID of the JWS is used to lookup the internal key, which is verified then used to form the userinfo_endpoint response.

On a refresh, the new access_token is returned.

We also may consider using ECDSA keys if the signature is significantly shorter.

Because access_tokens are opaque to the end user, we can internalize this logic later if we need to if the access_token gets too big.

[0] https://godoc.org/github.com/coreos/dex/storage#AuthCode

@chancez
Copy link
Contributor

chancez commented Jan 10, 2017

Seems like a great approach. This is almost exactly what the OIDC spec recommends if your attempting to build a stateless OIDC provider too.

@ericchiang
Copy link
Contributor

We also might consider encrypting the token instead of signing it. Just to make sure no one tries to rely on our access_token format.

@estroz
Copy link
Contributor

estroz commented Aug 23, 2017

A userinfo endpoint is required to pass the basic OpenID Connect Conformance Profile to achieve certification.

Certification issue: #42

@thomaschaaf
Copy link

I am trying to use dex with spinnaker and it needs the userInfoUri endpoint. Without this it's not possible to use dex with it.

See https://www.spinnaker.io/setup/security/authentication/oauth/#bring-your-own-provider

@lazypower
Copy link

Same w/ anyone attempting to integrate with Centrify. Centrify doesn't include any of the expected data in that id_token JWT. The expectation is that you will call the userinfo endpoint to gain the detail you are looking for.

details here: https://docs.centrify.com/en/centrify/appref/index.html?version=1507675723#page/cloudhelp%2Fgen%2FSAML-gen-OpenID.2.html

@fjbsantiago
Copy link
Contributor

fjbsantiago commented Oct 19, 2017

The same issue happens when integrating with the GenericOAuthenticator module used by JupyterHub for OpenID Connect authentication.
It also expects the Userinfo endpoint on the provider to exist to fetch user details.

@stapelberg
Copy link
Contributor

I am trying to use dex as an authentication provider with GitLab, and the omniauth-openid-connect gem which GitLab uses requires the userinfo endpoint as well.

I understand the philosophical standpoint that all information should be taken from the token, but at the same time, it seems like this stanza prevents using dex with a wide variety of software, which is a real shame.

Please consider the pragmatic solution of implementing the userinfo endpoint. Thank you!

@rithujohn191
Copy link
Contributor

Will work on this in the upcoming weeks and submit a proposal for review

@stapelberg
Copy link
Contributor

That’s great news! Thank you.

@fjbsantiago
Copy link
Contributor

fjbsantiago commented Oct 25, 2017

@rithujohn191 I forked Dex and successfully implemented the User Info endpoint. I will share it as soon as I finish polishing it, but I will give some details on how it works.

Connectors of type oidc have a new configuration option userInfo where a user info endpoint for the OP can be provided. E.g.:

- type: oidc
  id: google
  name: Google
  config:
    issuer: https://accounts.google.com
    userInfo: https://www.googleapis.com/oauth2/v3/userinfo         <<<<<<
    clientID: $GOOGLE_CLIENT_ID
    clientSecret: $GOOGLE_CLIENT_SECRET
    redirectURI: http://127.0.0.1:5556/dex/callback
    hostedDomains:
    - $GOOGLE_HOSTED_DOMAIN

How it works technically:

  1. Once the user is authenticated with the OP, Dex receives an Access Token
  2. Dex stores this token and generates a random token that will be forwarded to the Relying Party (client). This random token is also used as the ID to identify the object that contains the real token in future requests.
  3. The random access token is then sent to the RP instead of the real access token
    • This forces the RP to use dex for all requests that require the access token
  4. The RP uses this token to make a User Info request to Dex
  5. Dex receives the random access token
  6. Dex uses the random access token to find the real Access Token stored in step 2
  7. Dex uses the real token to make a user info request to the configured userInfo endpoint of the OP
  8. Dex returns the result to the RP

Note: I did not consider token refresh.

This has only be tested with the generic OAuthenticator plugin of Jupyterhub which uses a basic OAuth2 flow.

@markuslindenberg
Copy link

@fjbsantiago Does your implementation also work with other connectors like LDAP?

@fjbsantiago
Copy link
Contributor

fjbsantiago commented Oct 26, 2017

@markuslindenberg Sorry, but I only implemented this for Open ID Connect connectors, unfortunately.

@ericchiang
Copy link
Contributor

Just a heads up. Any dex user info implementation we add to dex will work with any backing connector (LDAP, SAML, GitHub, etc), not just with OpenID Connect.

@fjbsantiago
Copy link
Contributor

I have another quick question @ericchiang.

Some OPs return different kinds of claims from the userinfo endpoint like, for example, birth date and gender.
Will these claims be lost if you implement the Access Token as per your proposal?

@fjbsantiago
Copy link
Contributor

@NobodysNightmare I wrote an implementation for the UserInfo endpoint. It is currently pending as a pull request.

It would be nice if you could try it to see if it solves your issue with omniauth-openid-connect, unless you already found a workaround.

@hardbone12
Copy link

@fjbsantiago I have made a simple test of your code as openshift(kubernetes) auth provider

As i reviewed openshift openid plugin code
https://github.com/openshift/origin/blob/9a9a948e55f943e1aa2cff3965a7545f7809a380/pkg/auth/oauth/external/openid/openid.go#L187
and
http://openid.net/specs/openid-connect-core-1_0.html#UserInfoResponse

I think the subject in AccessToken should be the same as in id_token
https://github.com/coreos/dex/pull/1133/files#diff-105fedf355a9fcad82982745cef24f7aR1055

@jackielii
Copy link
Contributor

@hardbone12 rolled my own, borrowed mostly from @fjbsantiago , fixed the subject issue

@gcavalcante8808
Copy link

Hey Folks, any news on this?

@pdhung
Copy link

pdhung commented Nov 7, 2018

Since I am not familiar with all flows and OIDC specifications, I have some dummy questions:

  • If I use a refresh token to request a new id_token, will the IdPs, who support offline_access, issue me new claims that reflect the changes in IdP (like changed groups, changed name etc)
  • If yes, then which url should I post request to? My guess is /token.
  • Which struct and format should I send to /token?
  • As I understand, the UserInfo endpoint discussed here is used for get the up-to-date info (new claims) from IdPs while not having refresh_token (like SAML) but having valid access_token ((in dex, i suppose access_token == id_token). Is it right?
  • Is there any plan to implement the UserInfo endpoint?

@mdbraber
Copy link
Contributor

mdbraber commented May 27, 2019

I've created a PR which adds userinfo_endpoint based on the current code and the previous PR from @jackielii #1454. Also available as a Docker image from https://hub.docker.com/r/mdbraber/dex

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.