Practical Example of Implementing OAuth 2.0 Using ory/hydra

  • The authentication and authorization process can be done in one handler/API, makes it easy to understand and implement.
  • There is no separation of concern between authorization and authentication process.
  • Your user service may be blocked by tremendous data of access tokens.
  • Hard to maintain multi-application with same user’s credential. For example, service Gmail may consist of n services behind it and Youtube m services, but if we only build Auth service for Gmail only, it sometimes hard to Youtube to use the same login credential.

OAuth 2.0

Before we go, it will be useful to know what is OAuth itself. OAuth is not an authentication protocol, therefore it does not need to know user’s context. Although we can implement Open ID Connect as an authentication layer on top OAuth 2.0, it is a different topic that I will not explain here.

Authentication VS Authorization

Citing from Egor Homakov, he wrote:

  • Third Party Application (Client): or OAuth 2.0 Client is the external application (can be mobile app or web app or any application) that will access Protected Resource if Resource Owner (User) gives the access. To know that, the Client will ask Authorization Server.
  • Resource Owner (User): is a end-user who have username and password (or other credentials) to access Protected Resource.
  • Authorization Server: is a server to proof that this user is authorized or permitted to access the Protected Resource. In the last section we will use ory/hydra as Authorization Server.
  • Resource Server (Authentication Server): or others called it as an Identity Provider, is a server to proof that this user has the right credentials to do the operation in the Protected Resource. It commonly a username and password.
  • Protected Resource: or sometimes called as Resource Provider, is a server(s) where the data can only be accessed if user is authenticated AND has permission (authorized) to access that data.

Grant Type: A Method To Authorize Your Client

OAuth 2.0 offers some grant type to authorize the 3rd party apps/clients to access to your data. The authorization process for mobile application or website will differs from smart-TV application or back-end’s service authorization process. This because each application runs in different capability limitation, and since OAuth 2.0 usually need web browser to redirect and run to authentication page process, some grant type is arranged to comply with device limitations.

Figure 1. Authorization Code Flow. Image source: accessed at 6 February 2021 18.39 GMT+7
  • client_id: A Client ID that the Third Party Application (Client) owner obtained from the OAuth 2.0 service. This includes client_secret.
  • redirect_uri: a Front-End or website page or URI where the access token (and sometimes refresh token) will given back. This URI must be registered first when creating an OAuth 2.0 Client. Usually it will be redirected to the Third Party Application (Client) page.
  • response_type: for Authorization Code grant, use “code”.
  • scope: list of permission that client (or the 3rd party) asks to access protected resource on user’s behalf.
  • state: a random code to be validated later when access_token is given back to the application. This is used to prevent CSRF attacks.
  • Resource Server will validates the username and password.
  • Once Resource Server say “okay”, then Resource Server may request to Authorization Server to ask Resource Owner (User)’s consent about what permissions he/she give to Third Party Application (Client) to access. This process done by sending “scope” parameters to the Authorization Server.
  • When authentication and permission process is done, Resource Server then ask Authorization Server to issue short-live authorization code. This code will be used later by the Third Party Application (Client) to be exchanged with Access Token to access Protected Resource.

Implementing OAuth 2.0 using ory/hydra

The better way to learn is by practicing. Here I will show you how to implement Authorization Code grant flow in OAuth 2.0 using ory/hydra.

Figure 2. OAuth 2.0 Flow using Ory/Hydra. Image source: accessed 7 February 2021 21.13 GMT+7
  1. Login Page — a Web UI that show a form for user to input their credentials. This is needed in process “Redirects end user with login challenge” and to “Fetches login info”. In this page, we need to capture a login_challenge from query parameter that sent by Hydra when “OAuth 2.0 Client initiates OAuth2 Authorize Code or Implicit Flow.”
    We then need to call Hydra to check whether current user already logged in (checked via cookie or remember flag). If already logged in (response key skip is true) then we do not need to show this login page, instead we use previous login info data to accept the login request and “Redirects end user to redirect url with login verifier”. Otherwise, we need to show a login form.
  2. Login Handler — an API to handle user’s info login. This handler will retrieve username and password of the User, then it will validate whether the inputted credentials is true. When valid, we need to accepts the login request to Hydra using login_challenge code sent by Hydra in process “Redirects end user with login challenge”. After accepting the request, Hydra will generate a consent_challenge and “Redirects end user with consent challenge” to Consent Page.
  3. Consent Page — a Web UI shows a list of permission that Resource Owner (User) need to accepts. For example, if the app need to access User’s profile info, it probably show a checkbox to access user info where the User can unchecked it (disagree) or checked it (agree). In this page, we will receive a consent_challenge that we need to send back to Hydra with list of scopes (permissions) that user agreed.
    We need to ask Hydra whether current request has requested the same scopes from the same user previously. If yes then skip parameter is true and you must not ask the user to grant the requested scopes.
  4. Consent Handler — an API handler to receive action of Consent Page (process 3). This handler will retrieve a grant_scope that User agreed in Consent Page UI, then ask Hydra to accepts Consent Request. The final response of this proccess is a redirect URI where Hydra will “Redirects to redirect url with consent verifier”. Hydra then verifies grant and transmits authorization code/token back to the redirect_uri in Third Party Application (Client). The Client then needs to exchange this Authorization code with an access token.
