diff --git a/app/controllers/platform/api/v1/users_controller.rb b/app/controllers/platform/api/v1/users_controller.rb index 453e475b0..7b9284cd9 100644 --- a/app/controllers/platform/api/v1/users_controller.rb +++ b/app/controllers/platform/api/v1/users_controller.rb @@ -1,9 +1,9 @@ class Platform::Api::V1::UsersController < PlatformController # ref: https://stackoverflow.com/a/45190318/939299 # set resource is called for other actions already in platform controller - # we want to add login to that chain as well - before_action(only: [:login]) { set_resource } - before_action(only: [:login]) { validate_platform_app_permissible } + # we want to add login and token to that chain as well + before_action(only: [:login, :token]) { set_resource } + before_action(only: [:login, :token]) { validate_platform_app_permissible } def show; end @@ -18,6 +18,8 @@ class Platform::Api::V1::UsersController < PlatformController render json: { url: @resource.generate_sso_link } end + def token; end + def update @resource.assign_attributes(user_update_params) diff --git a/app/views/platform/api/v1/users/token.json.jbuilder b/app/views/platform/api/v1/users/token.json.jbuilder new file mode 100644 index 000000000..d9d5468d7 --- /dev/null +++ b/app/views/platform/api/v1/users/token.json.jbuilder @@ -0,0 +1,9 @@ +json.access_token @resource.access_token.token +json.expiry nil +json.user do + json.id @resource.id + json.name @resource.name + json.display_name @resource.display_name + json.email @resource.email + json.pubsub_token @resource.pubsub_token +end diff --git a/config/routes.rb b/config/routes.rb index ee6ec5e8a..13866f01e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -396,6 +396,7 @@ Rails.application.routes.draw do resources :users, only: [:create, :show, :update, :destroy] do member do get :login + post :token end end resources :agent_bots, only: [:index, :create, :show, :update, :destroy] do diff --git a/spec/controllers/platform/api/v1/users_controller_spec.rb b/spec/controllers/platform/api/v1/users_controller_spec.rb index 895f30b29..c73a03654 100644 --- a/spec/controllers/platform/api/v1/users_controller_spec.rb +++ b/spec/controllers/platform/api/v1/users_controller_spec.rb @@ -76,6 +76,54 @@ RSpec.describe 'Platform Users API', type: :request do end end + describe 'POST /platform/api/v1/users/{user_id}/token' do + context 'when it is an unauthenticated platform app' do + it 'returns unauthorized' do + post "/platform/api/v1/users/#{user.id}/token" + expect(response).to have_http_status(:unauthorized) + end + end + + context 'when it is an invalid platform app token' do + it 'returns unauthorized' do + post "/platform/api/v1/users/#{user.id}/token", headers: { api_access_token: 'invalid' }, as: :json + expect(response).to have_http_status(:unauthorized) + end + end + + context 'when it is an authenticated platform app' do + let(:platform_app) { create(:platform_app) } + + it 'returns unauthorized when its not a permissible object' do + post "/platform/api/v1/users/#{user.id}/token", headers: { api_access_token: platform_app.access_token.token }, as: :json + expect(response).to have_http_status(:unauthorized) + end + + it 'returns access token for the user with expiry and user info' do + create(:platform_app_permissible, platform_app: platform_app, permissible: user) + + post "/platform/api/v1/users/#{user.id}/token", + headers: { api_access_token: platform_app.access_token.token }, as: :json + + expect(response).to have_http_status(:success) + data = response.parsed_body + + # Check access token and expiry + expect(data['access_token']).to eq(user.access_token.token) + expect(data['expiry']).to be_nil + + # Check user info + expect(data['user']).to include( + 'id' => user.id, + 'name' => user.name, + 'display_name' => user.display_name, + 'email' => user.email, + 'pubsub_token' => user.pubsub_token + ) + end + end + end + describe 'POST /platform/api/v1/users/' do context 'when it is an unauthenticated platform app' do it 'returns unauthorized' do diff --git a/swagger/paths/index.yml b/swagger/paths/index.yml index 769f38c27..79ecd1c2e 100644 --- a/swagger/paths/index.yml +++ b/swagger/paths/index.yml @@ -64,6 +64,11 @@ - $ref: '#/parameters/platform_user_id' get: $ref: './platform/users/login.yml' +/platform/api/v1/users/{id}/token: + parameters: + - $ref: '#/parameters/platform_user_id' + post: + $ref: './platform/users/token.yml' # ---------------- end of platform path -----------# diff --git a/swagger/paths/platform/users/token.yml b/swagger/paths/platform/users/token.yml new file mode 100644 index 000000000..f4fedc311 --- /dev/null +++ b/swagger/paths/platform/users/token.yml @@ -0,0 +1,42 @@ +tags: + - Users +operationId: post-user-token +summary: Get User Access Token +description: Get the access token of a user +security: + - platformAppApiKey: [] +responses: + 200: + description: Success + schema: + type: object + properties: + access_token: + type: string + description: Access token of the user + expiry: + type: [integer, "null"] + description: Expiry timestamp + user: + type: object + properties: + id: + type: integer + description: User ID + name: + type: string + description: User's full name + display_name: + type: string + description: User's display name + email: + type: string + description: User's email address + pubsub_token: + type: string + description: User's pubsub token + 401: + description: Unauthorized + 404: + description: The given user does not exist + diff --git a/swagger/swagger.json b/swagger/swagger.json index 4e557e964..68cd11eff 100644 --- a/swagger/swagger.json +++ b/swagger/swagger.json @@ -655,6 +655,78 @@ } } }, + "/platform/api/v1/users/{id}/token": { + "parameters": [ + { + "$ref": "#/parameters/platform_user_id" + } + ], + "post": { + "tags": [ + "Users" + ], + "operationId": "post-user-token", + "summary": "Get User Access Token", + "description": "Get the access token of a user", + "security": [ + { + "platformAppApiKey": [] + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object", + "properties": { + "access_token": { + "type": "string", + "description": "Access token of the user" + }, + "expiry": { + "type": [ + "integer", + "null" + ], + "description": "Expiry timestamp" + }, + "user": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "description": "User ID" + }, + "name": { + "type": "string", + "description": "User's full name" + }, + "display_name": { + "type": "string", + "description": "User's display name" + }, + "email": { + "type": "string", + "description": "User's email address" + }, + "pubsub_token": { + "type": "string", + "description": "User's pubsub token" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "404": { + "description": "The given user does not exist" + } + } + } + }, "/public/api/v1/inboxes/{inbox_identifier}": { "parameters": [ {