OIDC: Secure Authentication with OpenID Connect

Reading material

This article has very good explanation about it: https://www.fortinet.com/resources/cyberglossary/oidc

Some history

If OAuth is for authorization, OpenID is for authentication. Created in 2005 to log in to LiveJournal, one of the early blogging websites, OpenID was adopted as a way to sign in with the same username and password across multiple sites.

Ironically, in a way, internet users do this anyway. When prompted to create a new username and password for a website, they often default to the same credentials they have used repeatedly with other sites. While this helps them to remember their credentials, the practice can also leave them vulnerable to cyberattacks. Physically typing credentials into a website that are also used for multiple other sites increases the chances of malicious actors intercepting sensitive user data.

In a man-in-the-middle attack, cyberattackers use Wi-Fi eavesdropping or session hijacking to steal credentials, in hopes to gain entry into other websites.

Eventually, the developer community lost their enthusiasm with OpenID, especially as Facebook and its soon-to-be-ubiquitous “Sign in with Facebook” capability started spreading throughout the internet. However, rather than completely retiring OpenID, the developers released a reinvented version in 2014 as an authentication layer for OAuth. With this new version, OpenID and OAuth complement each other. For modern implementations, this evolved standard is widely known as OpenID Connect (OIDC), which extends OAuth 2.0 to provide both authentication and authorization.

Pseudo-Authentication with OAuth 2.0

https://developer.okta.com/blog/2017/06/21/what-the-heck-is-oauth#pseudo-authentication-with-oauth-20

Login with OAuth was made famous by Facebook Connect and Twitter. In this flow, a client accesses a /me endpoint with an access token. All it says is that the client has access to the resource with a token. People invented this fake endpoint as a way of getting back a user profile with an access token. It’s a non-standard way to get information about the user. There’s nothing in the standards that say everyone has to implement this endpoint. Access tokens are meant to be opaque. They’re meant for the API, they’re not designed to contain user information.

What you’re really trying to answer with authentication is who the user is, when did the user authenticate, and how did the user authenticate. You can typically answer these questions with SAML assertions, not with access tokens and authorization grants. That’s why we call this pseudo authentication.

Enter OpenID Connect

To solve the pseudo authentication problem, the best parts of OAuth 2.0, Facebook Connect, and SAML 2.0 were combined to create OpenID Connect. OpenID Connect (OIDC) extends OAuth 2.0 with a new signed id_token for the client and a UserInfo endpoint to fetch user attributes. Unlike SAML, OIDC provides a standard set of scopes and claims for identities. Examples include: profile, email, address, and phone.

OIDC was created to be internet scalable by making things completely dynamic. There’s no longer downloading metadata and federation like SAML requires. There’s built-in registration, discovery, and metadata for dynamic federations. You can type in your email address, then it dynamically discovers your OIDC provider, dynamically downloads the metadata, dynamically know what certs it’s going to use, and allows BYOI (Bring Your Own Identity). It supports high assurance levels and key SAML use cases for enterprises.

OIDC was made famous by Google and Microsoft, both big early adopters. Okta has made a big investment in OIDC as well.

All that changes in the initial request is it contains standard scopes (like openid and email):

Request

GET https://accounts.google.com/o/oauth2/auth?
scope=openid email&
redirect_uri=https://app.example.com/oauth2/callback&
response_type=code&
client_id=812741506391&
state=af0ifjsldkj

Response

HTTP/1.1 302 Found
Location: https://app.example.com/oauth2/callback?
code=MsCeLvIaQm6bTrgtp7&state=af0ifjsldkj

The code returned is the authorization grant and state is to ensure it’s not forged and it’s from the same request.

And the authorization grant for tokens response contains an ID token.

Request

POST /oauth2/v3/token HTTP/1.1
Host: www.googleapis.com
Content-Type: application/x-www-form-urlencoded

code=MsCeLvIaQm6bTrgtp7&client_id=812741506391&
  client_secret={client_secret}&
  redirect_uri=https://app.example.com/oauth2/callback&
  grant_type=authorization_code

Response

{
  "access_token": "2YotnFZFEjr1zCsicMWpAA",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "tGzv3JOkF0XG5Qx2TlKWIA",
  "id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjFlOWdkazcifQ..."
}

You can see this is layered nicely on top of OAuth to give back an ID token as a structured token. An ID token is a JSON Web Token (JWT). A JWT (aka “jot”) is much smaller than a giant XML-based SAML assertion and can be efficiently passed around between different devices. A JWT has three parts: a header, a body, and a signature. The header says what algorithm was used to sign it, the claims are in the body, and its signed in the signature.

An Open ID Connect flow involves the following steps:

  1. Discover OIDC metadata
  2. Perform OAuth flow to obtain id token and access token
  3. Get JWT signature keys and optionally dynamically register the Client application
  4. Validate JWT ID token locally based on built-in dates and signature
  5. Get additional user attributes as needed with access token