From 73c929f25e322ab466c76e9fde8d297d0b24bb17 Mon Sep 17 00:00:00 2001 From: Faruk AYDIN Date: Mon, 22 Apr 2024 15:19:17 +0200 Subject: [PATCH 1/3] feat: Create access tokens model --- .../20240422130323_create_access_tokens.js | 15 +++++++++ packages/backend/src/models/access-token.js | 32 +++++++++++++++++++ packages/backend/src/models/user.js | 9 ++++++ 3 files changed, 56 insertions(+) create mode 100644 packages/backend/src/db/migrations/20240422130323_create_access_tokens.js create mode 100644 packages/backend/src/models/access-token.js diff --git a/packages/backend/src/db/migrations/20240422130323_create_access_tokens.js b/packages/backend/src/db/migrations/20240422130323_create_access_tokens.js new file mode 100644 index 00000000..d71af5b8 --- /dev/null +++ b/packages/backend/src/db/migrations/20240422130323_create_access_tokens.js @@ -0,0 +1,15 @@ +export async function up(knex) { + return knex.schema.createTable('access_tokens', (table) => { + table.uuid('id').primary().defaultTo(knex.raw('gen_random_uuid()')); + table.string('token').notNullable(); + table.integer('expires_in').notNullable(); + table.timestamp('revoked_at').nullable(); + table.uuid('user_id').references('id').inTable('users'); + + table.timestamps(true, true); + }); +} + +export async function down(knex) { + return knex.schema.dropTable('access_tokens'); +} diff --git a/packages/backend/src/models/access-token.js b/packages/backend/src/models/access-token.js new file mode 100644 index 00000000..7afb4776 --- /dev/null +++ b/packages/backend/src/models/access-token.js @@ -0,0 +1,32 @@ +import Base from './base.js'; +import User from './user.js'; + +class AccessToken extends Base { + static tableName = 'access_tokens'; + + static jsonSchema = { + type: 'object', + required: ['token', 'expiresIn'], + + properties: { + id: { type: 'string', format: 'uuid' }, + userId: { type: 'string', format: 'uuid' }, + token: { type: 'string', minLength: 32 }, + expiresIn: { type: 'integer' }, + revokedAt: { type: ['string', 'null'], format: 'date-time' }, + }, + }; + + static relationMappings = () => ({ + user: { + relation: Base.BelongsToOneRelation, + modelClass: User, + join: { + from: 'access_tokens.user_id', + to: 'users.id', + }, + }, + }); +} + +export default AccessToken; diff --git a/packages/backend/src/models/user.js b/packages/backend/src/models/user.js index 9452e8b0..aca2ea7b 100644 --- a/packages/backend/src/models/user.js +++ b/packages/backend/src/models/user.js @@ -8,6 +8,7 @@ import userAbility from '../helpers/user-ability.js'; import createAuthTokenByUserId from '../helpers/create-auth-token-by-user-id.js'; import Base from './base.js'; import App from './app.js'; +import AccessToken from './access-token.js'; import Connection from './connection.js'; import Execution from './execution.js'; import Flow from './flow.js'; @@ -42,6 +43,14 @@ class User extends Base { }; static relationMappings = () => ({ + accessTokens: { + relation: Base.HasManyRelation, + modelClass: AccessToken, + join: { + from: 'users.id', + to: 'access_tokens.user_id', + }, + }, connections: { relation: Base.HasManyRelation, modelClass: Connection, From 6a7cdf257016d41dbfed12798e9b7daa1c2df71e Mon Sep 17 00:00:00 2001 From: Faruk AYDIN Date: Mon, 22 Apr 2024 16:57:34 +0200 Subject: [PATCH 2/3] feat: Use persisted access tokens for authentication --- .../v1/admin/apps/get-auth-client.ee.test.js | 2 +- .../v1/admin/apps/get-auth-clients.ee.test.js | 2 +- .../get-permissions-catalog.ee.test.js | 2 +- .../api/v1/admin/roles/get-role.ee.test.js | 2 +- .../api/v1/admin/roles/get-roles.ee.test.js | 2 +- .../get-role-mappings.ee.test.js | 2 +- .../get-saml-auth-provider.ee.test.js | 2 +- .../get-saml-auth-providers.ee.test.js | 2 +- .../api/v1/admin/users/get-user.ee.test.js | 2 +- .../api/v1/admin/users/get-users.ee.test.js | 2 +- .../api/v1/apps/get-action-substeps.test.js | 2 +- .../api/v1/apps/get-actions.test.js | 2 +- .../controllers/api/v1/apps/get-app.test.js | 2 +- .../controllers/api/v1/apps/get-apps.test.js | 2 +- .../api/v1/apps/get-auth-client.ee.test.js | 2 +- .../api/v1/apps/get-auth-clients.ee.test.js | 2 +- .../controllers/api/v1/apps/get-auth.test.js | 2 +- .../api/v1/apps/get-config.ee.test.js | 2 +- .../api/v1/apps/get-connections.test.js | 2 +- .../controllers/api/v1/apps/get-flows.test.js | 2 +- .../api/v1/apps/get-trigger-substeps.test.js | 2 +- .../api/v1/apps/get-triggers.test.js | 2 +- .../api/v1/connections/create-test.test.js | 2 +- .../api/v1/connections/get-flows.test.js | 2 +- .../v1/executions/get-execution-steps.test.js | 2 +- .../api/v1/executions/get-execution.test.js | 2 +- .../api/v1/executions/get-executions.test.js | 2 +- .../controllers/api/v1/flows/get-flow.test.js | 2 +- .../api/v1/flows/get-flows.test.js | 2 +- .../api/v1/payment/get-paddle-info.ee.test.js | 2 +- .../api/v1/payment/get-plans.ee.test.js | 2 +- .../api/v1/steps/create-dynamic-data.test.js | 2 +- .../v1/steps/create-dynamic-fields.test.js | 2 +- .../api/v1/steps/get-connection.test.js | 2 +- .../api/v1/steps/get-previous-steps.test.js | 2 +- .../controllers/api/v1/users/get-apps.test.js | 2 +- .../api/v1/users/get-current-user.test.js | 2 +- .../api/v1/users/get-invoices.ee.test.js | 2 +- .../v1/users/get-plan-and-usage.ee.test.js | 2 +- .../api/v1/users/get-subscription.ee.test.js | 4 ++-- .../api/v1/users/get-user-trial.ee.test.js | 2 +- .../backend/src/graphql/mutations/login.js | 2 +- .../backend/src/helpers/authentication.js | 19 +++++++++++++++---- .../src/helpers/authentication.test.js | 4 ++-- .../helpers/create-auth-token-by-user-id.js | 16 +++++++++++----- packages/backend/src/helpers/passport.js | 4 ++-- packages/backend/src/models/user.js | 2 +- 47 files changed, 74 insertions(+), 57 deletions(-) diff --git a/packages/backend/src/controllers/api/v1/admin/apps/get-auth-client.ee.test.js b/packages/backend/src/controllers/api/v1/admin/apps/get-auth-client.ee.test.js index f9f6c7ee..581c49e7 100644 --- a/packages/backend/src/controllers/api/v1/admin/apps/get-auth-client.ee.test.js +++ b/packages/backend/src/controllers/api/v1/admin/apps/get-auth-client.ee.test.js @@ -22,7 +22,7 @@ describe('GET /api/v1/admin/apps/:appKey/auth-clients/:appAuthClientId', () => { appKey: 'deepl', }); - token = createAuthTokenByUserId(currentUser.id); + token = await createAuthTokenByUserId(currentUser.id); }); it('should return specified app auth client', async () => { diff --git a/packages/backend/src/controllers/api/v1/admin/apps/get-auth-clients.ee.test.js b/packages/backend/src/controllers/api/v1/admin/apps/get-auth-clients.ee.test.js index 0f59a846..0dfd472c 100644 --- a/packages/backend/src/controllers/api/v1/admin/apps/get-auth-clients.ee.test.js +++ b/packages/backend/src/controllers/api/v1/admin/apps/get-auth-clients.ee.test.js @@ -17,7 +17,7 @@ describe('GET /api/v1/admin/apps/:appKey/auth-clients', () => { adminRole = await createRole({ key: 'admin' }); currentUser = await createUser({ roleId: adminRole.id }); - token = createAuthTokenByUserId(currentUser.id); + token = await createAuthTokenByUserId(currentUser.id); }); it('should return specified app auth client info', async () => { diff --git a/packages/backend/src/controllers/api/v1/admin/permissions/get-permissions-catalog.ee.test.js b/packages/backend/src/controllers/api/v1/admin/permissions/get-permissions-catalog.ee.test.js index 44a791dc..bbeba16b 100644 --- a/packages/backend/src/controllers/api/v1/admin/permissions/get-permissions-catalog.ee.test.js +++ b/packages/backend/src/controllers/api/v1/admin/permissions/get-permissions-catalog.ee.test.js @@ -14,7 +14,7 @@ describe('GET /api/v1/admin/permissions/catalog', () => { role = await createRole({ key: 'admin' }); currentUser = await createUser({ roleId: role.id }); - token = createAuthTokenByUserId(currentUser.id); + token = await createAuthTokenByUserId(currentUser.id); }); it('should return roles', async () => { diff --git a/packages/backend/src/controllers/api/v1/admin/roles/get-role.ee.test.js b/packages/backend/src/controllers/api/v1/admin/roles/get-role.ee.test.js index bf2b7451..020539f4 100644 --- a/packages/backend/src/controllers/api/v1/admin/roles/get-role.ee.test.js +++ b/packages/backend/src/controllers/api/v1/admin/roles/get-role.ee.test.js @@ -18,7 +18,7 @@ describe('GET /api/v1/admin/roles/:roleId', () => { permissionTwo = await createPermission({ roleId: role.id }); currentUser = await createUser({ roleId: role.id }); - token = createAuthTokenByUserId(currentUser.id); + token = await createAuthTokenByUserId(currentUser.id); }); it('should return role', async () => { diff --git a/packages/backend/src/controllers/api/v1/admin/roles/get-roles.ee.test.js b/packages/backend/src/controllers/api/v1/admin/roles/get-roles.ee.test.js index 2161e388..6f22f50b 100644 --- a/packages/backend/src/controllers/api/v1/admin/roles/get-roles.ee.test.js +++ b/packages/backend/src/controllers/api/v1/admin/roles/get-roles.ee.test.js @@ -15,7 +15,7 @@ describe('GET /api/v1/admin/roles', () => { roleTwo = await createRole({ key: 'user' }); currentUser = await createUser({ roleId: roleOne.id }); - token = createAuthTokenByUserId(currentUser.id); + token = await createAuthTokenByUserId(currentUser.id); }); it('should return roles', async () => { diff --git a/packages/backend/src/controllers/api/v1/admin/saml-auth-providers/get-role-mappings.ee.test.js b/packages/backend/src/controllers/api/v1/admin/saml-auth-providers/get-role-mappings.ee.test.js index 10ca9f33..42f37a3a 100644 --- a/packages/backend/src/controllers/api/v1/admin/saml-auth-providers/get-role-mappings.ee.test.js +++ b/packages/backend/src/controllers/api/v1/admin/saml-auth-providers/get-role-mappings.ee.test.js @@ -28,7 +28,7 @@ describe('GET /api/v1/admin/saml-auth-providers/:samlAuthProviderId/role-mapping remoteRoleName: 'User', }); - token = createAuthTokenByUserId(currentUser.id); + token = await createAuthTokenByUserId(currentUser.id); }); it('should return role mappings', async () => { diff --git a/packages/backend/src/controllers/api/v1/admin/saml-auth-providers/get-saml-auth-provider.ee.test.js b/packages/backend/src/controllers/api/v1/admin/saml-auth-providers/get-saml-auth-provider.ee.test.js index 1f0b63e1..adddb53d 100644 --- a/packages/backend/src/controllers/api/v1/admin/saml-auth-providers/get-saml-auth-provider.ee.test.js +++ b/packages/backend/src/controllers/api/v1/admin/saml-auth-providers/get-saml-auth-provider.ee.test.js @@ -17,7 +17,7 @@ describe('GET /api/v1/admin/saml-auth-provider/:samlAuthProviderId', () => { currentUser = await createUser({ roleId: role.id }); samlAuthProvider = await createSamlAuthProvider(); - token = createAuthTokenByUserId(currentUser.id); + token = await createAuthTokenByUserId(currentUser.id); }); it('should return saml auth provider with specified id', async () => { diff --git a/packages/backend/src/controllers/api/v1/admin/saml-auth-providers/get-saml-auth-providers.ee.test.js b/packages/backend/src/controllers/api/v1/admin/saml-auth-providers/get-saml-auth-providers.ee.test.js index 0904cf6f..ca2106e2 100644 --- a/packages/backend/src/controllers/api/v1/admin/saml-auth-providers/get-saml-auth-providers.ee.test.js +++ b/packages/backend/src/controllers/api/v1/admin/saml-auth-providers/get-saml-auth-providers.ee.test.js @@ -18,7 +18,7 @@ describe('GET /api/v1/admin/saml-auth-providers', () => { samlAuthProviderOne = await createSamlAuthProvider(); samlAuthProviderTwo = await createSamlAuthProvider(); - token = createAuthTokenByUserId(currentUser.id); + token = await createAuthTokenByUserId(currentUser.id); }); it('should return saml auth providers', async () => { diff --git a/packages/backend/src/controllers/api/v1/admin/users/get-user.ee.test.js b/packages/backend/src/controllers/api/v1/admin/users/get-user.ee.test.js index 6a3976b9..93ee5053 100644 --- a/packages/backend/src/controllers/api/v1/admin/users/get-user.ee.test.js +++ b/packages/backend/src/controllers/api/v1/admin/users/get-user.ee.test.js @@ -18,7 +18,7 @@ describe('GET /api/v1/admin/users/:userId', () => { anotherUser = await createUser(); anotherUserRole = await anotherUser.$relatedQuery('role'); - token = createAuthTokenByUserId(currentUser.id); + token = await createAuthTokenByUserId(currentUser.id); }); it('should return specified user info', async () => { diff --git a/packages/backend/src/controllers/api/v1/admin/users/get-users.ee.test.js b/packages/backend/src/controllers/api/v1/admin/users/get-users.ee.test.js index bf1f9744..25f5ee82 100644 --- a/packages/backend/src/controllers/api/v1/admin/users/get-users.ee.test.js +++ b/packages/backend/src/controllers/api/v1/admin/users/get-users.ee.test.js @@ -28,7 +28,7 @@ describe('GET /api/v1/admin/users', () => { fullName: 'Another User', }); - token = createAuthTokenByUserId(currentUser.id); + token = await createAuthTokenByUserId(currentUser.id); }); it('should return users data', async () => { diff --git a/packages/backend/src/controllers/api/v1/apps/get-action-substeps.test.js b/packages/backend/src/controllers/api/v1/apps/get-action-substeps.test.js index 44676d9e..cc4c01a3 100644 --- a/packages/backend/src/controllers/api/v1/apps/get-action-substeps.test.js +++ b/packages/backend/src/controllers/api/v1/apps/get-action-substeps.test.js @@ -11,7 +11,7 @@ describe('GET /api/v1/apps/:appKey/actions/:actionKey/substeps', () => { beforeEach(async () => { currentUser = await createUser(); - token = createAuthTokenByUserId(currentUser.id); + token = await createAuthTokenByUserId(currentUser.id); exampleApp = await App.findOneByKey('github'); }); diff --git a/packages/backend/src/controllers/api/v1/apps/get-actions.test.js b/packages/backend/src/controllers/api/v1/apps/get-actions.test.js index 24748dce..52219147 100644 --- a/packages/backend/src/controllers/api/v1/apps/get-actions.test.js +++ b/packages/backend/src/controllers/api/v1/apps/get-actions.test.js @@ -11,7 +11,7 @@ describe('GET /api/v1/apps/:appKey/actions', () => { beforeEach(async () => { currentUser = await createUser(); - token = createAuthTokenByUserId(currentUser.id); + token = await createAuthTokenByUserId(currentUser.id); }); it('should return the app actions', async () => { diff --git a/packages/backend/src/controllers/api/v1/apps/get-app.test.js b/packages/backend/src/controllers/api/v1/apps/get-app.test.js index 22013c45..2cc0d839 100644 --- a/packages/backend/src/controllers/api/v1/apps/get-app.test.js +++ b/packages/backend/src/controllers/api/v1/apps/get-app.test.js @@ -11,7 +11,7 @@ describe('GET /api/v1/apps/:appKey', () => { beforeEach(async () => { currentUser = await createUser(); - token = createAuthTokenByUserId(currentUser.id); + token = await createAuthTokenByUserId(currentUser.id); }); it('should return the app info', async () => { diff --git a/packages/backend/src/controllers/api/v1/apps/get-apps.test.js b/packages/backend/src/controllers/api/v1/apps/get-apps.test.js index a7a39e7b..87f1702a 100644 --- a/packages/backend/src/controllers/api/v1/apps/get-apps.test.js +++ b/packages/backend/src/controllers/api/v1/apps/get-apps.test.js @@ -11,7 +11,7 @@ describe('GET /api/v1/apps', () => { beforeEach(async () => { currentUser = await createUser(); - token = createAuthTokenByUserId(currentUser.id); + token = await createAuthTokenByUserId(currentUser.id); apps = await App.findAll(); }); diff --git a/packages/backend/src/controllers/api/v1/apps/get-auth-client.ee.test.js b/packages/backend/src/controllers/api/v1/apps/get-auth-client.ee.test.js index 7b60f397..050432ff 100644 --- a/packages/backend/src/controllers/api/v1/apps/get-auth-client.ee.test.js +++ b/packages/backend/src/controllers/api/v1/apps/get-auth-client.ee.test.js @@ -19,7 +19,7 @@ describe('GET /api/v1/apps/:appKey/auth-clients/:appAuthClientId', () => { appKey: 'deepl', }); - token = createAuthTokenByUserId(currentUser.id); + token = await createAuthTokenByUserId(currentUser.id); }); it('should return specified app auth client', async () => { diff --git a/packages/backend/src/controllers/api/v1/apps/get-auth-clients.ee.test.js b/packages/backend/src/controllers/api/v1/apps/get-auth-clients.ee.test.js index c671ce74..8bc479d9 100644 --- a/packages/backend/src/controllers/api/v1/apps/get-auth-clients.ee.test.js +++ b/packages/backend/src/controllers/api/v1/apps/get-auth-clients.ee.test.js @@ -15,7 +15,7 @@ describe('GET /api/v1/apps/:appKey/auth-clients', () => { currentUser = await createUser(); - token = createAuthTokenByUserId(currentUser.id); + token = await createAuthTokenByUserId(currentUser.id); }); it('should return specified app auth client info', async () => { diff --git a/packages/backend/src/controllers/api/v1/apps/get-auth.test.js b/packages/backend/src/controllers/api/v1/apps/get-auth.test.js index 5955ef21..a6405f70 100644 --- a/packages/backend/src/controllers/api/v1/apps/get-auth.test.js +++ b/packages/backend/src/controllers/api/v1/apps/get-auth.test.js @@ -11,7 +11,7 @@ describe('GET /api/v1/apps/:appKey/auth', () => { beforeEach(async () => { currentUser = await createUser(); - token = createAuthTokenByUserId(currentUser.id); + token = await createAuthTokenByUserId(currentUser.id); }); it('should return the app auth info', async () => { diff --git a/packages/backend/src/controllers/api/v1/apps/get-config.ee.test.js b/packages/backend/src/controllers/api/v1/apps/get-config.ee.test.js index ee286358..d10c2bd7 100644 --- a/packages/backend/src/controllers/api/v1/apps/get-config.ee.test.js +++ b/packages/backend/src/controllers/api/v1/apps/get-config.ee.test.js @@ -22,7 +22,7 @@ describe('GET /api/v1/apps/:appKey/config', () => { disabled: false, }); - token = createAuthTokenByUserId(currentUser.id); + token = await createAuthTokenByUserId(currentUser.id); }); it('should return specified app config info', async () => { diff --git a/packages/backend/src/controllers/api/v1/apps/get-connections.test.js b/packages/backend/src/controllers/api/v1/apps/get-connections.test.js index e35d1a53..c95cc467 100644 --- a/packages/backend/src/controllers/api/v1/apps/get-connections.test.js +++ b/packages/backend/src/controllers/api/v1/apps/get-connections.test.js @@ -14,7 +14,7 @@ describe('GET /api/v1/apps/:appKey/connections', () => { currentUser = await createUser(); currentUserRole = await currentUser.$relatedQuery('role'); - token = createAuthTokenByUserId(currentUser.id); + token = await createAuthTokenByUserId(currentUser.id); }); it('should return the connections data of specified app for current user', async () => { diff --git a/packages/backend/src/controllers/api/v1/apps/get-flows.test.js b/packages/backend/src/controllers/api/v1/apps/get-flows.test.js index e5280415..b53d70ca 100644 --- a/packages/backend/src/controllers/api/v1/apps/get-flows.test.js +++ b/packages/backend/src/controllers/api/v1/apps/get-flows.test.js @@ -15,7 +15,7 @@ describe('GET /api/v1/apps/:appKey/flows', () => { currentUser = await createUser(); currentUserRole = await currentUser.$relatedQuery('role'); - token = createAuthTokenByUserId(currentUser.id); + token = await createAuthTokenByUserId(currentUser.id); }); it('should return the flows data of specified app for current user', async () => { diff --git a/packages/backend/src/controllers/api/v1/apps/get-trigger-substeps.test.js b/packages/backend/src/controllers/api/v1/apps/get-trigger-substeps.test.js index 9dc2cfb0..840cb85e 100644 --- a/packages/backend/src/controllers/api/v1/apps/get-trigger-substeps.test.js +++ b/packages/backend/src/controllers/api/v1/apps/get-trigger-substeps.test.js @@ -11,7 +11,7 @@ describe('GET /api/v1/apps/:appKey/triggers/:triggerKey/substeps', () => { beforeEach(async () => { currentUser = await createUser(); - token = createAuthTokenByUserId(currentUser.id); + token = await createAuthTokenByUserId(currentUser.id); exampleApp = await App.findOneByKey('github'); }); diff --git a/packages/backend/src/controllers/api/v1/apps/get-triggers.test.js b/packages/backend/src/controllers/api/v1/apps/get-triggers.test.js index c8261681..ff825a71 100644 --- a/packages/backend/src/controllers/api/v1/apps/get-triggers.test.js +++ b/packages/backend/src/controllers/api/v1/apps/get-triggers.test.js @@ -11,7 +11,7 @@ describe('GET /api/v1/apps/:appKey/triggers', () => { beforeEach(async () => { currentUser = await createUser(); - token = createAuthTokenByUserId(currentUser.id); + token = await createAuthTokenByUserId(currentUser.id); }); it('should return the app triggers', async () => { diff --git a/packages/backend/src/controllers/api/v1/connections/create-test.test.js b/packages/backend/src/controllers/api/v1/connections/create-test.test.js index ec44cde3..152b404a 100644 --- a/packages/backend/src/controllers/api/v1/connections/create-test.test.js +++ b/packages/backend/src/controllers/api/v1/connections/create-test.test.js @@ -14,7 +14,7 @@ describe('POST /api/v1/connections/:connectionId/test', () => { currentUser = await createUser(); currentUserRole = await currentUser.$relatedQuery('role'); - token = createAuthTokenByUserId(currentUser.id); + token = await createAuthTokenByUserId(currentUser.id); }); it('should update the connection as not verified for current user', async () => { diff --git a/packages/backend/src/controllers/api/v1/connections/get-flows.test.js b/packages/backend/src/controllers/api/v1/connections/get-flows.test.js index 3cfa6d73..bc9088d6 100644 --- a/packages/backend/src/controllers/api/v1/connections/get-flows.test.js +++ b/packages/backend/src/controllers/api/v1/connections/get-flows.test.js @@ -16,7 +16,7 @@ describe('GET /api/v1/connections/:connectionId/flows', () => { currentUser = await createUser(); currentUserRole = await currentUser.$relatedQuery('role'); - token = createAuthTokenByUserId(currentUser.id); + token = await createAuthTokenByUserId(currentUser.id); }); it('should return the flows data of specified connection for current user', async () => { diff --git a/packages/backend/src/controllers/api/v1/executions/get-execution-steps.test.js b/packages/backend/src/controllers/api/v1/executions/get-execution-steps.test.js index fc43ec8b..d93fbb11 100644 --- a/packages/backend/src/controllers/api/v1/executions/get-execution-steps.test.js +++ b/packages/backend/src/controllers/api/v1/executions/get-execution-steps.test.js @@ -20,7 +20,7 @@ describe('GET /api/v1/executions/:executionId/execution-steps', () => { anotherUser = await createUser(); - token = createAuthTokenByUserId(currentUser.id); + token = await createAuthTokenByUserId(currentUser.id); }); it('should return the execution steps of current user execution', async () => { diff --git a/packages/backend/src/controllers/api/v1/executions/get-execution.test.js b/packages/backend/src/controllers/api/v1/executions/get-execution.test.js index edf59644..a6a86ce9 100644 --- a/packages/backend/src/controllers/api/v1/executions/get-execution.test.js +++ b/packages/backend/src/controllers/api/v1/executions/get-execution.test.js @@ -17,7 +17,7 @@ describe('GET /api/v1/executions/:executionId', () => { currentUser = await createUser(); currentUserRole = await currentUser.$relatedQuery('role'); - token = createAuthTokenByUserId(currentUser.id); + token = await createAuthTokenByUserId(currentUser.id); }); it('should return the execution data of current user', async () => { diff --git a/packages/backend/src/controllers/api/v1/executions/get-executions.test.js b/packages/backend/src/controllers/api/v1/executions/get-executions.test.js index cc5cbc08..49f29c9f 100644 --- a/packages/backend/src/controllers/api/v1/executions/get-executions.test.js +++ b/packages/backend/src/controllers/api/v1/executions/get-executions.test.js @@ -18,7 +18,7 @@ describe('GET /api/v1/executions', () => { anotherUser = await createUser(); - token = createAuthTokenByUserId(currentUser.id); + token = await createAuthTokenByUserId(currentUser.id); }); it('should return the executions of current user', async () => { diff --git a/packages/backend/src/controllers/api/v1/flows/get-flow.test.js b/packages/backend/src/controllers/api/v1/flows/get-flow.test.js index a3746d48..cd150f5a 100644 --- a/packages/backend/src/controllers/api/v1/flows/get-flow.test.js +++ b/packages/backend/src/controllers/api/v1/flows/get-flow.test.js @@ -16,7 +16,7 @@ describe('GET /api/v1/flows/:flowId', () => { currentUser = await createUser(); currentUserRole = await currentUser.$relatedQuery('role'); - token = createAuthTokenByUserId(currentUser.id); + token = await createAuthTokenByUserId(currentUser.id); }); it('should return the flow data of current user', async () => { diff --git a/packages/backend/src/controllers/api/v1/flows/get-flows.test.js b/packages/backend/src/controllers/api/v1/flows/get-flows.test.js index 05839619..3df8a2bb 100644 --- a/packages/backend/src/controllers/api/v1/flows/get-flows.test.js +++ b/packages/backend/src/controllers/api/v1/flows/get-flows.test.js @@ -15,7 +15,7 @@ describe('GET /api/v1/flows', () => { currentUser = await createUser(); currentUserRole = await currentUser.$relatedQuery('role'); - token = createAuthTokenByUserId(currentUser.id); + token = await createAuthTokenByUserId(currentUser.id); }); it('should return the flows data of current user', async () => { diff --git a/packages/backend/src/controllers/api/v1/payment/get-paddle-info.ee.test.js b/packages/backend/src/controllers/api/v1/payment/get-paddle-info.ee.test.js index 2c9ab70b..7fccd60f 100644 --- a/packages/backend/src/controllers/api/v1/payment/get-paddle-info.ee.test.js +++ b/packages/backend/src/controllers/api/v1/payment/get-paddle-info.ee.test.js @@ -12,7 +12,7 @@ describe('GET /api/v1/payment/paddle-info', () => { beforeEach(async () => { user = await createUser(); - token = createAuthTokenByUserId(user.id); + token = await createAuthTokenByUserId(user.id); vi.spyOn(appConfig, 'isCloud', 'get').mockReturnValue(true); vi.spyOn(billing.paddleInfo, 'vendorId', 'get').mockReturnValue( diff --git a/packages/backend/src/controllers/api/v1/payment/get-plans.ee.test.js b/packages/backend/src/controllers/api/v1/payment/get-plans.ee.test.js index 56d32c06..4f7665aa 100644 --- a/packages/backend/src/controllers/api/v1/payment/get-plans.ee.test.js +++ b/packages/backend/src/controllers/api/v1/payment/get-plans.ee.test.js @@ -11,7 +11,7 @@ describe('GET /api/v1/payment/plans', () => { beforeEach(async () => { user = await createUser(); - token = createAuthTokenByUserId(user.id); + token = await createAuthTokenByUserId(user.id); vi.spyOn(appConfig, 'isCloud', 'get').mockReturnValue(true); }); diff --git a/packages/backend/src/controllers/api/v1/steps/create-dynamic-data.test.js b/packages/backend/src/controllers/api/v1/steps/create-dynamic-data.test.js index 699eb23b..a83ac23b 100644 --- a/packages/backend/src/controllers/api/v1/steps/create-dynamic-data.test.js +++ b/packages/backend/src/controllers/api/v1/steps/create-dynamic-data.test.js @@ -18,7 +18,7 @@ describe('POST /api/v1/steps/:stepId/dynamic-data', () => { currentUser = await createUser(); currentUserRole = await currentUser.$relatedQuery('role'); - token = createAuthTokenByUserId(currentUser.id); + token = await createAuthTokenByUserId(currentUser.id); }); describe('should return dynamically created data', () => { diff --git a/packages/backend/src/controllers/api/v1/steps/create-dynamic-fields.test.js b/packages/backend/src/controllers/api/v1/steps/create-dynamic-fields.test.js index 75e27dcb..7ae163b5 100644 --- a/packages/backend/src/controllers/api/v1/steps/create-dynamic-fields.test.js +++ b/packages/backend/src/controllers/api/v1/steps/create-dynamic-fields.test.js @@ -16,7 +16,7 @@ describe('POST /api/v1/steps/:stepId/dynamic-fields', () => { currentUser = await createUser(); currentUserRole = await currentUser.$relatedQuery('role'); - token = createAuthTokenByUserId(currentUser.id); + token = await createAuthTokenByUserId(currentUser.id); }); it('should return dynamically created fields of the current users step', async () => { diff --git a/packages/backend/src/controllers/api/v1/steps/get-connection.test.js b/packages/backend/src/controllers/api/v1/steps/get-connection.test.js index 003b80bd..27e6151e 100644 --- a/packages/backend/src/controllers/api/v1/steps/get-connection.test.js +++ b/packages/backend/src/controllers/api/v1/steps/get-connection.test.js @@ -17,7 +17,7 @@ describe('GET /api/v1/steps/:stepId/connection', () => { currentUser = await createUser(); currentUserRole = await currentUser.$relatedQuery('role'); - token = createAuthTokenByUserId(currentUser.id); + token = await createAuthTokenByUserId(currentUser.id); }); it('should return the current user connection data of specified step', async () => { diff --git a/packages/backend/src/controllers/api/v1/steps/get-previous-steps.test.js b/packages/backend/src/controllers/api/v1/steps/get-previous-steps.test.js index 7e015e89..f9205295 100644 --- a/packages/backend/src/controllers/api/v1/steps/get-previous-steps.test.js +++ b/packages/backend/src/controllers/api/v1/steps/get-previous-steps.test.js @@ -17,7 +17,7 @@ describe('GET /api/v1/steps/:stepId/previous-steps', () => { currentUser = await createUser(); currentUserRole = await currentUser.$relatedQuery('role'); - token = createAuthTokenByUserId(currentUser.id); + token = await createAuthTokenByUserId(currentUser.id); }); it('should return the previous steps of the specified step of the current user', async () => { diff --git a/packages/backend/src/controllers/api/v1/users/get-apps.test.js b/packages/backend/src/controllers/api/v1/users/get-apps.test.js index 175a0f48..eb24b66a 100644 --- a/packages/backend/src/controllers/api/v1/users/get-apps.test.js +++ b/packages/backend/src/controllers/api/v1/users/get-apps.test.js @@ -17,7 +17,7 @@ describe('GET /api/v1/users/:userId/apps', () => { currentUserRole = await createRole(); currentUser = await createUser({ roleId: currentUserRole.id }); - token = createAuthTokenByUserId(currentUser.id); + token = await createAuthTokenByUserId(currentUser.id); }); it('should return all apps of the current user', async () => { diff --git a/packages/backend/src/controllers/api/v1/users/get-current-user.test.js b/packages/backend/src/controllers/api/v1/users/get-current-user.test.js index 7ed4f09c..362c9815 100644 --- a/packages/backend/src/controllers/api/v1/users/get-current-user.test.js +++ b/packages/backend/src/controllers/api/v1/users/get-current-user.test.js @@ -25,7 +25,7 @@ describe('GET /api/v1/users/me', () => { roleId: role.id, }); - token = createAuthTokenByUserId(currentUser.id); + token = await createAuthTokenByUserId(currentUser.id); }); it('should return current user info', async () => { diff --git a/packages/backend/src/controllers/api/v1/users/get-invoices.ee.test.js b/packages/backend/src/controllers/api/v1/users/get-invoices.ee.test.js index fba18c39..1b0e8732 100644 --- a/packages/backend/src/controllers/api/v1/users/get-invoices.ee.test.js +++ b/packages/backend/src/controllers/api/v1/users/get-invoices.ee.test.js @@ -11,7 +11,7 @@ describe('GET /api/v1/user/invoices', () => { beforeEach(async () => { currentUser = await createUser(); - token = createAuthTokenByUserId(currentUser.id); + token = await createAuthTokenByUserId(currentUser.id); }); it('should return current user invoices', async () => { diff --git a/packages/backend/src/controllers/api/v1/users/get-plan-and-usage.ee.test.js b/packages/backend/src/controllers/api/v1/users/get-plan-and-usage.ee.test.js index 239a6e36..4986ad2b 100644 --- a/packages/backend/src/controllers/api/v1/users/get-plan-and-usage.ee.test.js +++ b/packages/backend/src/controllers/api/v1/users/get-plan-and-usage.ee.test.js @@ -14,7 +14,7 @@ describe('GET /api/v1/users/:userId/plan-and-usage', () => { beforeEach(async () => { const trialExpiryDate = DateTime.now().plus({ days: 30 }).toISODate(); user = await createUser({ trialExpiryDate }); - token = createAuthTokenByUserId(user.id); + token = await createAuthTokenByUserId(user.id); vi.spyOn(appConfig, 'isCloud', 'get').mockReturnValue(true); }); diff --git a/packages/backend/src/controllers/api/v1/users/get-subscription.ee.test.js b/packages/backend/src/controllers/api/v1/users/get-subscription.ee.test.js index 20c918b9..24c6db47 100644 --- a/packages/backend/src/controllers/api/v1/users/get-subscription.ee.test.js +++ b/packages/backend/src/controllers/api/v1/users/get-subscription.ee.test.js @@ -22,7 +22,7 @@ describe('GET /api/v1/users/:userId/subscription', () => { subscription = await createSubscription({ userId: currentUser.id }); - token = createAuthTokenByUserId(currentUser.id); + token = await createAuthTokenByUserId(currentUser.id); }); it('should return subscription info of the current user', async () => { @@ -41,7 +41,7 @@ describe('GET /api/v1/users/:userId/subscription', () => { roleId: role.id, }); - const token = createAuthTokenByUserId(userWithoutSubscription.id); + const token = await createAuthTokenByUserId(userWithoutSubscription.id); await request(app) .get(`/api/v1/users/${userWithoutSubscription.id}/subscription`) diff --git a/packages/backend/src/controllers/api/v1/users/get-user-trial.ee.test.js b/packages/backend/src/controllers/api/v1/users/get-user-trial.ee.test.js index 52e300b6..f560554b 100644 --- a/packages/backend/src/controllers/api/v1/users/get-user-trial.ee.test.js +++ b/packages/backend/src/controllers/api/v1/users/get-user-trial.ee.test.js @@ -14,7 +14,7 @@ describe('GET /api/v1/users/:userId/trial', () => { beforeEach(async () => { const trialExpiryDate = DateTime.now().plus({ days: 30 }).toISODate(); user = await createUser({ trialExpiryDate }); - token = createAuthTokenByUserId(user.id); + token = await createAuthTokenByUserId(user.id); vi.spyOn(appConfig, 'isCloud', 'get').mockReturnValue(true); }); diff --git a/packages/backend/src/graphql/mutations/login.js b/packages/backend/src/graphql/mutations/login.js index de9d036d..b0504570 100644 --- a/packages/backend/src/graphql/mutations/login.js +++ b/packages/backend/src/graphql/mutations/login.js @@ -7,7 +7,7 @@ const login = async (_parent, params) => { }); if (user && (await user.login(params.input.password))) { - const token = createAuthTokenByUserId(user.id); + const token = await createAuthTokenByUserId(user.id); return { token, user }; } diff --git a/packages/backend/src/helpers/authentication.js b/packages/backend/src/helpers/authentication.js index 5ba9ae57..d60ac986 100644 --- a/packages/backend/src/helpers/authentication.js +++ b/packages/backend/src/helpers/authentication.js @@ -1,7 +1,6 @@ import { allow, rule, shield } from 'graphql-shield'; -import jwt from 'jsonwebtoken'; -import appConfig from '../config/app.js'; import User from '../models/user.js'; +import AccessToken from '../models/access-token.js'; export const isAuthenticated = async (_parent, _args, req) => { const token = req.headers['authorization']; @@ -9,10 +8,22 @@ export const isAuthenticated = async (_parent, _args, req) => { if (token == null) return false; try { - const { userId } = jwt.verify(token, appConfig.appSecretKey); + const accessToken = await AccessToken.query().findOne({ + token, + revoked_at: null, + }); + + const expirationTime = + new Date(accessToken.createdAt).getTime() + accessToken.expiresIn * 1000; + + if (Date.now() > expirationTime) { + return false; + } + + const user = await accessToken.$relatedQuery('user'); req.currentUser = await User.query() - .findById(userId) + .findById(user.id) .leftJoinRelated({ role: true, permissions: true, diff --git a/packages/backend/src/helpers/authentication.test.js b/packages/backend/src/helpers/authentication.test.js index f2b06d2a..a5a4b60f 100644 --- a/packages/backend/src/helpers/authentication.test.js +++ b/packages/backend/src/helpers/authentication.test.js @@ -17,7 +17,7 @@ describe('isAuthenticated', () => { it('should return true if token is valid and there is a user', async () => { const user = await createUser(); - const token = createAuthTokenByUserId(user.id); + const token = await createAuthTokenByUserId(user.id); const req = { headers: { authorization: token } }; expect(await isAuthenticated(null, null, req)).toBe(true); @@ -25,7 +25,7 @@ describe('isAuthenticated', () => { it('should return false if token is valid and but there is no user', async () => { const user = await createUser(); - const token = createAuthTokenByUserId(user.id); + const token = await createAuthTokenByUserId(user.id); await user.$query().delete(); const req = { headers: { authorization: token } }; diff --git a/packages/backend/src/helpers/create-auth-token-by-user-id.js b/packages/backend/src/helpers/create-auth-token-by-user-id.js index d70382d9..d7da68db 100644 --- a/packages/backend/src/helpers/create-auth-token-by-user-id.js +++ b/packages/backend/src/helpers/create-auth-token-by-user-id.js @@ -1,10 +1,16 @@ -import jwt from 'jsonwebtoken'; -import appConfig from '../config/app.js'; +import crypto from 'crypto'; +import User from '../models/user.js'; +import AccessToken from '../models/access-token.js'; -const TOKEN_EXPIRES_IN = '14d'; +const TOKEN_EXPIRES_IN = 14 * 24 * 60 * 60; // 14 days in seconds -const createAuthTokenByUserId = (userId) => { - const token = jwt.sign({ userId }, appConfig.appSecretKey, { +const createAuthTokenByUserId = async (userId) => { + const user = await User.query().findById(userId).throwIfNotFound(); + const token = await crypto.randomBytes(48).toString('hex'); + + await AccessToken.query().insert({ + token, + userId: user.id, expiresIn: TOKEN_EXPIRES_IN, }); diff --git a/packages/backend/src/helpers/passport.js b/packages/backend/src/helpers/passport.js index 2e7a1430..cf3b37d6 100644 --- a/packages/backend/src/helpers/passport.js +++ b/packages/backend/src/helpers/passport.js @@ -76,8 +76,8 @@ export default function configurePassport(app) { failureRedirect: '/', failureFlash: true, }), - (req, res) => { - const token = createAuthTokenByUserId(req.currentUser.id); + async (req, res) => { + const token = await createAuthTokenByUserId(req.currentUser.id); const redirectUrl = new URL( `/login/callback?token=${token}`, diff --git a/packages/backend/src/models/user.js b/packages/backend/src/models/user.js index aca2ea7b..893f057e 100644 --- a/packages/backend/src/models/user.js +++ b/packages/backend/src/models/user.js @@ -185,7 +185,7 @@ class User extends Base { }); if (user && (await user.login(password))) { - const token = createAuthTokenByUserId(user.id); + const token = await createAuthTokenByUserId(user.id); return token; } } From 2a4f8ed45fa6aa145c14c6d5073d990c6b50d141 Mon Sep 17 00:00:00 2001 From: Faruk AYDIN Date: Wed, 24 Apr 2024 12:03:45 +0200 Subject: [PATCH 3/3] feat: Add indexes to token and userId columns of access tokens --- .../20240424100113_add_indexes_to_access_tokens.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 packages/backend/src/db/migrations/20240424100113_add_indexes_to_access_tokens.js diff --git a/packages/backend/src/db/migrations/20240424100113_add_indexes_to_access_tokens.js b/packages/backend/src/db/migrations/20240424100113_add_indexes_to_access_tokens.js new file mode 100644 index 00000000..0cb5d96f --- /dev/null +++ b/packages/backend/src/db/migrations/20240424100113_add_indexes_to_access_tokens.js @@ -0,0 +1,13 @@ +export async function up(knex) { + return knex.schema.table('access_tokens', (table) => { + table.index('token'); + table.index('user_id'); + }); +} + +export async function down(knex) { + return knex.schema.table('access_tokens', (table) => { + table.dropIndex('token'); + table.dropIndex('user_id'); + }); +}