23

I'm using JWTs for user auth in a web application. I have a user db where each user's unique ID is their email address. To identify the subject of the JWT, I currently have a claim which stores the user's email address in the token. Does that pose a security problem? If so, should I be using a GUID or a hash of the email address as an ID?

Mike Harris
  • 572
  • 3
  • 12
Justin Borromeo
  • 401
  • 1
  • 4
  • 6
  • It's not a security problem, if you do not mind potential leak of emails of your user base, however, there could be a problem with having an email as a unique identifier of a user within your system. I have seen it like 10 times, where email was used for unique identification and the business has decided to provide other means of authentication. If you can, prepare for that by using artificial identifier right from the get go. – Andy Sep 07 '17 at 06:53
  • 1
    Agreed. Here (Spain) happens something similar with systems that use the Identification document (DNI). There's a false assumption that these are unique and identify unequivocally one person. But that's not true. There could be more than one person with the same DNI. The additional overhead of using emails is *what happens if users want to change the email*. In any case, JWTs are agnostic to these concerns, they are just a container of data. – Laiv Sep 07 '17 at 06:58

3 Answers3

21

Yes, it is bad practice and a security problem.

Email addresses are PII (personally identifiable information). Like all other PII, email addresses should never be stored unencrypted at rest; doing so is inherently insecure.

If your JWTs are going to be stored at rest anywhere - such as a database, or local or session storage in the browser - then you should not use any claims in your JWT that expose PII.

The fact that email is a registered IANA JWT claim is beside the point - so are given_name, middle_name, family_name, birthdate, phone_number, and address, but that's all PII too.

alexwebb2
  • 325
  • 2
  • 4
  • 3
    This should be the correct answer. I would add that `sub` is a better identifier & gives the flexibility to change/update email addresses (e.g. johnd@example.com -> jdoe@example.com) – asr9 Apr 09 '20 at 18:16
  • If JWTs are leaking then you already have something much worse than leaking personal information IMO. JWTs might be used for impersonating the user unless multiple other countermeasures are taken (e.g. IP-bound session + XSRF). I DON'T recommend storing email addresses in JWTs either, but mostly for the other reasons mentioned. – Gábor Imre May 27 '21 at 11:41
  • @GáborImre Live JWTs falling into the wrong hands is bad, but hopefully you've got mechanisms in place for global signout with a denylist at both the user level ("I think my account's been compromised, please invalidate all my sessions") and the global level (a big red button). With a bit of foresight those are things you can solve immediately if they come up. – alexwebb2 Jun 03 '21 at 12:30
  • @alexwebb2 Yeah, you can prevent some damage the way you described too. But it's already about damage control; my point was that leaking PII this way is not a big issue -- it's already much worse if we got to this point. – Gábor Imre Jun 09 '21 at 08:52
16

The short answer is no. There should not be any problem because email is a valid and registered public claim.

I have a user DB where each user's unique ID is their email ...

Well, there's a protected claim for users' ID. The claim sub.

4.1.2. "sub" (Subject) Claim

The "sub" (subject) claim identifies the principal that is the subject of the JWT. The claims in a JWT are normally statements about the subject. The subject value MUST either be scoped to be locally unique in the context of the issuer or be globally unique. The processing of this claim is generally application specific. The "sub" value is a case-sensitive string containing a StringOrURI value. Use of this claim is OPTIONAL.

Perhaps, it would be more appropriated to use the claim sub instead of email because in your system the email is an ID and probably you want to treat as such regardless the format.

That said, nothing prevents you from implementing both sub and email. That's application-specific too.

From the security point of view, the main concerns should be at implementing the TLS (https) and the sign/encrypt of the token.

Laiv
  • 14,283
  • 1
  • 31
  • 69
  • 1
    A customer wants to implement an SSO with JWT tokens for their legacy internal websites. Now, when a website receives a JWT, it has `sub` with ID that is unique in the context of the issuer and the website cannot find a user in its local database for the `sub`. We could send login username as `sub`, but some accounts don't have a username at all because they authenticate through Active Directory and have AD UIDs instead. So, we might send "username|AD_GUID" as `sub` to identify the user in website's local database by username or adguid. It looks dirty. I'm still looking for a clean solution. – JustAMartin Jul 31 '19 at 14:57
  • 1
    Add claims. Those you need, It will make things cleaner. You can send as many id as you need in diferent claims. Just make sure theres no claims' collision among systems – Laiv Jul 31 '19 at 17:58
4

It's commonplace to store a user's e-mail address in a token.

The properties of said e-mail address are up to the identity provider (is it unique, can it be changed etc.)

A few scenarios which are potentially insecure are a user changing their e-mail address and another user then taking up that e-mail address. Or a user deleting their account and re-creating that account under the same e-mail address. There is also a risk of an admin inadvertently unchecking the "enforce unique e-mail addresses" checkbox in the identity provider's configuration (if present)

You would also be mindful of this e-mail address leaking PII into logs and reporting.

When using an UUID or other non-guessable, stable identifier most of these issues are avoided. When a new account is created it receives a new UUID thus becomes a new identity whereas the e-mail address can be changed and it will stay the same identity.

Martin K
  • 2,867
  • 6
  • 17