mirror of
https://github.com/sasjs/server.git
synced 2025-12-11 19:44:35 +00:00
feat: make access token duration configurable when creating client/secret
This commit is contained in:
@@ -57,6 +57,11 @@ components:
|
|||||||
type: string
|
type: string
|
||||||
description: 'Client Secret'
|
description: 'Client Secret'
|
||||||
example: someRandomCryptoString
|
example: someRandomCryptoString
|
||||||
|
accessTokenExpiryDays:
|
||||||
|
type: number
|
||||||
|
format: double
|
||||||
|
description: 'Number of days in which access token will expire'
|
||||||
|
example: 1
|
||||||
required:
|
required:
|
||||||
- clientId
|
- clientId
|
||||||
- clientSecret
|
- clientSecret
|
||||||
@@ -679,8 +684,8 @@ paths:
|
|||||||
$ref: '#/components/schemas/ClientPayload'
|
$ref: '#/components/schemas/ClientPayload'
|
||||||
examples:
|
examples:
|
||||||
'Example 1':
|
'Example 1':
|
||||||
value: {clientId: someFormattedClientID1234, clientSecret: someRandomCryptoString}
|
value: {clientId: someFormattedClientID1234, clientSecret: someRandomCryptoString, accessTokenExpiryDays: 1}
|
||||||
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.'
|
||||||
tags:
|
tags:
|
||||||
- Client
|
- Client
|
||||||
security:
|
security:
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import {
|
|||||||
removeTokensInDB,
|
removeTokensInDB,
|
||||||
saveTokensInDB
|
saveTokensInDB
|
||||||
} from '../utils'
|
} from '../utils'
|
||||||
|
import Client from '../model/Client'
|
||||||
|
|
||||||
@Route('SASjsApi/auth')
|
@Route('SASjsApi/auth')
|
||||||
@Tags('Auth')
|
@Tags('Auth')
|
||||||
@@ -83,7 +84,13 @@ const token = async (data: any): Promise<TokenResponse> => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
const refreshToken = generateRefreshToken(userInfo)
|
||||||
|
|
||||||
await saveTokensInDB(userInfo.userId, clientId, accessToken, refreshToken)
|
await saveTokensInDB(userInfo.userId, clientId, accessToken, refreshToken)
|
||||||
@@ -92,7 +99,13 @@ const token = async (data: any): Promise<TokenResponse> => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const refresh = async (userInfo: InfoJWT): Promise<TokenResponse> => {
|
const refresh = async (userInfo: InfoJWT): Promise<TokenResponse> => {
|
||||||
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)
|
const refreshToken = generateRefreshToken(userInfo)
|
||||||
|
|
||||||
await saveTokensInDB(
|
await saveTokensInDB(
|
||||||
|
|||||||
@@ -7,12 +7,13 @@ import Client, { ClientPayload } from '../model/Client'
|
|||||||
@Tags('Client')
|
@Tags('Client')
|
||||||
export class ClientController {
|
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<ClientPayload>({
|
@Example<ClientPayload>({
|
||||||
clientId: 'someFormattedClientID1234',
|
clientId: 'someFormattedClientID1234',
|
||||||
clientSecret: 'someRandomCryptoString'
|
clientSecret: 'someRandomCryptoString',
|
||||||
|
accessTokenExpiryDays: 1
|
||||||
})
|
})
|
||||||
@Post('/')
|
@Post('/')
|
||||||
public async createClient(
|
public async createClient(
|
||||||
@@ -22,8 +23,8 @@ export class ClientController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const createClient = async (data: any): Promise<ClientPayload> => {
|
const createClient = async (data: ClientPayload): Promise<ClientPayload> => {
|
||||||
const { clientId, clientSecret } = data
|
const { clientId, clientSecret, accessTokenExpiryDays } = data
|
||||||
|
|
||||||
// Checking if client is already in the database
|
// Checking if client is already in the database
|
||||||
const clientExist = await Client.findOne({ clientId })
|
const clientExist = await Client.findOne({ clientId })
|
||||||
@@ -32,13 +33,15 @@ const createClient = async (data: any): Promise<ClientPayload> => {
|
|||||||
// Create a new client
|
// Create a new client
|
||||||
const client = new Client({
|
const client = new Client({
|
||||||
clientId,
|
clientId,
|
||||||
clientSecret
|
clientSecret,
|
||||||
|
accessTokenExpiryDays
|
||||||
})
|
})
|
||||||
|
|
||||||
const savedClient = await client.save()
|
const savedClient = await client.save()
|
||||||
|
|
||||||
return {
|
return {
|
||||||
clientId: savedClient.clientId,
|
clientId: savedClient.clientId,
|
||||||
clientSecret: savedClient.clientSecret
|
clientSecret: savedClient.clientSecret,
|
||||||
|
accessTokenExpiryDays: savedClient.accessTokenExpiryDays
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,11 @@ export interface ClientPayload {
|
|||||||
* @example "someRandomCryptoString"
|
* @example "someRandomCryptoString"
|
||||||
*/
|
*/
|
||||||
clientSecret: string
|
clientSecret: string
|
||||||
|
/**
|
||||||
|
* Number of days in which access token will expire
|
||||||
|
* @example 1
|
||||||
|
*/
|
||||||
|
accessTokenExpiryDays?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
const ClientSchema = new Schema<ClientPayload>({
|
const ClientSchema = new Schema<ClientPayload>({
|
||||||
@@ -21,6 +26,10 @@ const ClientSchema = new Schema<ClientPayload>({
|
|||||||
clientSecret: {
|
clientSecret: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true
|
required: true
|
||||||
|
},
|
||||||
|
accessTokenExpiryDays: {
|
||||||
|
type: Number,
|
||||||
|
default: 1
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import jwt from 'jsonwebtoken'
|
import jwt from 'jsonwebtoken'
|
||||||
import { InfoJWT } from '../types'
|
import { InfoJWT } from '../types'
|
||||||
|
|
||||||
export const generateAccessToken = (data: InfoJWT) =>
|
export const generateAccessToken = (data: InfoJWT, expiry?: number) =>
|
||||||
jwt.sign(data, process.secrets.ACCESS_TOKEN_SECRET, {
|
jwt.sign(data, process.secrets.ACCESS_TOKEN_SECRET, {
|
||||||
expiresIn: '1day'
|
expiresIn: expiry ? `${expiry}d` : '1d'
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -88,7 +88,8 @@ export const updateUserValidation = (
|
|||||||
export const registerClientValidation = (data: any): Joi.ValidationResult =>
|
export const registerClientValidation = (data: any): Joi.ValidationResult =>
|
||||||
Joi.object({
|
Joi.object({
|
||||||
clientId: Joi.string().required(),
|
clientId: Joi.string().required(),
|
||||||
clientSecret: Joi.string().required()
|
clientSecret: Joi.string().required(),
|
||||||
|
accessTokenExpiryDays: Joi.number()
|
||||||
}).validate(data)
|
}).validate(data)
|
||||||
|
|
||||||
export const registerPermissionValidation = (data: any): Joi.ValidationResult =>
|
export const registerPermissionValidation = (data: any): Joi.ValidationResult =>
|
||||||
|
|||||||
Reference in New Issue
Block a user