Figure 3. Sample of Login Page in “Sign In With Google” button. Image source: accessed at 8 February 2021 09:04 GMT+7
Figure 4. Consent Page in “Sign In With Google”. Image source: accessed at 8 February 2021 09:08 GMT+7
  1. GET /authentication/login —
  2. POST /authentication/login —
  3. GET /authentication/consent —
  4. POST /authentication/consent —
docker-compose -f quickstart.yml exec hydra \
hydra token user \
--client-id auth-code-client \
--client-secret secret \
--endpoint \
--port 5555 \
--scope openid,offline
version: '3.7'

image: oryd/hydra:v1.9.0
restart: on-failure
- ory-hydra-network
migrate sql -e --yes
- DSN=postgres://hydra:secret@postgresd:5432/hydra?sslmode=disable&max_conns=20&max_idle_conns=4
- postgresd

image: oryd/hydra:v1.9.0
restart: on-failure
- ory-hydra-network
- "4444:4444" # Public port
- "4445:4445" # Admin port
- "5555:5555" # Port for hydra token user, testing purpose only
serve all --dangerous-force-http
- SECRETS_SYSTEM=this-is-the-primary-secret
- URLS_LOGIN=http://localhost:8000/authentication/login # Sets the login endpoint of the User Login & Consent flow.
- URLS_CONSENT=http://localhost:8000/authentication/consent # Sets the consent endpoint of the User Login & Consent flow.

# set to Hydra public domain
- URLS_SELF_PUBLIC=http://localhost:4444 # to public endpoint
- URLS_SELF_ISSUER=http://localhost:4444 # to public endpoint
- DSN=postgres://hydra:secret@postgresd:5432/hydra?sslmode=disable&max_conns=20&max_idle_conns=4
- LOG_LEVEL=debug
- postgresd
- jaeger

image: postgres:13
restart: on-failure
- ory-hydra-network
- "5433:5432"
- ./logs:/var/lib/postgresql/data

image: adminer
restart: always
- ory-hydra-network
- 9000:8080

image: jaegertracing/all-in-one:1.7.0
restart: on-failure
- ory-hydra-network
- 5775:5775/udp
- 6831:6831/udp
- 6832:6832/udp
- 16686:16686 # Web App GUI to see traces

name: ory-hydra-net
$ git clone
$ cd oauth-example-hydra
$ git checkout v0.1.0
$ go mod download
$ go run cmd/authc/main.go
curl -X POST 'http://localhost:4445/clients' \
-H 'Content-Type: application/json' \
--data-raw '{
"client_id": "myclient",
"client_name": "MyApp",
"client_secret": "mysecret",
"grant_types": ["authorization_code", "refresh_token"],
"redirect_uris": ["http://localhost:1234/callbacks"],
"response_types": ["code", "id_token"],
"scope": "offline users.write users.edit users.delete",
"token_endpoint_auth_method": "client_secret_post"
REDIRECT_URL=http://localhost:1234/callbacks CLIENT_ID=myclient CLIENT_SECRET=mysecret go run cmd/frontend/main.go
Figure 5. Left tab is for docker compose, top-right tab is for Identity Provider run in port 8000, bottom-right is for Front-End run in port 1234.
Figure 6. Page show “Click here to _Sign In with YourApplicationName_”
Figure 7. A Login Page in Identity Provider.
Figure 8. A Consent Page in Identity Provider
Figure 9. A Front-End callback retrieve a authorization code and state to be validated.

References which also good to read



Yogyakarta — Indonesia

Love podcasts or audiobooks? Learn on the go with our new app.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store