Mapping claims from JWT to a Discourse User via login plugin

So been trying to find an SSO plugin that allows me to leverage the claims coming from my IdP for my Discourse Users.

In OIDC plugin you are pretty much locked to the userinfo endpoint. That’s not bad, but I was trying to use other info from our identity store and the userinfo result can’t be adjusted. I had tried to force OIDC plugin to use the id_token_info to fabricate the user, but no luck.

I jumped back to the oauth plugin, but on the surface it looks to have the same basic restriction which is it depends on user information from a specific endpoint. Working to see if I can find one that returns the content of the JWT claims, but that’s not really a normal use case so not expecting much.

I originally thought that the “callback userinfo paths” on the oauth basic could be used to map the claims into the User, but always seem to get nulls in the response and failed insert. I can decode the token from the IdP and see the correct claims and in this case at the root of the JSON like like iss, exp, etc, but can’t connect them to the ActiveRecord side.

I am looking at jwt but it doesn’t seem to have the mapping of claims to user at all. Basically if you get a 200 you are good which isn’t what i was looking for either.

I also found omniauth-jwt](GitHub - discourse/discourse-omniauth-jwt: An OmniAuth strategy that uses JSON Web Token for Single Sign-On) which seems to be closer to my goal though doesn’t look to be a plugin nor actively maintained. Something maybe I could fix, but a bigger bite than i was hoping to take.

Anyone point me in a direction for a currently maintained plugin to map JWT claims to a User or where I might be going wrong with one of the existing plugins?

I don’t have any idea, but what I’d do is get GitHub - discourse/all-the-plugins and grep for OmniAuth. That’ll give you a bunch of plugins that useThat gives you GitHub - discourse/discourse-jwt: Discourse Auth support for JSON Web Tokens (JWT), which might be what you’re looking for.

Yup already swung through that one.

Unless I am just extra dull today it only covers auth with fixed attributes. No way to do a claim mapping that I could find. If I were to fork something that would likely be where I started, but wanted to make sure I was not missing something obvious out there.

1 Like

And just to add a bit more context for folks who stumble on this topic.

The OAuth basic does seem to only support sourcing attributes from a defined user data endpoint and does not support mapping JWT claims. So it’s similar to the OIDC plugin, but instead of the userinfo location provided by discovery doc you can target any JSON endpoint and then mapping by path. Adding in the settings for including auth in header and you can get to places like which we use for Entra based OAuth.

Now Entra ID offers some extensibility for core objects, but it’s not as easy as tacking on an optional claim and it would be a global change from what I see. So not sure it’s a real option for us. Stepping even further back the maturity path and just doing the JWT plugin seems like the only path, but it would require some PR work to add claims mapping support. Basically in the same fashion that the existing oauth2-basic allows for customizing the mapping of the Discourse field to a JSON attribute it would need to allow for more customization of field to JWT claims.

Now that is a path for us, but I ran into a different issue that i think stops it all in its tracks.

After getting oauth2-basic working it prompts for a new user and sees there is an existing user using the email from the existing OIDC plugin use. Even though they share the same mail attribute I think it can’t move between providers for the same Discourse user. Having everyone start from scratch isn’t a real option and while I could probably hack in a migration of an oauth provider record in user_associated_accounts form an oidc provider feels like I am just asking for trouble. So even if JWT had the claims mapping support all the existing Users are pinned to the OIDC provider without some database shenanigans or building an “existing user” handler to allow changing associated account it seems like you are stuck.

That’s odd. It should match the email address and connect to the same account it would seem. The oauth logins work that way.

I had hoped that they would link up either by allowing >1 user_associated record per Discourse user (per provider_id) or a “linking” prompt to allow switching from one provider to a new provider. In my testing that was not the case though and it just notes the email as in use and prompts to create a new User.

If I was staying on the same plugin I am sure it would be seamless, but in this case they are unique provider ids each with their own metadata.