This is mainly for my own notes (I’ll update), but I’m going to use OAuth2 for an API I’ll be building using Apigility. First thing I did was add a client into the oauth_clients table. the password should be bcrypted, and as I’m doing a server to server situation (my web site (the client) to the api) i type authorization_code into the grant_type. In the redirect_url put /oauth/receivecode
Next up I had issues getting the Postman client OAuth setup to work correctly, so I decided to use an awesome cli alternative, HTTPie, which can be installed by sudo apt-get install httpie.Run the following command to request an authorization code:
http --verify no -f POST https://api.awesome.del/oauth/authorize client_id=testclient response_type=code redirect_uri=/oauth/receivecode state=xyz authorized=yes
The –verify no option stops it freaking out if the SSL certificate (OAuth2 MUST be used on port 443!) is a self signed one. We pass in the client_id, response_type, a redirect_uri, state can be anything (available to use for csrf?), and authorized=yes is the form variable on apigilities authorization page. You should get something like this:
HTTP/1.1 302 Found Connection: close Content-Length: 0 Content-Type: text/html; charset=UTF-8 Date: Tue, 28 Jul 2015 05:36:56 GMT Location: /oauth/receivecode?code=668d8b8d8ac4442fdf51419bf89c33f8b49f9971&state=xyz Server: Apache/2.4.12 (Ubuntu)
As you can see, $_GET[‘code’] is there. Once we have authorised a client to the api, it adds a row to oauth_authorization_codes, with the client, callback, and an expiry date not long at all after being generated. Using the code variable, you run the following command:
http --verify no -f POST https://api.awesome.del/oauth client_id=testclient client_secret=testpass grant_type=authorization_code redirect_uri=/oauth/receivecode code=668d8b8d8ac4442fdf51419bf89c33f8b49f9971
If all is going well you should see this:
HTTP/1.1 200 OK Cache-Control: no-store Connection: close Content-Type: application/json Date: Tue, 28 Jul 2015 05:43:02 GMT Pragma: no-cache Server: Apache/2.4.12 (Ubuntu) Transfer-Encoding: chunked { "access_token": "a920d6e7d85a2eb6225c07efb17c0f1fb7b5e9e6", "expires_in": 3600, "refresh_token": "fea627801b8d1d4fce095c7cef6dde7c0d3b5850", "scope": null, "token_type": "Bearer" }
Now that you have the access_token and refresh_token, we can start calling the sections of our api that we secure up! Currently I have a /ping endpoint that returns the server time, just for testing connectivity. In the Apigility Panel, click on the name of the API, and set the authentication type to your OAuth2 one. Then in your api service (ping in my example), in the authorization tab, click GET checkbox to run authorization on GET /ping. Now if you access /ping without authorisation, you should see the following:
{ "type": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html", "title": "Forbidden", "status": 403, "detail": "Forbidden" }
So we need to access with our access_token. At this point I ran into an annoying problem, which to save you a lot of hassle, was this; that Apache 2.4 is set by default to strip out the Authorization Header! Amazingly, my answer was in my own post about getting Basic HTTP Authentication working in puPHPet! You need to set in your vhosts (or in my below example, the puphpet config.yaml) a setenvif:
setenvif: - 'Authorization "(.*)" HTTP_AUTHORIZATION=$1'
Reprovision your puppet box or restart apache if you edited your vhosts file. No we should be able to accept requests with an access_token:
http --verify no GET https://api.awesome.del/ping "Authorization:Bearera920d6e7d85a2eb6225c07efb17c0f1fb7b5e9e6"
And you should see:
HTTP/1.1 200 OK Connection: close Content-Type: application/json; charset=utf-8 Date: Tue, 28 Jul 2015 21:06:10 GMT Server: Apache/2.4.12 (Ubuntu) Transfer-Encoding: chunked { "ack": "2015-07-28 21:06:12" }
So now we have resources which can be set public, and which can require authorisation. I’ll update this once I learn some more about the oauth_scopes. Have fun 🙂