Artificial Intelligence

Simple password grants with OAuth 2.0 and Drupal

Like many Drupal developers, we have become big fans of decoupled front-ends using Drupal as a RESTful backend (a.k.a. "headless" Drupal). The myriad of authorization options can be confusing, however. We've settled on OAuth 2.0 for most situations. When OAuth is brought up, many people will think of the single-sign-on flow in a browser, with the associated redirects and permission dialogs. This flow is widely used, but not always a good fit for first-party applications, or machine-to-machine API interactions.


Filed under:

Like many Drupal developers, we have become big fans of decoupled front-ends using Drupal as a RESTful backend (a.k.a. "headless" Drupal). The myriad of authorization options can be confusing, however. We've settled on OAuth 2.0 for most situations. When OAuth is brought up, many people will think of the single-sign-on flow in a browser, with the associated redirects and permission dialogs. This flow is widely used, but not always a good fit for first-party applications, or machine-to-machine API interactions.

However, an under-appreciated feature of OAuth 2.0 is the "password" grant type. Quite simply, it allows the client to exchange a username and password for a bearer token. It functions much like a session cookie, but with the benefit of a standardized protocol (and without the CSRF problems that can occur if session cookies aren't handled carefully).

Here's what the flow looks like using the Drupal OAuth2 Server and Services module as an example:

POST /oauth2/token HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded
 
grant_type=password&client_id=default&username=alice&password=secret
HTTP/1.1 200 OK
Content-Type: application/json
 
{
  "access_token":"2a91adb0335be14b665a57448ccc45bafd50fb73",
  "expires_in":3600,
  "token_type":"Bearer",
  "scope":null,
  "refresh_token":"6297399d225064e6be01d2811b0e99415742bdd5"
}

Now the client has a bearer token, and it's added to the Authorization header of subsequent requests. Unlike OAuth 1.0, there is no need for complicated cryptographic signatures of each request.

GET /api/node.json HTTP/1.1
Host: example.com
Authorization: Bearer 2a91adb0335be14b665a57448ccc45bafd50fb73
HTTP/1.1 200 OK
Content-Type: application/json
 
[
   {
      "nid":"1",
      "vid":"1",
      "type":"article",
      "language":"und",
      "title":"foo",
      "uid":"1",
      "status":"1",
      "created":"1410328315",
      "changed":"1410328315",
      "comment":"2",
      "promote":"1",
      "sticky":"0",
      "tnid":"0",
      "translate":"0",
      "uri":"http://example/api/node/1"
   }
]

I'll close with some cautions. The "password" grant type doesn't use a client secret, which makes it a "public client" in OAuth parlance. This means anyone with a valid password can access the API, with client code of their own choosing, and all client apps are treated equally by the server (this could be a feature or a bug, depending on your perspective). It's also not a good idea for third-party apps to use this method, because it requires the client app to collect the user's password. For those scenarios, stick with the other grant types.

Similar posts

Get notified on new marketing insights

Be the first to know about new B2B SaaS Marketing insights to build or refine your marketing function with the tools and knowledge of today’s industry.