authts / oidc-client-ts

OpenID Connect (OIDC) and OAuth2 protocol support for browser-based JavaScript applications
https://authts.github.io/oidc-client-ts/
Apache License 2.0
1.33k stars 197 forks source link

InvalidTokenError: Invalid token specified: missing part #2 #1643

Closed shadowfoxish closed 1 week ago

shadowfoxish commented 2 weeks ago

I've created an IdP/sso server using OpenIddict, and I'm integrating the login mechanism into my React site.

I'm stuck on this problem and I can use some advice.

[JwtUtils.decode] InvalidTokenError: Invalid token specified: missing part #2

Basically, my SSO server is sending an access token in the /connect/token call, and the token looks "normal" in there, but, importantly I haven't put claims in it. (I was expecting the introspection endpoint or userinfo endpoints to be called, but the process isn't getting that far).

Everything leading up to this point seems to be working correctly, on Sign-In request, the site redirects to the SSO server, user authenticates/logs in, then is redirected back to the website with the /?code=blah bits attached. Then, there's a call made to the .well-known endpoint. Then there's a call to the sso's /connect/token endpoint, and the access_token is returned in the response, with token type of "bearer". The token is a 3 part format, [header].[token].[signature] , Thats when the InvalidTokenError happens, and the rest of the sign in process fails.

There's kind of 2 paths to take, both of which I'm having problems getting past. Path 1) How can I tell oidc-client-ts to tell jwt-decode there's a header part of this token? jwt-decode has a second method parameter which controls where it looks for the token data. _I'd love to be able to print some debug code JwtUtil or jwt-decode to understand what its actually finding as the accesstoken, and I tried npx patch-package, but my JS chops are not up to snuff I guess, or the method I'm patching isn't coming from the places I've tried to modify.

Path 2) Since the token itself doesn't contain the claims anyway, how can I tell oidc-client-ts not to bother trying to read the access_token and use userinfo or introspection instead to get them?

Maybe there's something else I missed with how this is supposed to work.

This is the /.well-known/openid-configuration response:

{
  "issuer": "https://localhost:7179/",
  "authorization_endpoint": "https://localhost:7179/connect/authorize",
  "token_endpoint": "https://localhost:7179/connect/token",
  "introspection_endpoint": "https://localhost:7179/connect/introspect",
  "end_session_endpoint": "https://localhost:7179/connect/logout",
  "userinfo_endpoint": "https://localhost:7179/connect/userinfo",
  "jwks_uri": "https://localhost:7179/.well-known/jwks",
  "grant_types_supported": [
    "client_credentials",
    "authorization_code",
    "password",
    "refresh_token"
  ],
  "response_types_supported": [
    "code"
  ],
  "response_modes_supported": [
    "form_post",
    "fragment",
    "query"
  ],
  "scopes_supported": [
    "openid",
    "api",
    "email",
    "profile",
    "roles",
    "offline_access"
  ],
  "claims_supported": [
    "aud",
    "exp",
    "iat",
    "iss",
    "sub"
  ],
  "id_token_signing_alg_values_supported": [
    "RS256"
  ],
  "code_challenge_methods_supported": [
    "plain",
    "S256"
  ],
  "subject_types_supported": [
    "public"
  ],
  "token_endpoint_auth_methods_supported": [
    "client_secret_post",
    "private_key_jwt",
    "client_secret_basic"
  ],
  "introspection_endpoint_auth_methods_supported": [
    "client_secret_post",
    "private_key_jwt",
    "client_secret_basic"
  ],
  "claims_parameter_supported": false,
  "request_parameter_supported": false,
  "request_uri_parameter_supported": false,
  "authorization_response_iss_parameter_supported": true
}
shadowfoxish commented 2 weeks ago

Update: I managed to get a debug statement in there, and the token its trying to decode is empty string. I'm continuing to dig..

shadowfoxish commented 2 weeks ago

Okay, the IdP wasn't returning the id_token. That's the primary problem. I do think the error being returned here could be cleaned up though.

https://github.com/authts/oidc-client-ts/blob/5edbb90735a3fa627b76be55f9eea50e67212b1f/src/ResponseValidator.ts#L198 const incoming = JwtUtils.decode(response.id_token ?? "");

The ?? "" implies the id_token can be blank, but that leads to an error being thrown. Maybe a quick check like this right before would be helpful?

    if(!response.id_token) { 
         logger.throw(new Error("ID Token is missing"));
    }
pamapa commented 1 week ago

I guess we leave it as is, after all you were able to spot the error and the code behaved correctly.

shadowfoxish commented 1 week ago

Agreed. If someone else encounters the same error, they'll be able to find this thread and resolution.

I've been building an IdP and some things in that implementation are still firming up.