Skip to main content

OpenID Connect (OIDC)

Before you start reading this document, please make sure to have covered all topics in OAuth 2.0 Concepts.

OpenID Connect works like OAuth2. The primary use case for OpenID Connect is to solve "Login with <Google|Facebook|Hydra>" flows.

To initiate an OpenID Connect flow all you have to do is to add the openid scope to your OAuth2 Authorize Code Flow:


You need to make sure that your OAuth2 Client is allowed to request the openid scope!

Once you exchange the authorize code for the access and refresh token

POST /oauth/token HTTP/1.1
Host: my-hydra


you will receive an ID Token:

"access_token": "MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3",
"token_type": "bearer",
"expires_in": 3600,
"refresh_token": "IwOGYzYTlmM2YxOTQ5MGE3YmNmMDFkNTVk",
"id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjFlOWdkazcifQ.ewogImlzcyI6ICJodHRwOi8vc2VydmVyLmV4YW1wbGUuY29tIiwKICJzdWIiOiAiMjQ4Mjg5NzYxMDAxIiwKICJhdWQiOiAiczZCaGRSa3F0MyIsCiAibm9uY2UiOiAibi0wUzZfV3pBMk1qIiwKICJleHAiOiAxMzExMjgxOTcwLAogImlhdCI6IDEzMTEyODA5NzAKfQ.ggW8hZ1EuVLuxNuuIJKX_V8a_OMXzR0EHR9R6jgdqrOOF4daGU96Sr_P6qJp6IcmD3HP99Obi1PRs-cwh3LO-p146waJ8IhehcwL7F09JdijmBqkvPeB2T9CJNqeGpe-gccMg4vfKjkM8FcGvnzZUN4_KSP0aAp1tOJ1zZwgjxqGByKHiOtX7TpdQyHE5lcMiKPXfEIQILVq0pc_E2DzL7emopWoaoZTF_m0_N0YzFC6g6EJbOEoRoSK5hoDalrcvRYLSrQAZZKflyuVCyixEoV9GfNQC3_osjzw2PAithfubEEBLuVVk4XUVrWOLrLl0nx7RkKU8NXNHq-rvKMzqg",
"scope": "openid"

The ID Token's purpose is to authenticate the End-User at the OAuth2 Client Application. It doesn't solve session management or anything else (you still have to manage cookies, logout, ... yourself!) - it's just a "certificate".


The /userinfo endpoint returns information on a user given an access token. Since Ory OAuth2 & OpenID is agnostic to any end-user data, the /userinfo endpoint returns only minimal information per default:

GET https://ory-hydra:4444/userinfo
Authorization: bearer access-token.xxxx

"acr": "oauth2",
"sub": "[email protected]"

Any information set to the key session.id_token during accepting the consent request will also be included here.

// This is node-js pseudo code and won't work if you copy it 1:1

const body = {
// grant_scope: ["foo", "bar"],
// ...
session: {
id_token: {
"foo": "bar"

fetch('https://hydra/oauth2/auth/requests/consent/' + challenge + '/accept', {
method: 'PUT',
body: JSON.stringify(body),
headers: { 'Content-Type': 'application/json' }
// then(function (response) {

By making the /userinfo call with a token issued by this consent request, one would receive:

GET https://ory-hydra:4444/userinfo
Authorization: bearer new-access-token.xxxx

"acr": "oauth2",
"sub": "[email protected]",
"foo": "bar"

You should only include data that has been authorized by the end-user through an OAuth 2.0 Scope. If an OAuth 2.0 Client, for example, requests the phone scope and the end-user authorizes that scope, the phone number should be added to session.id_token.

Be aware that the /userinfo endpoint is public. Its contents are thus as publicly visible as those of ID Tokens. It's therefore imperative to not expose sensitive information without end-user consent.