ramosbugs / openidconnect-rs

OpenID Connect Library for Rust
MIT License
404 stars 100 forks source link

400 error on code -> token exchange #155

Closed dakom closed 6 months ago

dakom commented 6 months ago

In a wasm environment, I am getting an error when it gets to the client.exchange_code() token exchange part.

Following the Google example from the readme, and looking at the traffic between my server and Google, I noticed the redirect_uri was missing.

So I added a call to .set_redirect_uri(), which isn't in the example, but I am now getting a redirect_uri_mismatch error - even though I've added this new redirect to the console too.

From looking at the docs, it seems that client_id and client_secret are supposed to be attached to this request... could that be the problem?

docs: https://developers.google.com/identity/protocols/oauth2/web-server#exchange-authorization-code (under HTTP/REST tab)

dakom commented 6 months ago

related: https://github.com/ramosbugs/openidconnect-rs/issues/126

dakom commented 6 months ago

update, from looking at that other issue I've added .set_auth_type(AuthType::RequestBody)

also tried intercepting the body and turning it into UrlSearchParams

same results so far, error code 400 with redirect_uri_mismatch

dakom commented 6 months ago

uuuggghh... okay, my issue was solved by setting it to the same redirect_uri as the authorize_url() request.

I have no idea where that's documented... the google docs say:

One of the redirect URIs listed for your project [...]

Which, I'd think means it just needs to be, well, one of the uris listed there, so adding a new one for this step is fine. Evidently not, or it's a cache issue, or who knows what.

Hope that helps anyone else stumbling here, just use the same url and look for the query params to be different (e.g. presence of access_token)

Closing this issue, no problem in the Rust code at all :)

ramosbugs commented 6 months ago

Google is just following the behavior required by the spec:

REQUIRED, if the "redirect_uri" parameter was included in the authorization request as described in Section 4.1.1, and their values MUST be identical.

dakom commented 6 months ago

Thanks for pointing that out, and I should give the spec a look :)

Google should update their docs to match it too ;)

dakom commented 6 months ago

curious though, what's this actually used for? at this point in the flow there's no more redirection iiuc, the access token has been returned/extracted already?

ramosbugs commented 6 months ago

I think it's because if a client/app has multiple redirect URLs registered, they may not want people to take authorization codes issued to one of those redirect URLs and pass them to another (a substitution attack), which could have security consequences if those different redirect URLs correspond to different parts of an app with different levels of access (although I don't think it makes sense to use redirect URLs as a security boundary; separate client IDs would make a lot more sense). It functions similarly to the aud claim in the ID token to confirm that the authorization code was in fact intended for that audience (in this case identified by redirect URL). This is just a guess though.

dakom commented 5 months ago

followup question - now that I got Google working, trying to integrate Facebook.

I created an app, set up a test user account, added email / login use case, got app id and secret.

Now when I pop it in via the same core flow, I get "no token_url provided" on the token exchange part. Any ideas?

I see that it's trying to access https://www.facebook.com/.well-known/oauth/openid/jwks/, if that's a lead...

dakom commented 5 months ago

oh... I think it's the missing token_endpoint in facebook's discovery document?

comparing facebook: https://www.facebook.com/.well-known/openid-configuration/ to google: https://accounts.google.com/.well-known/openid-configuration

dakom commented 5 months ago

hrmf, some confirmation: https://github.com/nextauthjs/next-auth/issues/4608

fix here is just to manually patch it:

provider_metadata = provider_metadata.set_token_endpoint(Some(TokenUrl::new("https://graph.facebook.com/oauth/access_token".to_string())