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

Add optional token_endpoint to IdP config #584

Closed
aaronpk opened this issue May 15, 2024 · 4 comments
Closed

Add optional token_endpoint to IdP config #584

aaronpk opened this issue May 15, 2024 · 4 comments

Comments

@aaronpk
Copy link

aaronpk commented May 15, 2024

As I've been working on profiling this for OAuth/OIDC, in particular with IdP registration (#240), I encountered the need to include the OAuth token endpoint in the IdP config.

The flow is as follows:

  • RP calls navigator.credentials.get with configURL: any
  • IdP returns an OAuth authorization code in the response (instead of an ID token)
  • RP sends the authorization code to its server
  • RP's server exchanges the authorization code for an access token and ID token at the IdP's token endpoint

The nice thing about doing it this way is it means we don't need to use a signed format for the token in the response from the FedCM API, since the RP never actually has to parse that value. It also means the JS code in the RP can send this value to its server, and the actual user data is transferred server-to-server, so it can be used with less validation too.

However, the problem arises in IdP registration mode, where the RP is not preconfigured with the IdP's information. The FedCM API returns the IdP's configURL in the response at the same time that it returns the authorization code, which is the first time the RP knows anything about which IdP was used. So we need to be able to go from the FedCM configURL to the token endpoint.

My solution was to extend my IdP config to include the IdP's token endpoint with a new parameter token_endpoint. An alternative would be to rely on the OAuth Server Metadata spec, which uses a .well-known path for the OAuth server metadata, however that still leaves the missing piece of going from the FedCM configURL to the OAuth issuer URL which is used for discovery, so I don't think that actually solves anything. Plus then you're more limited in use cases because of the .well-known requirement. So I like the simpler solution of including the token endpoint in the config.

@npm1
Copy link
Collaborator

npm1 commented May 15, 2024

Oh interesting. Are you suggesting we add this optional parameter in the config URL and then perhaps include it directly from IdentityCredential so that the RP knows where to exchange the token they receive from FedCM right away? This seems reasonable to me, and fairly simple for the browser to do. The naming is a bit tricky though since we'd want to make sure it is clearly different from the ID assertion endpoint, which in turn used to be called the token endpoint

@samuelgoto
Copy link
Collaborator

Ha, that's an interesting proposal indeed.

As I've been working on profiling this for OAuth/OIDC
However, the problem arises in IdP registration mode, where the RP is not preconfigured with the IdP's information.

Speaking of profiling OAuth/OIDC, have you considered an alternative design where you make the IdP return an agreed upon JSON object that contains both the code as well as the token_endpoint in the token response of the id_assertion_endpoint?

For example:

const credential = await navigator.credentials.get({
  identity: {
     providers: [{
       configURL: "any"
     }]
  }
});

const {code, endpoint} = JSON.parse(credential.token);

// RP now knows where to send the code to

Wouldn't that work?

The naming is a bit tricky though since we'd want to make sure it is clearly different from the ID assertion endpoint

Something I'm pondering is that the token_endpoint is an endpoint that the RP's server needs, but that it is never used by the browser, as opposed to every other endpoint. It also seems like an endpoint that it OAuth-specific, in that I'm guessing other protocols like SAML wouldn't use.

I guess, what I'm trying to get to, is that maybe we need something like w3c-fedid/custom-requests#2 , but passing arbitrary data from the configURL to the RP (e.g. an extensible params property in the config file )?

@aaronpk
Copy link
Author

aaronpk commented May 15, 2024

The token endpoint is definitely OAuth-specific.

In my implementation I'm using a server backend, but if the OAuth client was in the browser, as with a full SPA, then the browser would need the token endpoint.

const {code, endpoint} = JSON.parse(credential.token);

I wouldn't want to return the endpoint directly, because that means my server has an endpoint that will accept an arbitrary string and a URL and POST the string to the URL, without being able to confirm that the URL is actually an OAuth token endpoint. So I like the added step of doing some discovery to find the token endpoint so that I know I'm at least about to post it to an OAuth server and not something else.

But you're right, I could return the OAuth server metadata URL in this response and that would be sufficient for both SPA and server apps.

@aaronpk
Copy link
Author

aaronpk commented May 15, 2024

Update: ok that worked fine. I don't love the JSON.parse there, it just feels wrong. But it does work, and I don't know if it's actually any better moving that parse into the browser instead, but that feels cleaner. You could think of it as allowing the IdP to return arbitrary JSON to the RP, then you wouldn't have to name the field token at all.

Closing this in favor of #578.

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

No branches or pull requests

3 participants