Introduction
As discussed in a previous blog post several high profile websites such as Booking.com, Kayak, and Grammarly have been affected by various issues relating to OpenID Connect (OIDC).
One of the most common is the use of the email
claim as a stable identifier when authenticating a user.
In this blog post we’ll discuss why this happens and how to do it safely when implementing SSO.
The origin of the issue
The OIDC specification clarifies that the only authoritative claims a resource server such as Google can provide are the sub
(Subject) and iss
(Issuer) claims. In particular, the spec states that the sub
must be locally unique and never reassigned within the OIDC Server/Issuer to a different user.
However, most issuers also include an email
claim in their ID tokens and many relying parties (RPs) use the email
address as a valid, unique claim. This happens for two reasons:
- Most companies want to associate an email address with a user, so taking advantage of the
email
claim decreases friction during sign-up - As for many complex protocols, very few developers read the full specification before implementing it
In this scenario what normally happens is that an account is created (or a user is authenticated into an account) in the RP server based on the email
claim.
The cost of getting it wrong
The ultimate issue here is the ability for an attacker to take over a victim’s account. Several examples of this have been shown in the wild, in the last year:
- Flickr using AWS Cognito: In this case an attacker could overwrite the
email
attributes on his account and impersonate another user since Flickr didn’t check theverified
field. - All apps using Sign-in with Microsoft until June 2023: In this case an attacker could create a fake tenant with an unverified email, impersonating any user and ultimately taking over the account in the vulnerable application.
The status of the email claim by provider
Fortunately, a number of high profile identity providers (IdPs) provide ways to check the validity of an email
for a user. Let’s see a few examples.
Google exposes an API to fetch the email address. The API documentation says that the email
field in the response is the Google user’s primary email address, which is always verified.
Microsoft
Microsoft has recently introduced a an optional claim xms_edov
(Email Domain Owner Verified) in the ID Token that indicates whether an email claim contains a domain-verified email address.
Further, and more safely, it is possible to use the removeUnverifiedEmailClaim
flag in the Graph APIs.
Okta
Okta provides an API to retrieve the email of a logged-in user, and the response includes an email_verified
value.
Apple
Apple includes an email_verified
claim in the ID token returned via OIDC.
Github
You can retrieve the email through the Github API using the access token obtained via OIDC, and the response body contains the fields primary
and verified
.
Gitlab
You can retrieve the email through the Gitlab API using the access token obtained via OIDC, but the response body does not contain an email_verified
field.
Further, the Gitlab docs indicate that users may not always verify email addresses.
Bitbucket
You can retrieve the email through the Bitbucket API using the access token obtained via OIDC. The response body contains two fields: is_primary
and is_confirmed
.
However, the Bitbucket API does not contain any reference to these fields, so it’s difficult to confirm exactly what these fields mean.
LINE
It is possible to retrieve the email by sending the ID token to the token verification endpoint, which returns the email.
However there’s no equivalent email_verified
claim, and the LINE docs do not explicitly say one way or the other if emails are verified.
You can retrieve the email through the Facebook API using the access token obtained via OIDC, if the user has an email address, which is not always the case with Facebook.
The response doesn’t contain an email_verified
field. The Facebook developer docs do not explicitly say if emails are verified, but the Facebook user-facing docs say that emails are verified at sign-up and when emails are added to a profile.
Conclusion
As the OIDC protocol specification states, ultimately it is unsafe to rely on the Issuer to verify the email of a user. If your application requires a high-level of assurance we recommend only relying on the sub
field and independently verifying the user’s email address.
If you are interested in implementing SSO securely, get a free account here or reach out to us!