API Security

Run your own OAuth 2.0 Server

Become an OAuth2 and OpenID Connect provider using secure and scalable open source technology.

In this guide, you will set up a hardened, fully functional OAuth 2.0 (OAuth2) server. It will take you about ~15 minutes. This guide is for you, if you are looking to do something like in the gif on the right, or more specifically:

  • You want to use OAuth2 for API security.
  • You want to open up your API to third party developers like Dropbox, or GitHub.
  • You want to become an identity provider like Google, Facebook, or Twitter.
  • You need to federate (delegate) authentication or authorization.

We will use ORY Hydra (open source), a security-first OAuth2 and OpenID Connect server written in Golang.

GitHub OAuth 2.0 visual flow
What OAuth 2.0 looks like in the wild: CircleCI performs API calls to GitHub on your behalf.

This is how ORY Hydra works

We originally built ORY Hydra because all other OAuth2 servers imposed their user management on us. But we had a user management in place already, and did not want to migrate away from it.

ORY Hydra defines a consent flow which let's you implement the bridge between ORY Hydra and your user management easily using only a few lines of code. If you want, you could say that ORY Hydra translates the user information you provide to OAuth2 Access Tokens and OpenID Connect ID Tokens, which are then reusable across all your applications (web app, mobile app, CRM, Mail, ...) and also by third-party developers.

Sounds good, let's go!

You're hooked? Great! Let's start by downloading some docker images. By the way, this tutorial relies heavily on docker. If you haven't already, please install docker now.

Sidenote: Please be aware that this tutorial is making extensive use of Docker. As such, this tutorial assumes that you have some knowledge of how Docker works.

Create a Network

Before we can start, a network must be created which we will attach all our Docker containers to. That way, the containers can talk to one another.

$ docker network create hydraguide

Install and run PostgreSQL

First, a database is required, and we will choose PostgreSQL 9.6 (MySQL is also supported).

This docker command starts postgres container ory-hydra-example--postgres and sets up a database called hydra with user hydra and password secret.

By the way, some code listings use \ at the end of the line. Shells like bash concatenate these to one line.

$ docker run --network hydraguide \
  --name ory-hydra-example--postgres \
  -e POSTGRES_USER=hydra \
  -e POSTGRES_PASSWORD=secret \
  -e POSTGRES_DB=hydra \
  -d postgres:9.6

By the way, don't deploy databases using docker in production. It will make your life miserable. Use a managed solution like Amazon RDS or Google Cloud SQL. Even small instances will be able to serve a lot of traffic, check out some of the benchmarks.

Configure the environment

System Secret

The system secret is used to encrypt data at rest, and to sign tokens and authorize codes. Once a database is initialized with a system secret, you always need to use that secret to access the database.

$ export SYSTEM_SECRET=y82XL-wAPCCZu+B4

Database

The database url must point to the postgres container we created above. The database will be used to persist and query data. ORY Hydra prevents data leaks as only token signatures are stored in the database. For a valid token, both payload and signature are required.

$ export DATABASE_URL=postgres://hydra:secret@ory-hydra-example--postgres:5432/hydra?sslmode=disable

Initialize the database

Next, the database needs to be initialized. This can be achieved with hydra migrate sql. Here we pull the latest docker image for ORY Hydra and run a container that executes the migrate command.

$ docker run -it --rm \
  --network hydraguide \
  oryd/hydra:v1.0.0-beta.3 \
  migrate sql $DATABASE_URL

To prevent bad things from happening, SQL migrations are never run without you explicitly telling them to. This is the case for new and existing databases.

Run the OAuth2 server

Besides setting the system secret (SYSTEM_SECRET), the database url (DATABASE_URL), the public url (OAUTH2_ISSUER_URL) of the server, the user login endpoint (OAUTH2_LOGIN_URL) and the user consent endpoint (OAUTH2_CONSENT_URL) are passed using environment variables.

Both user login and consent urls point to one or two web service(s) which will be explained and set up in the next sections. For now, you can think of it as connecting ORY Hydra to your identity management (user registration, profile management, user login ,...)).

For the sake of simplicity, we will force ORY Hydra to run HTTP instead of HTTPS. Also, please, use more secure values in production.

