diff --git a/api/public/swagger.yaml b/api/public/swagger.yaml index 9d97d3b..5d6d695 100644 --- a/api/public/swagger.yaml +++ b/api/public/swagger.yaml @@ -57,6 +57,11 @@ components: type: string description: 'Client Secret' example: someRandomCryptoString + accessTokenExpiryDays: + type: number + format: double + description: 'Number of days in which access token will expire' + example: 1 required: - clientId - clientSecret @@ -679,8 +684,8 @@ paths: $ref: '#/components/schemas/ClientPayload' examples: 'Example 1': - value: {clientId: someFormattedClientID1234, clientSecret: someRandomCryptoString} - summary: 'Create client with the following attributes: ClientId, ClientSecret. Admin only task.' + value: {clientId: someFormattedClientID1234, clientSecret: someRandomCryptoString, accessTokenExpiryDays: 1} + summary: 'Create client with the following attributes: ClientId, ClientSecret, accessTokenExpires (optional) . Admin only task.' tags: - Client security: diff --git a/api/src/controllers/auth.ts b/api/src/controllers/auth.ts index 737468e..138f237 100644 --- a/api/src/controllers/auth.ts +++ b/api/src/controllers/auth.ts @@ -8,6 +8,7 @@ import { removeTokensInDB, saveTokensInDB } from '../utils' +import Client from '../model/Client' @Route('SASjsApi/auth') @Tags('Auth') @@ -83,7 +84,13 @@ const token = async (data: any): Promise => { } } - const accessToken = generateAccessToken(userInfo) + const client = await Client.findOne({ clientId }) + if (!client) throw new Error('Invalid clientId.') + + const accessToken = generateAccessToken( + userInfo, + client.accessTokenExpiryDays + ) const refreshToken = generateRefreshToken(userInfo) await saveTokensInDB(userInfo.userId, clientId, accessToken, refreshToken) @@ -92,7 +99,13 @@ const token = async (data: any): Promise => { } const refresh = async (userInfo: InfoJWT): Promise => { - const accessToken = generateAccessToken(userInfo) + const client = await Client.findOne({ clientId: userInfo.clientId }) + if (!client) throw new Error('Invalid clientId.') + + const accessToken = generateAccessToken( + userInfo, + client.accessTokenExpiryDays + ) const refreshToken = generateRefreshToken(userInfo) await saveTokensInDB( diff --git a/api/src/controllers/client.ts b/api/src/controllers/client.ts index c65f52a..c0b32a5 100644 --- a/api/src/controllers/client.ts +++ b/api/src/controllers/client.ts @@ -7,12 +7,13 @@ import Client, { ClientPayload } from '../model/Client' @Tags('Client') export class ClientController { /** - * @summary Create client with the following attributes: ClientId, ClientSecret. Admin only task. + * @summary Create client with the following attributes: ClientId, ClientSecret, accessTokenExpires (optional) . Admin only task. * */ @Example({ clientId: 'someFormattedClientID1234', - clientSecret: 'someRandomCryptoString' + clientSecret: 'someRandomCryptoString', + accessTokenExpiryDays: 1 }) @Post('/') public async createClient( @@ -22,8 +23,8 @@ export class ClientController { } } -const createClient = async (data: any): Promise => { - const { clientId, clientSecret } = data +const createClient = async (data: ClientPayload): Promise => { + const { clientId, clientSecret, accessTokenExpiryDays } = data // Checking if client is already in the database const clientExist = await Client.findOne({ clientId }) @@ -32,13 +33,15 @@ const createClient = async (data: any): Promise => { // Create a new client const client = new Client({ clientId, - clientSecret + clientSecret, + accessTokenExpiryDays }) const savedClient = await client.save() return { clientId: savedClient.clientId, - clientSecret: savedClient.clientSecret + clientSecret: savedClient.clientSecret, + accessTokenExpiryDays: savedClient.accessTokenExpiryDays } } diff --git a/api/src/model/Client.ts b/api/src/model/Client.ts index 113bffa..2f9da19 100644 --- a/api/src/model/Client.ts +++ b/api/src/model/Client.ts @@ -11,6 +11,11 @@ export interface ClientPayload { * @example "someRandomCryptoString" */ clientSecret: string + /** + * Number of days in which access token will expire + * @example 1 + */ + accessTokenExpiryDays?: number } const ClientSchema = new Schema({ @@ -21,6 +26,10 @@ const ClientSchema = new Schema({ clientSecret: { type: String, required: true + }, + accessTokenExpiryDays: { + type: Number, + default: 1 } }) diff --git a/api/src/utils/generateAccessToken.ts b/api/src/utils/generateAccessToken.ts index 2b385b6..ec25c61 100644 --- a/api/src/utils/generateAccessToken.ts +++ b/api/src/utils/generateAccessToken.ts @@ -1,7 +1,7 @@ import jwt from 'jsonwebtoken' import { InfoJWT } from '../types' -export const generateAccessToken = (data: InfoJWT) => +export const generateAccessToken = (data: InfoJWT, expiry?: number) => jwt.sign(data, process.secrets.ACCESS_TOKEN_SECRET, { - expiresIn: '1day' + expiresIn: expiry ? `${expiry}d` : '1d' }) diff --git a/api/src/utils/validation.ts b/api/src/utils/validation.ts index e3a3d3d..7d38dce 100644 --- a/api/src/utils/validation.ts +++ b/api/src/utils/validation.ts @@ -88,7 +88,8 @@ export const updateUserValidation = ( export const registerClientValidation = (data: any): Joi.ValidationResult => Joi.object({ clientId: Joi.string().required(), - clientSecret: Joi.string().required() + clientSecret: Joi.string().required(), + accessTokenExpiryDays: Joi.number() }).validate(data) export const registerPermissionValidation = (data: any): Joi.ValidationResult =>