Interacting as an OAuth client with Doorkeeper

Daniel Nill edited this page Jun 16, 2017 · 3 revisions

You will be interacting with the Doorkeeper-built application (we'll call it "DK" and pretend it lives at http://dk-app.com/) using JSON. To that end, you'll want to set the header Accept: application/json in all of your API calls. When posting or patching you'll be using that for your Content-Type: value, as well.

When writing applications to interface with DK, you'll need to implement OAuth.

How OAuth works

TL;DR : just pop to the bottom where client libraries are listed.

To describe the process, we'll use this diagram taken from RFC 6749 (the official word on OAuth):

  +--------+                                           +---------------+
  |        |--(A)------- Authorization Grant --------->|               |
  |        |                                           |               |
  |        |<-(B)----------- Access Token -------------|               |
  |        |               & Refresh Token             |               |
  |        |                                           |               |
  |        |                            +----------+   |               |
  |        |--(C)---- Access Token ---->|          |   |               |
  |        |                            |          |   |               |
  |        |<-(D)- Protected Resource --| Resource |   | Authorization |
  | Client |                            |  Server  |   |     Server    |
  |        |--(E)---- Access Token ---->|          |   |               |
  |        |                            |          |   |               |
  |        |<-(F)- Invalid Token Error -|          |   |               |
  |        |                            +----------+   |               |
  |        |                                           |               |
  |        |--(G)----------- Refresh Token ----------->|               |
  |        |                                           |               |
  |        |<-(H)----------- Access Token -------------|               |
  +--------+           & Optional Refresh Token        +---------------+

In step A, we ask the authorization server to grant authorization to our client. The authorization server should prompt the user for recognition of this application; if granted, then access and refresh tokens are issued. The access token has a time-to-live value associated with it.

When downloading protected resources (steps C and D), the access token must be presented. If an expired or invalid token is presented, it will be rejected; DK should then attempt a refresh (step G.) If the refresh fails, DK should start over from step A.

Writing a Raw OAuth Client

You're reading this because you want to build an app, right? Well, let's get you started. First we'll register your app at the DK applications page, which commonly resides at (https://dk-app.com/oauth/applications).

Configuring an Application

NAME YOUR APP. They say that the two hardest problems in programming are Naming, Cache Invalidation, and Off-By-One Errors.

Give it a callback URI. When access is granted, this URI will be triggered with the parameter code=... appended. For some systems this might obligate you to fire up a socket listener. On iOS, for example, we just register a custom scheme (typically in my case, appname://call/back.)

When you create your application, you will then receive two magic numbers: a client ID and a client secret. These two numbers will be used in your app, so store them as appropriate. For example, Rubyists store them in environment variables; iOS developers will often hard-code the values into their apps.

Requesting the Grant

In order to prompt the user to grant the access, we need to open a browser window. That window will open https://dk-app.com/oauth/authorize?client_id=XXX&response_type=code&redirect_uri=YYY with the following stand-in values:

  • XXX stands for the client ID received in the previous step.
  • YYY is the callback URI you configured in the previous step. These must match exactly or your request will be rejected.

When the user grants access to your application, that callback URI will be triggered and we will receive our authorization code. When we see callback://myapp/opensesame?code=1928dbb28h... we are really only concerned with the business after the equals sign, of course. That is our authorization code.

Now, we turn that in to get an access token.

Getting an Access Token

For this, we will craft a POST request to https://dk-app.com/oauth/token that presents our various bits and asks for a reusable token. The required parameters must be passed as form-urlencoded. The required parameters are:

  • client_id: The client ID issued in the first step.
  • client_secret: The client secret issued in the first step.
  • redirect_uri: The callback URI we defined previously.
  • grant_type: This is authorization_code in the initial request.
  • code: The authorization code received in the previous step.

The response body that comes back looks like this:

{"access_token":"09ba487fc3df...",
 "token_type":"bearer",
 "expires_in":7200,
 "refresh_token":"8c488ab5f75d61..."
}

We'll parse out the access_token, refresh_token and expires_in values. The access_token is what we'll set in all our HTTP headers; it will expire in expires_in seconds. Once that period has passed, we use the refresh_token to get a new access_token.

To this end, to keep from re-authorizing each time the app runs, the refresh_token should be persisted somewhere.

Using the Access Token

For each request to access a protected resource, you will want to add this HTTP header:

Authorization: Bearer 09ba487fc3df...

And thus the access will be granted.

Renewing the Access Token

When we need to refresh our token, we will craft a POST request very similar to the one following the authorization grant. Only a few values are different, marked in bold:

  • client_id: The client ID issued in the first step.
  • client_secret: The client secret issued in the first step.
  • redirect_uri: The callback URI we defined previously.
  • grant_type: This was authorization_code in the initial request, but now it'll be refresh_token.
  • refresh_token: The saved refresh token.

Revoking Access

If a user wishes to revoke an authorization, they do it via https://dk-app.com/oauth/authorized_applications.

Revoking authorization to an app is done through the DK applications page at https://dk-app.com/oauth/applications.

Available Libraries