Commit 8d68697

mo <mo@mokhan.ca>
2018-10-28 21:06:33
add example of authorization code grant flow.
1 parent fd94f12
app/controllers/oauth/tokens_controller.rb
@@ -2,6 +2,8 @@
 
 module Oauth
   class TokensController < ApplicationController
+    protect_from_forgery with: :null_session
+
     def create
       response.headers['Cache-Control'] = 'no-store'
       response.headers['Pragma'] = 'no-cache'
config/jekyll.yml
@@ -17,7 +17,7 @@ title: Proof - API Documentation
 email: mokha@example.com
 description: >- # this means to ignore newlines until "baseurl:"
   API documentation for Proof.
-baseurl: "doc" # the subpath of your site, e.g. /blog
+baseurl: "/doc" # the subpath of your site, e.g. /blog
 url: "" # the base hostname & protocol for your site, e.g. http://example.com
 github_username:  mokhan
 source: 'doc'
doc/_includes/get-well-known-oauth-authorization-server.html
@@ -34,7 +34,7 @@ Referrer-Policy: strict-origin-when-cross-origin
 Content-Type: application/json; charset=utf-8
 Etag: W/"7f1eee6ebfc3008c58d630548ed1707c"
 Cache-Control: max-age=0, private, must-revalidate
-X-Request-Id: 12be87d2-f521-4366-916e-c4de2495dc37
+X-Request-Id: fd71ef5e-db78-40c8-9370-5bf7f895d8ce
 Transfer-Encoding: chunked
 ```
 
doc/_includes/oauth-tokens-authorization-code.html
@@ -0,0 +1,63 @@
+
+#### POST http://localhost:5000/oauth/tokens
+
+Example curl request:
+
+```bash
+$ curl http://localhost:5000/oauth/tokens \
+  -X POST \
+  -d '{"grant_type":"authorization_code","code":"FbMvnDUuS9P197L1VAa8wTaV"}' \
+  -H "Accept: application/json" \
+  -H "Content-Type: application/json" \
+  -H "User-Agent: net/hippie 0.1.9" \
+  -H "Authorization: Basic YjBkYzc4MzUtOGI1NC00NjRhLTk0MmItN2E5NDBhZmM2ZDllOjFhWWNBVWZ0R0s1Q0xBbk1HODdYTmZWdg==" \
+  -H "Accept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3"
+```
+Request Headers:
+
+```text
+Accept: application/json
+Content-Type: application/json
+User-Agent: net/hippie 0.1.9
+Authorization: Basic YjBkYzc4MzUtOGI1NC00NjRhLTk0MmItN2E5NDBhZmM2ZDllOjFhWWNBVWZ0R0s1Q0xBbk1HODdYTmZWdg==
+Accept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3
+```
+
+
+Request Body:
+```json
+{
+  "grant_type": "authorization_code",
+  "code": "FbMvnDUuS9P197L1VAa8wTaV"
+}
+```
+
+Response Headers:
+
+```text
+X-Frame-Options: SAMEORIGIN
+X-Xss-Protection: 1; mode=block
+X-Content-Type-Options: nosniff
+X-Download-Options: noopen
+X-Permitted-Cross-Domain-Policies: none
+Referrer-Policy: strict-origin-when-cross-origin
+Cache-Control: private, no-store
+Pragma: no-cache
+Content-Type: application/json; charset=utf-8
+Etag: W/"2778e3b5f668fcdcd35b51a2ef5cf5c8"
+X-Request-Id: c21b24f2-8ffe-4759-bced-d888c7acd509
+Transfer-Encoding: chunked
+```
+
+
+Response Body:
+```json
+{
+  "access_token": "eyJhbGciOiJSUzI1NiJ9.eyJleHAiOjE1NDA3NjQyMjAsImlhdCI6MTU0MDc2MDYyMCwiaXNzIjoiaHR0cDovL3Byb29mLnRlc3QvbWV0YWRhdGEiLCJuYmYiOjE1NDA3NjA2MjAsImF1ZCI6ImIwZGM3ODM1LThiNTQtNDY0YS05NDJiLTdhOTQwYWZjNmQ5ZSIsImp0aSI6ImU3ODYyNjNkLTkzYmItNDFjMy05ODk2LTQxMTg0NWNhZDQxZSIsInN1YiI6IjM3NzI4NGRiLWExMGYtNGViMC04YTA5LWRhNjdiMThlNGIzNiIsInRva2VuX3R5cGUiOiJhY2Nlc3MifQ.pL7TpT2AeUPTNodAhUn8T8GJOONEbKp10sWoN8D6JT_2fEJcnEKmm-AyJ0GbbFP08ZeIHJxb7hBVsPFI7clXxVq7tYy51H0cDF9SBrDnOiBsXb3Ku2iCfs0R2-7OkeYY-uay1-S98vZwYs3OzqCxC1rB5LUumLVhpe9lo0qD9DXb6pKYjHW7CqRbPNe4vEEEeRxI-u7_zxx6yYn-Sk6tfu8sf-urr-iX6An7grc8aZJ52xrPNCEjiMzPgGu6SF6LXu-C-d_l56hpc982Rol9bMyDXFRpiJ8SnuZiu5cMQ1WDGshURjfvPRGNT4Rn-wbTOERqa484Rwmn8X4n0yIFcQ",
+  "token_type": "Bearer",
+  "expires_in": 3600,
+  "refresh_token": "eyJhbGciOiJSUzI1NiJ9.eyJleHAiOjE1NDA4NDcwMjAsImlhdCI6MTU0MDc2MDYyMCwiaXNzIjoiaHR0cDovL3Byb29mLnRlc3QvbWV0YWRhdGEiLCJuYmYiOjE1NDA3NjA2MjAsImF1ZCI6ImIwZGM3ODM1LThiNTQtNDY0YS05NDJiLTdhOTQwYWZjNmQ5ZSIsImp0aSI6ImUxODNiMzExLWMyZjktNGQ3Mi1hOGU2LTdlMjU0YzlkMjE2ZiIsInN1YiI6IjM3NzI4NGRiLWExMGYtNGViMC04YTA5LWRhNjdiMThlNGIzNiIsInRva2VuX3R5cGUiOiJyZWZyZXNoIn0.m0Ht55DA-14kJOje9NqW35Kcp3IW_CuXyvzsqescKm4ss5TI_pg3ku8cuUpgszTSiAVf1RW-ETkodrazRlje2yi34Fjn6v5FbXqtIk8nl_8rW_M-aVLZMgd4PGQ5MUGp1blua6uI9o6XKHxOCLbucSpYZ7XtvKVav2OuYeU0_j7IeC_SEQj0tAv6LiMgZ1z3IG4ZysvWHDVPOEMX7Z-klJVXU4cND4MwA925ogSjt6jRaCWpgrigEWrtO3Li6dapQ-EPeJa2GRE6G9QHSIc41wDcRCty5m7Bbd044KRAkvJRhCGrkSMTE7xLPW8xQriBGVKZElmRvySBixofbXFlfg"
+}
+```
+
+
doc/_posts/2018-10-28-oauth-tokens.markdown
@@ -0,0 +1,42 @@
+---
+layout: post
+title:  "OAuth 2.0 - Tokens"
+date:   2018-10-28 14:00:00 -0700
+permalink: /oauth/tokens.html
+categories: oauth
+---
+
+The Tokens endpoint adheres to [RFC-6749](https://tools.ietf.org/html/rfc6749).
+
+## Authorization Code Grant Flow
+
+```text
+    +----------+
+    | Resource |
+    |   Owner  |
+    |          |
+    +----------+
+        ^
+        |
+       (B)
+    +----|-----+          Client Identifier      +---------------+
+    |         -+----(A)-- & Redirection URI ---->|               |
+    |  User-   |                                 | Authorization |
+    |  Agent  -+----(B)-- User authenticates --->|     Server    |
+    |          |                                 |               |
+    |         -+----(C)-- Authorization Code ---<|               |
+    +-|----|---+                                 +---------------+
+      |    |                                         ^      v
+     (A)  (C)                                        |      |
+      |    |                                         |      |
+      ^    v                                         |      |
+    +---------+                                      |      |
+    |         |>---(D)-- Authorization Code ---------'      |
+    |  Client |          & Redirection URI                  |
+    |         |                                             |
+    |         |<---(E)----- Access Token -------------------'
+    +---------+       (w/ Optional Refresh Token)
+```
+[RFC-6749 Section 4.1](https://tools.ietf.org/html/rfc6749#section-4.1)
+
+{% include oauth-tokens-authorization-code.html %}
lib/tasks/doc.rake
@@ -22,7 +22,7 @@ namespace :doc do
   end
 
   desc "Watch and rebuild static pages"
-  task watch: [:environment] do
+  task watch: [:clean, :environment] do
     custom_options = default_options.merge(watch: true)
     Jekyll::Commands::Build.process(custom_options)
   end
spec/documentation.rb
@@ -28,13 +28,24 @@ RSpec.configure do |config|
 end
 
 RSpec.describe "documentation" do
-  let(:client) { Net::Hippie::Client.new(verify_mode: OpenSSL::SSL::VERIFY_NONE) }
+  let(:hippie) { Net::Hippie::Client.new(verify_mode: OpenSSL::SSL::VERIFY_NONE) }
   let(:host) { ENV.fetch('HOST', 'proof.test') }
   let(:scheme) { ENV.fetch('SCHEME', 'https') }
 
   specify do
     VCR.use_cassette("get-well-known-oauth-authorization-server") do
-      response = client.get("#{scheme}://#{host}/.well-known/oauth-authorization-server")
+      response = hippie.get("#{scheme}://#{host}/.well-known/oauth-authorization-server")
+      expect(response.code).to eql('200')
+    end
+  end
+
+  specify do
+    client = create(:client)
+    authorization = create(:authorization, client: client)
+    headers = { 'Authorization' => ActionController::HttpAuthentication::Basic.encode_credentials(client.to_param, client.password) }
+    body = { grant_type: 'authorization_code', code: authorization.code }
+    VCR.use_cassette("oauth-tokens-authorization-code") do
+      response = hippie.post("#{scheme}://#{host}/oauth/tokens", body: body, headers: headers)
       expect(response.code).to eql('200')
     end
   end