diff --git a/app/controllers/my/access_tokens_controller.rb b/app/controllers/my/access_tokens_controller.rb index 99c87893f..82cd93842 100644 --- a/app/controllers/my/access_tokens_controller.rb +++ b/app/controllers/my/access_tokens_controller.rb @@ -15,9 +15,18 @@ class My::AccessTokensController < ApplicationController def create access_token = my_access_tokens.create!(access_token_params) - expiring_id = verifier.generate access_token.id, expires_in: 10.seconds - redirect_to my_access_token_path(expiring_id) + respond_to do |format| + format.html do + expiring_id = verifier.generate access_token.id, expires_in: 10.seconds + redirect_to my_access_token_path(expiring_id) + end + + format.json do + render status: :created, json: \ + { token: access_token.token, description: access_token.description, permission: access_token.permission } + end + end end def destroy diff --git a/docs/API.md b/docs/API.md index 21bd24b86..e55faf400 100644 --- a/docs/API.md +++ b/docs/API.md @@ -134,6 +134,48 @@ __Response:__ Returns `204 No Content` on success. +#### Create an access token via the API + +You can programmatically create a personal access token using either a session cookie or an existing Bearer token: + +```bash +curl -X POST \ + -H "Content-Type: application/json" \ + -H "Accept: application/json" \ + -H "Cookie: session_token=eyJfcmFpbHMi..." \ + -d '{"access_token": {"description": "Fizzy CLI", "permission": "write"}}' \ + https://app.fizzy.do/1234567/my/access_tokens +``` + +Or with a Bearer token (must have `write` permission): + +```bash +curl -X POST \ + -H "Content-Type: application/json" \ + -H "Accept: application/json" \ + -H "Authorization: Bearer put-your-access-token-here" \ + -d '{"access_token": {"description": "Fizzy CLI", "permission": "write"}}' \ + https://app.fizzy.do/1234567/my/access_tokens +``` + +The `permission` field accepts `read` or `write`. + +__Response:__ + +``` +HTTP/1.1 201 Created +``` + +```json +{ + "token": "4f9Q6d2wXr8Kp1Ls0Vz3BnTa", + "description": "Fizzy CLI", + "permission": "write" +} +``` + +Store the `token` value securely — it won't be retrievable again. Use it as a Bearer token for subsequent API requests. + ## Caching Most endpoints return [ETag](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/ETag) and [Cache-Control](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Cache-Control) headers. You can use these to avoid re-downloading unchanged data. diff --git a/test/controllers/my/access_tokens_controller_test.rb b/test/controllers/my/access_tokens_controller_test.rb index 43a90fac5..176302336 100644 --- a/test/controllers/my/access_tokens_controller_test.rb +++ b/test/controllers/my/access_tokens_controller_test.rb @@ -19,6 +19,41 @@ class My::AccessTokensControllerTest < ActionDispatch::IntegrationTest end end + test "create new token via JSON with session" do + assert_difference -> { identities(:kevin).access_tokens.count }, +1 do + post my_access_tokens_path, params: { access_token: { description: "Fizzy CLI", permission: "write" } }, as: :json + end + assert_response :created + body = @response.parsed_body + assert body["token"].present? + assert_equal "Fizzy CLI", body["description"] + assert_equal "write", body["permission"] + end + + test "create new token via JSON with bearer token" do + sign_out + bearer_token = { "HTTP_AUTHORIZATION" => "Bearer #{identity_access_tokens(:davids_api_token).token}" } + + assert_difference -> { identities(:david).access_tokens.count }, +1 do + post my_access_tokens_path, params: { access_token: { description: "Fizzy CLI", permission: "read" } }, env: bearer_token, as: :json + end + assert_response :created + body = @response.parsed_body + assert body["token"].present? + assert_equal "Fizzy CLI", body["description"] + assert_equal "read", body["permission"] + end + + test "cannot create new token via JSON with read-only bearer token" do + sign_out + bearer_token = { "HTTP_AUTHORIZATION" => "Bearer #{identity_access_tokens(:jasons_api_token).token}" } + + assert_no_difference -> { identities(:jason).access_tokens.count } do + post my_access_tokens_path, params: { access_token: { description: "Fizzy CLI", permission: "read" } }, env: bearer_token, as: :json + end + assert_response :unauthorized + end + test "accessing new token after reveal window redirects to index" do assert_changes -> { identities(:kevin).access_tokens.count }, +1 do post my_access_tokens_path, params: { access_token: { description: "GitHub", permission: "read" } }