Login Flow
OAuth2 and OpenID Connect require an authenticated End-User session for all
OAuth2 / OpenID Connect flows except the client_credentials
flow which does
not involve End-Users.
Ory Hydra does not contain a database with End-Users but instead uses HTTP Redirection to "delegate" the login flow to another app - we call this the Login & Consent App.
The following short video shows the flow from an End-User's perspective - it includes both login and consent.
The following sequence diagram describes the different API calls and HTTP Redirects when performing the OAuth2 flow:
Initiating the OAuth 2.0 / OpenID Connect Flow​
The OAuth2 2.0 / OpenID Connect Flow is initiated by pointing the End-User's
browser to the /oauth2/auth
endpoint. Depending on which flow ("Authorize Code
Flow", "Implicit Flow", ...) you want to use some of the query parameters (e.g.
/oauth2/auth?response_type=code
, /oauth2/auth?response_type=token
, ...)
might change but the overall initiation works always by sending the browser to
that URL.
note
This guide uses URLs from the 5 Minute Tutorial:
- Ory Hydra Public Endpoint: http://127.0.0.1:4444
- Ory Hydra Admin Endpoint: http://127.0.0.1:4445
When translating this guide into your own environment, make sure to use the correct endpoint for your interactions.
- UI
- HTML
- JavaScript
<a
href="https://<hydra-public>/oauth2/auth?client_id=...&response_type=...&scope=..."
>
Login in with Ory Hydra</a
>
// ...
window.location.href =
'https://public.hydra.url/oauth2/auth?client_id=...&response_type=...&scope=...'
Redirection to the Login Endpoint​
The next task for Ory Hydra is to know the user of the request. To achieve that,
Ory Hydra checks if a session cookie is set containing information about a
previously successful login. Additionally, OpenID Connect parameters
id_token_hint
, prompt
, and max_age
are evaluated and processed. Depending
on their values and the login state, the user might need to re-authenticate or
the flow will fail completely.
To authenticate the user (this happens regardless of whether a session exists for the user or not), Ory Hydra redirects the browser to the "Login Endpoint" established in your config:
# Can also be set using the environment variable:
# URLS_LOGIN=https://login-app/login
urls:
login: https://login-app/login
Ory Hydra appends a login_challenge
query parameter to the url. The value is a
ID which should later be used by the Login Endpoint to fetch important
information about the request.
https://login-app/login?login_challenge=7bb518c4eec2454dbb289f5fdb4c0ee2
Login Sessions, prompt
, max_age
, id_token_hint
​
Ory Hydra keeps track of user sessions. It does so by issuing a cookie which contains the user ID. On subsequent OAuth2 / OpenID Connect flows, the session will be checked and the Login Endpoint will be instructed to, for example, show the Login HTML Form or skip the Login HTML Form.
Ory Hydra supports the following OpenID Connect query parameters:
prompt
(optional). Space delimited, case sensitive list of ASCII string values that specifies whether the Authorization Server prompts the End-User for reauthentication and consent.prompt=none
instructs Ory Hydra to not display the login or consent user interface pages. An error is returned if an End-User is not already authenticated or the Client does not have pre-configured consent for the requested Claims or does not fulfill other conditions for processing the request. The error code will typically belogin_required
,interaction_required
, or another code. This can be used as a method to check for existing authentication and/or consent.prompt=login
instructs Ory Hydra to force the End-User to log in using the Login HTML Form in the Login Endpoint.prompt=consent
instructs Ory Hydra to force the End-User to re-authorize (give consent) the OAuth2 Client using the Consent HTML Form in the Consent Endpoint.prompt=select_account
is currently not supported in Ory Hydra, see [#].
max_age
(optional) specifies the allowable elapsed time in seconds since the last time the End-User was actively authenticated by Ory Hydra. If the elapsed time is greater than this value, the Login HTML Form must be shown and the End-User must re-authenticate.id_token_hint
(optional) - ID Token previously issued by Ory Hydra being passed as a hint about the End-User's current or past authenticated session with the Client. If the End-User identified by the ID Token is logged in or is logged in by the request, then the Authorization Server returns a positive response; otherwise, it returns an error, typicallylogin_required
. It does not matter if the ID Token is expired or not.
To specify these parameters add them to the OAuth2 Auth Endpoint URL Query:
https://<hydra-public>/oauth2/auth?prompt=login&max_age=60&id_token_hint=...'
The Login Endpoint​
The Login Endpoint (set by urls.login
) is an application written by you. You
can find an exemplary
NodeJS reference implementation on our GitHub.
The Login Endpoint uses the login_challenge
value in the URL to fetch
information about the login request by making a HTTP GET request to:
http(s)://<HYDRA_ADMIN_URL>/oauth2/auth/requests/login?login_challenge=<challenge>
The response (see below in "Login Challenge Response" tab) contains information
about the login request. The body contains a skip
value. If the value is
false
, the user interface must be shown. If skip
is true, you should not
show the user interface but instead just accept or reject the login request! For
more details about the implementation check the
"Implementing the Login Endpoint" Guide.
- UI
- curl
- Login Challenge Response
curl "http://127.0.0.1:4445/oauth2/auth/requests/login?login_challenge=7bb518c4eec2454dbb289f5fdb4c0ee2"
Check the "Implementing the Login Endpoint" Guide for examples using the Ory Hydra SDK in different languages.
{
"challenge": "7bb518c4eec2454dbb289f5fdb4c0ee2",
"requested_scope": ["openid", "offline"],
"requested_access_token_audience": null,
"skip": false,
"subject": "",
"oidc_context": {},
"client": {
"client_id": "auth-code-client",
"client_name": "",
"redirect_uris": ["http://127.0.0.1:5555/callback"],
"grant_types": ["authorization_code", "refresh_token"],
"response_types": ["code", "id_token"],
"scope": "openid offline",
"audience": null,
"owner": "",
"policy_uri": "",
"allowed_cors_origins": null,
"tos_uri": "",
"client_uri": "",
"logo_uri": "",
"contacts": null,
"client_secret_expires_at": 0,
"subject_type": "public",
"token_endpoint_auth_method": "client_secret_basic",
"userinfo_signed_response_alg": "none",
"created_at": "2020-07-08T12:31:47Z",
"updated_at": "2020-07-08T12:31:47Z"
},
"request_url": "http://127.0.0.1:4444/oauth2/auth?audience=&client_id=auth-code-client&max_age=0&nonce=hognfveoohhddoralbeygsjg&prompt=&redirect_uri=http%3A%2F%2F127.0.0.1%3A5555%2Fcallback&response_type=code&scope=openid+offline&state=imnweycejbfpyrmnahgqzcmm",
"session_id": "d3c98aa6-67ae-478b-bc30-f7887b58f630"
}
The way you authenticate the End-User is up to you. In most cases, you will show an HTML form similar to:
<form action="/login" method="post">
<input type="hidden" name="csrf_token" value="...." />
<!-- Use CSRF tokens in your HTML forms! -->
<input
type="email"
name="login_email"
placeholder="Please enter your email address to log in"
/>
<input type="password" name="login_password" />
<input type="checkbox" name="remember" value="Remember me on this device" />
<input type="submit" value="Log in" />
</form>
Once the End-User authenticated successfully, you either accept the login challenge, or you reject (e.g. the user is not allowed to perform OAuth2 flows) the login challenge.
Accepting the Login Flow​
To accept the Login Challenge, make a HTTP PUT request with
Content-Type: application/json
and a JSON payload (see
Accept Login Request HTTP API Reference)
warning
The subject must be an immutable user ID, it should never be an email address, a username, or something else that may change over time.
{
// Subject is the user ID of the end-user that authenticated.
"subject": "string", // required!
// All values below are optional!
// Remember, if set to true, tells Ory Hydra to remember this user by telling the user agent (browser) to store
// a cookie with authentication data. If the same user performs another OAuth 2.0 Authorization Request, he/she will not be asked to log in again.
"remember": true,
// RememberFor sets how long the authentication should be remembered for in seconds. If set to 0,
// the authorization will be remembered for the duration of the browser session (using a session cookie).
"remember_for": 0,
// ACR sets the Authentication AuthorizationContext Class Reference value for this authentication session. You can use it to express that, for example, a user authenticated using two factor authentication.
"acr": "string",
// Context is an optional object which can hold arbitrary data. The data will be made available when fetching the
// consent request under the "context" field. This is useful in scenarios where login and consent endpoints share
// data.
"context": {
// "foo": "bar"
},
// ForceSubjectIdentifier forces the "pairwise" user ID of the end-user that authenticated. The "pairwise"
// user ID refers to the (Pairwise Identifier Algorithm)[http://openid.net/specs/openid-connect-core-1_0.html#PairwiseAlg]
// of the OpenID Connect specification. It allows you to set an obfuscated subject ("user") identifier that is unique
// to the client. Please note that this changes the user ID on endpoint /userinfo and sub claim of the ID Token.
// It does not change the sub claim in the OAuth 2.0 Introspection. Per default, Ory Hydra handles this value with its own algorithm.
// In case you want to set this yourself you can use this field. Please note that setting this field has no effect if pairwise is not
// configured in Ory Hydra or the OAuth 2.0 Client does not expect a pairwise identifier (set via subject_type key in the client's configuration).
// Please also be aware that Ory Hydra is unable to properly compute this value during authentication. This implies that
// you have to compute this value on every authentication process (probably depending on the client ID or some other unique value).
// If you fail to compute the proper value, then authentication processes which have id_token_hint set might fail.
"force_subject_identifier": "string"
}
With curl
this might look like the following request:
$ curl --location --request PUT 'http://127.0.0.1:4445/oauth2/auth/requests/login/accept?login_challenge=7bb518c4eec2454dbb289f5fdb4c0ee2' \
--header 'Content-Type: application/json' \
--data-raw '{
"subject": "the-user-id-that-just-logged-in",
"remember": true,
"remember_for": 3600
}'
The server responds with JSON
{
"redirect_to": "http://127.0.0.1:4445/oauth2/auth..."
}
which is the URL your application must redirect the End-User's browser to.
Check the "Implementing the Login Endpoint" Guide for examples using the Ory Hydra SDK in different languages.
Rejecting the Login Flow​
To reject the Login Challenge, make a HTTP PUT request with
Content-Type: application/json
and a JSON payload (see
Reject Login Request HTTP API Reference)
{
// The error should follow the OAuth2 error format (e.g. `invalid_request`, `login_required`).
"error": "user_banned",
// Description of the error in a human readable format.
"error_description": "You are banned!",
// Hint to help resolve the error.
"error_hint": "Contact the site administrator.",
// Debug contains information to help resolve the problem as a developer. Usually not exposed
// to the public but only in the server logs.
"error_debug": "The user was marked banned in the database.",
// Represents the HTTP status code of the error (e.g. 401 or 403)
//
// Defaults to 400
"status_code": 403
}
With curl
this might look like the following request:
$ curl --location --request PUT 'http://127.0.0.1:4445/oauth2/auth/requests/login/reject?login_challenge=7bb518c4eec2454dbb289f5fdb4c0ee2' \
--header 'Content-Type: application/json' \
--data-raw '{
"error": "user_banned",
"error_debug": "The user was marked banned in the database.",
"error_description": "You are banned!",
"error_hint": "Contact the site administrator.",
"status_code": 403
}'
The server responds with JSON
{
"redirect_to": "http://127.0.0.1:4445/oauth2/auth..."
}
which is the URL your application must the End-User's browser to.
Check the "Implementing the Login Endpoint" Guide for examples using the Ory Hydra SDK in different languages.
Redirection to the Consent Endpoint​
Please head over to Consent Flow!
Revoking Ory Hydra Login Sessions​
Revoking a login session will remove all of the user's cookies at Ory Hydra and will require the user to re-authenticate when performing the next OAuth 2.0 Authorize Code Flow. Be aware that this option will remove all cookies from all devices.
info
Revoking a login session does not invalidate any Access, Refresh, or ID Tokens! If you log out of GitHub, you will not be logged out of CircleCI/TravisCI.
Revoking the login sessions of a user is as easy as sending DELETE
to
/oauth2/auth/sessions/login?subject={subject}
(see
full API documentation).
This endpoint is not compatible with OpenID Connect Front-/Backchannel logout and does not revoke any tokens.