$ docker run -d \
  --name ory-hydra-example--hydra \
  --network hydraguide \
  -p 9000:4444 \
  -e SYSTEM_SECRET=$SYSTEM_SECRET \
  -e DATABASE_URL=$DATABASE_URL \
  -e OAUTH2_ISSUER_URL=http://127.0.0.1:9000/ \
  -e OAUTH2_CONSENT_URL=http://127.0.0.1:9020/consent \
  -e OAUTH2_LOGIN_URL=http://127.0.0.1:9020/login \
  oryd/hydra:v1.0.0-beta.3 serve --dangerous-force-http

Is it alive?

This is easy to answer, just check the docker logs! Or, open the health check, which should show you ok.

$ docker logs ory-hydra-example--hydra

[...]

time="2017-06-29T21:26:34Z" level=info msg="Setting up http server on :4444"

Get help

ORY Hydra can be managed using the Hydra Command Line Interface (CLI), which is using ORY Hydra's REST APIs. To see the available commands, run the help command.

$ docker run --rm -it \
  oryd/hydra:v1.0.0-beta.3 \
  help

Performing the OAuth 2.0 Client Credentials Flow

Create an OAuth 2.0 Client

$ docker run --rm -it \
  --network hydraguide \
  oryd/hydra:v1.0.0-beta.3 \
  clients create \
    --endpoint http://ory-hydra-example--hydra:4444 \
    --id some-consumer \
    --secret some-secret \
    --grant-types client_credentials \
    --response-types token,code

Great! Our infrastructure is all set up! Next it's time to perform the OAuth 2.0 Client Credentials Flow. For that to work you have to createn an OAuth 2.0 Client that is able to perform this flow. For that purpose, you can use the ORY Hydra CLI.

We are passing several flags to the command, for example --grant-types client_credentials which allows the client to perform the OAuth 2.0 Client Credentials grant.

Issue an access token

$ docker run --rm -it \
  --network hydraguide \
  oryd/hydra:v1.0.0-beta.3 \
  token client \
    --client-id some-consumer \
    --client-secret some-secret \
    --endpoint http://ory-hydra-example--hydra:4444

ZcE0YWqnxemENLyJrjjlAHlFkdwaHB6TzkSi0c289HI.GQmXJsAYcw5de97S6mqOL0yB2UyFEf4DiXEM05vdfdY

The ORY Hydra CLI offers a method (hydra token client) which performs the OAuth 2.0 Client Credentials flow. Let's use the newly created client to perform this flow!

The result will be an OAuth 2.0 access token which we will validate in the next step.

Validate the access token

$ docker run --rm -it \
  --network hydraguide \
  oryd/hydra:v1.0.0-beta.3 \
  token introspect \
    --client-id some-consumer \
    --client-secret some-secret \
    --endpoint http://ory-hydra-example--hydra:4444 \
    >INSERT-TOKEN-HERE<

{
        "active": true,
        "client_id": "some-consumer",
        "exp": 1528901511,
        "iat": 1528897911,
        "iss": "http://127.0.0.1:9000/",
        "sub": "facebook-photo-backup",
        "token_type": "access_token"
}

Using hydra token introspect it is possible to validate an access token, and receive it's payload. ORY Hydra uses opaque tokens to greatly reduce attack vectors. You can set arbitrary data in the token, if you want. For more information on this head over to the developer guide.

You can validate access tokens using the OAuth 2.0 Introspection API, standardized as IETF OAuth 2.0 Token Introspection.

Please make sure to replace >INSERT-TOKEN-HERE< with the token you just received.

The user login & consent flow

ORY Hydra is not an Identity Management solution. Instead it uses your existing Identity Management which reduces adoption complexity. OAuth2 providers such as Keycloak, OpenAM, or IdentityServer are usually full-stack enterprise identity and access management solutions. They come with complex deployment dependencies, technologies not particularly suited for cloud native environments, and subtle, but annoying limitations at scale. ORY Hydra solves OAuth2 and OpenID Connect only, but it solves it well and extemely scalable.

To authenticate users, ORY Hydra defines the user login & consent flow. You can find an exemplary user login and consent application on our GitHub.

