Auth0 Home Blog Docs

Change subject in id token by rules

id_token
rules
#1

The following rule doesn’t work for changing the subject in id tokens

function (user, context, callback) {
if (context.connection === ‘Username-Password-Authentication’) {
context.idToken[‘sub’] = ‘anapalan|’ + user.email;
}

callback(null, user, context);
}

any help?

1 Like
#3

To my knowledge that is something that is simply not supported; what is the use case around that requirement?

#4

Our team has found it to be incredibly frustrating that Auth0 automatically prefixes the sub value with auth0|, even when using a custom database. Our users are not stored in the database as auth0|12345– they are stored as simply 12345. So now the token is useless for referencing a user in our database. We have to (1) check the sub every time and strip the provider prefix if (and only if) it’s auth0, or (2) include a custom claim and only use that… Which in my opinion defeats the purpose of even having a sub claim (and makes social logins harder to implement). Both options are ugly.

Is there no way around this? I’ve tried inserting users into our custom database with the prefix already added, but that results in something like auth0|auth0|12345.

What is the convention for dealing with actual user IDs? Surely I’m missing something.

#5

I understand the source of frustration although to be honest I think it’s almost a necessity (more of this later). In relation to workarounds, I’m afraid there’s currently no way to change the subject claim from rules and I would also personally not recommend using the approach of parsing the user identifier so I would prefer an explicit custom claim.

The reason I think this is a necessity is that if you’re moving from an application that implemented its own authentication then there was not really any boundary between a user identity record and the application data of users. In other words, you would likely have this in a single database and application data (tables) would link directly to user data hence a tight coupling with whatever you choose to be the primary key of the user table.

If you move to a system where user identities are behind an identity provider you are decoupling authentication from the application itself, but you need to accept that although decoupling will provide you certain benefits and additional flexibility it will also have its constraints and may introduce some additional overhead.

In conclusion, you should treat user identifiers coming from the identity provider as an opaque value that uniquely identifier the user and in this way the specific method with which they authenticates is mostly irrelevant to the application. However, this is easier when applied to a new system; if you’re migrating from an existing system where authentication was coupled with the application you may need to have additional logic for existing users and on recommendation would indeed be a custom claim that can communicate a legacy identifier to the application.

1 Like
#6

Thank you for the detailed and very quick response. I appreciate it.

I can kind of understand that line of reasoning… But I am trying to treat the user sub as an opaque value-- it’s Auth0 that is adding the prefix and forcing me to find workarounds. But I suppose it’s my lack of experience in this area that’s causing the confusion and frustration.

if you’re migrating from an existing system where authentication was coupled with the application you may need to have additional logic for existing users and on recommendation would indeed be a custom claim that can communicate a legacy identifier to the application.

So if I’m understanding correctly, it would be ideal for me to store authentication data and user data in completely separate tables. Then Auth0 would mangle the ID from my authentication table after login, and that mangled ID would be the one used as a key in the user data table. Is that right?

#7

I agree with your observation that our use of human-readable prefixes and the possibility for an integration to control parts of the identifier end up leading to implementations that take advantage of this fact and parse user identifiers to extract additional information.

I can informally let you know that I’m aware that ideally we would prefer to have different type of identifiers being generated and ones that would not lend itself to allow the above, but to be honest, this is unlikely to happen in the short term as it would be a considerable change.

Having said that, even though something is possible (parse identifiers) does not mean it we should do it and that’s what I was referring to with the use of a custom claim. In other words, if you currently have a custom database that leads to identifiers such as auth0|[internal_id] my recommendation would be that if you need [internal_id] to be surfaced to client applications then in your custom database connection return that identifier in a way it is stored in user metadata and then use a rule to expose it to client applications.

The benefit of the above is that if you use a custom claim like https://app.example.com/internal_id to convey that information your implementation is much more explicit and more robust to changes.

In relation to how your system represents data at the database level, it depends, I was not trying to insinuate that you would have to have a specific set of tables. However, it’s likely that the database schema for a system that has authentication coupled into it can be slightly different than a system where authentication is externalized.

My main recommendations/points were:

  • treat Auth0 user identifiers as opaque even if they can technically be parsed to extract/infer other information.
  • be prepared to have some overhead/changes if you are moving a system where authentication was proprietary to a system where authentication is externalized.
#8

@jmangelo, I’m having a similar issue that OP is having, and have a hard time getting my head around the opaqueness of the sub field as well.

I am developing a new system where administrators would be creating user accounts for the users (either by invitation, or by actually creating the user, this is TBD). Now in the application DB it would be

What are your recommandations for a new system it would be confortable to key the user accounts by email address, because that how the admins invite people, and that’s what users will use to log in (we’re not planning on using social login at the moment, although that may pop up as a requirement later). It’s also easier to say that use did this or that, rather than user did this or that (although yeah, that is just presentation, but it’s easier to follow when debugging).
When creating the user account specific metadata for the user needs to be created in the application database (permissions, a few resources for the new user, etc). And at this point we have no idea what the opaque value of the sub field will be when the user actually logs in through auth0. [Using the email address as sub would solve this issue], so we can’t key the users table with the auth0 opaque value, although as far as I’m reading your replies, neither should we.

So to the actual question:

What are your recommendation on how to pair up an internally generated user primary key (in this case the email address) to an incoming sub claim? The whole reason for using jwt tokens would be that we can validate them “offline”, without making an additional http request to auth0 for each request. Possibly keep a lookup table from sub -> user id, and only retrieve the email from the userdata endpoint when a new value is encounetered? Or the sub identifiers guaranteed to be stable?

What are the guarantees around these sub fields? Will they change for any reason? What happens when a social login is added for the user? Will the sub field be different based on which login method he used? (user/pass vs social). If the social login contains the same email address, then using the raw email would solve the issue, but that is not always the case.
Is there any good documentation on how auth0 handles multiple logins for the same user?

Now if the sub field should be treated as an opaque value,