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
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
- Most companies want to associate an email address with a user, so taking advantage of the
- 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
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
- 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
Google exposes an API to fetch the email address. The API documentation says that the
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 provides an API to retrieve the email of a logged-in user, and the response includes an
Apple includes an
email_verified claim in the ID token returned via OIDC.
You can retrieve the email through the Github API using the access token obtained via OIDC, and the response body contains the fields
You can retrieve the email through the Gitlab API using the access token obtained via OIDC, but the response body does not contain an
Further, the Gitlab docs indicate that users may not always verify email addresses.
You can retrieve the email through the Bitbucket API using the access token obtained via OIDC. The response body contains two fields:
However, the Bitbucket API does not contain any reference to these fields, so it’s difficult to confirm exactly what these fields mean.
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.
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.