Run the user login & consent app

For the sake of simplicity, we will use the already available user login and consent example app. It emulates a Identity Management application (it has only one user) and integrates with ORY Hydra's User Login & Consent Flow.

$ docker run -d \
  --name ory-hydra-example--consent \
  -p 9020:3000 \
  --network hydraguide \
  -e HYDRA_URL=http://ory-hydra-example--hydra:4444 \
  -e NODE_TLS_REJECT_UNAUTHORIZED=0 \
  oryd/hydra-login-consent-node:v1.0.0-beta.3

OAuth2 + OpenID Connect Authorize Flow

Create OAuth2 Consumer App

Awesome, the infrastructure is now set up! To perform the OAuth 2.0 and OpenID Connect flow, an OAuth 2.0 Client (consumer app) is required.

The client must be able to request the authorize_code grant, scope openid and offline, and response types token, code, and id_token.

$ docker run --rm -it \
  --network hydraguide \
  oryd/hydra:v1.0.0-beta.3 \
  clients create \
    --endpoint http://ory-hydra-example--hydra:4444 \
    --id another-consumer \
    --secret consumer-secret \
    -g authorization_code,refresh_token \
    -r token,code,id_token \
    --scope openid,offline \
    --callbacks http://127.0.0.1:9010/callback

Client ID: another-consumer
Client Secret: consumer-secret

Perform OAuth 2.0 Authorize Code Flow

To initialize an OAuth 2.0 authorize code flow, use the hydra token user command. It will generate the authorization url which the user must open in the browser. Requesting the authorization is the first step of the OAuth 2.0 authorize code flow.

Requesting OAuth 2.0 Access and Refresh tokens is usually done using a library for your programming language. Do not write this on your own. Here are some libraries for different languages: Golang, NodeJS,PHP.

$ docker run --rm -it \
  --network hydraguide \
  -p 9010:9010 \
  oryd/hydra:v1.0.0-beta.3 \
  token user \
    --port 9010 \
    --auth-url http://127.0.0.1:9000/oauth2/auth \
    --token-url http://ory-hydra-example--hydra:4444/oauth2/token \
    --client-id another-consumer \
    --client-secret consumer-secret \
    --scope openid,offline \
    --redirect http://127.0.0.1:9010/callback

Setting up home route on http://127.0.0.1:9010/
Setting up callback listener on http://127.0.0.1:4445/callback
Press ctrl + c on Linux / Windows or cmd + c on OSX to end the process.
If your browser does not open automatically, navigate to:

        http://127.0.0.1:9010/

Login & Consent

Open http://127.0.0.1:9010/ in your browser and you will see a simple screen asking you to authorize the application. If you remember the CircleCI example from the beginning of the article, this would be the "Log In with GitHub" button.

Consent App showing the login screen

After clicking "Authorize application" you will be asked to log in. The screen you are seeing is provided by the exemplary User Login & Consent app ("ory-hydra-example--consent"). The contents of these screens are under your control and you can use any technology you like to implement them. As already noted, the exemplary application has just one user. In a real-world scenario, you could probably sign up for a new account or use a social login provider (e.g. Google, Facebook) to sign in.

Consent App showing the login screen

The consent screen is the second important screen shown by the User Login & Consent app. It asks the end user which permissions to authorize. If a user has privacy concerns, he/she could not grant access to personal details. Since our example only requests very basic permissions, you should grant them all.

Consent App asking the user to grant the requested scopes to the application

Once logged in and authorized, ORY Hydra will issue an access, a refresh (if scope offline was granted), and an ID token (if scope openid was granted).

Successful authorization returns access, refresh and ID tokens

You made it!

That's it, you have a running OAuth2 server with an exemplary identity provider, and performed an OAuth2 request! You can use the token from the last request and pass it to hydra token introspect as we did earlier with the OAuth 2.0 Client Credentials flow.

ORY Hydra is an Apache 2.0 licensed Go server solving OAuth 2.0, OpenID Connect and API security in general. It secures millions of requests per day and has a vibrant and welcoming online community.

Check out ORY Hydra at Github and our other API Security products.