1
0
mirror of https://github.com/sasjs/server.git synced 2025-12-11 03:34:35 +00:00

Merge pull request #316 from sasjs/access-token-expiration

fix: change the expiration of access/refresh tokens from days to seconds
This commit is contained in:
Allan Bowe
2022-11-15 12:25:41 +00:00
committed by GitHub
7 changed files with 44 additions and 33 deletions

View File

@@ -57,16 +57,16 @@ components:
type: string type: string
description: 'Client Secret' description: 'Client Secret'
example: someRandomCryptoString example: someRandomCryptoString
accessTokenExpiryDays: accessTokenExpiration:
type: number type: number
format: double format: double
description: 'Number of days in which access token will expire' description: 'Number of seconds after which access token will expire. Default is 86400 (1 day)'
example: 1 example: 86400
refreshTokenExpiryDays: refreshTokenExpiration:
type: number type: number
format: double format: double
description: 'Number of days in which access token will expire' description: 'Number of seconds after which access token will expire. Default is 2592000 (30 days)'
example: 30 example: 2592000
required: required:
- clientId - clientId
- clientSecret - clientSecret
@@ -689,7 +689,11 @@ paths:
$ref: '#/components/schemas/ClientPayload' $ref: '#/components/schemas/ClientPayload'
examples: examples:
'Example 1': 'Example 1':
value: {clientId: someFormattedClientID1234, clientSecret: someRandomCryptoString, accessTokenExpiryDays: 1, refreshTokenExpiryDays: 30} value: {clientId: someFormattedClientID1234, clientSecret: someRandomCryptoString}
'Example 2':
value: {clientId: someFormattedClientID1234, clientSecret: someRandomCryptoString, accessTokenExpiration: 86400}
'Example 3':
value: {clientId: someFormattedClientID1234, clientSecret: someRandomCryptoString, accessTokenExpiration: 86400}
summary: "Admin only task. Create client with the following attributes:\nClientId,\nClientSecret,\naccessTokenExpiryDays (optional),\nrefreshTokenExpiryDays (optional)" summary: "Admin only task. Create client with the following attributes:\nClientId,\nClientSecret,\naccessTokenExpiryDays (optional),\nrefreshTokenExpiryDays (optional)"
tags: tags:
- Client - Client

View File

@@ -89,11 +89,11 @@ const token = async (data: any): Promise<TokenResponse> => {
const accessToken = generateAccessToken( const accessToken = generateAccessToken(
userInfo, userInfo,
client.accessTokenExpiryDays client.accessTokenExpiration
) )
const refreshToken = generateRefreshToken( const refreshToken = generateRefreshToken(
userInfo, userInfo,
client.refreshTokenExpiryDays client.refreshTokenExpiration
) )
await saveTokensInDB(userInfo.userId, clientId, accessToken, refreshToken) await saveTokensInDB(userInfo.userId, clientId, accessToken, refreshToken)
@@ -107,11 +107,11 @@ const refresh = async (userInfo: InfoJWT): Promise<TokenResponse> => {
const accessToken = generateAccessToken( const accessToken = generateAccessToken(
userInfo, userInfo,
client.accessTokenExpiryDays client.accessTokenExpiration
) )
const refreshToken = generateRefreshToken( const refreshToken = generateRefreshToken(
userInfo, userInfo,
client.refreshTokenExpiryDays client.refreshTokenExpiration
) )
await saveTokensInDB( await saveTokensInDB(

View File

@@ -1,6 +1,9 @@
import { Security, Route, Tags, Example, Post, Body } from 'tsoa' import { Security, Route, Tags, Example, Post, Body } from 'tsoa'
import Client, { ClientPayload } from '../model/Client' import Client, {
ClientPayload,
NUMBER_OF_SECONDS_IN_A_DAY
} from '../model/Client'
@Security('bearerAuth') @Security('bearerAuth')
@Route('SASjsApi/client') @Route('SASjsApi/client')
@@ -17,8 +20,8 @@ export class ClientController {
@Example<ClientPayload>({ @Example<ClientPayload>({
clientId: 'someFormattedClientID1234', clientId: 'someFormattedClientID1234',
clientSecret: 'someRandomCryptoString', clientSecret: 'someRandomCryptoString',
accessTokenExpiryDays: 1, accessTokenExpiration: NUMBER_OF_SECONDS_IN_A_DAY,
refreshTokenExpiryDays: 30 refreshTokenExpiration: NUMBER_OF_SECONDS_IN_A_DAY * 30
}) })
@Post('/') @Post('/')
public async createClient( public async createClient(
@@ -32,8 +35,8 @@ const createClient = async (data: ClientPayload): Promise<ClientPayload> => {
const { const {
clientId, clientId,
clientSecret, clientSecret,
accessTokenExpiryDays, accessTokenExpiration,
refreshTokenExpiryDays refreshTokenExpiration
} = data } = data
// Checking if client is already in the database // Checking if client is already in the database
@@ -44,7 +47,8 @@ const createClient = async (data: ClientPayload): Promise<ClientPayload> => {
const client = new Client({ const client = new Client({
clientId, clientId,
clientSecret, clientSecret,
accessTokenExpiryDays accessTokenExpiration,
refreshTokenExpiration
}) })
const savedClient = await client.save() const savedClient = await client.save()
@@ -52,7 +56,7 @@ const createClient = async (data: ClientPayload): Promise<ClientPayload> => {
return { return {
clientId: savedClient.clientId, clientId: savedClient.clientId,
clientSecret: savedClient.clientSecret, clientSecret: savedClient.clientSecret,
accessTokenExpiryDays: savedClient.accessTokenExpiryDays, accessTokenExpiration: savedClient.accessTokenExpiration,
refreshTokenExpiryDays: savedClient.refreshTokenExpiryDays refreshTokenExpiration: savedClient.refreshTokenExpiration
} }
} }

View File

@@ -1,5 +1,6 @@
import mongoose, { Schema } from 'mongoose' import mongoose, { Schema } from 'mongoose'
export const NUMBER_OF_SECONDS_IN_A_DAY = 86400
export interface ClientPayload { export interface ClientPayload {
/** /**
* Client ID * Client ID
@@ -12,15 +13,15 @@ export interface ClientPayload {
*/ */
clientSecret: string clientSecret: string
/** /**
* Number of days in which access token will expire * Number of seconds after which access token will expire. Default is 86400 (1 day)
* @example 1 * @example 86400
*/ */
accessTokenExpiryDays?: number accessTokenExpiration?: number
/** /**
* Number of days in which access token will expire * Number of seconds after which access token will expire. Default is 2592000 (30 days)
* @example 30 * @example 2592000
*/ */
refreshTokenExpiryDays?: number refreshTokenExpiration?: number
} }
const ClientSchema = new Schema<ClientPayload>({ const ClientSchema = new Schema<ClientPayload>({
@@ -32,13 +33,13 @@ const ClientSchema = new Schema<ClientPayload>({
type: String, type: String,
required: true required: true
}, },
accessTokenExpiryDays: { accessTokenExpiration: {
type: Number, type: Number,
default: 1 default: NUMBER_OF_SECONDS_IN_A_DAY
}, },
refreshTokenExpiryDays: { refreshTokenExpiration: {
type: Number, type: Number,
default: 30 default: NUMBER_OF_SECONDS_IN_A_DAY * 30
} }
}) })

View File

@@ -1,7 +1,8 @@
import jwt from 'jsonwebtoken' import jwt from 'jsonwebtoken'
import { InfoJWT } from '../types' import { InfoJWT } from '../types'
import { NUMBER_OF_SECONDS_IN_A_DAY } from '../model/Client'
export const generateAccessToken = (data: InfoJWT, expiry?: number) => export const generateAccessToken = (data: InfoJWT, expiry?: number) =>
jwt.sign(data, process.secrets.ACCESS_TOKEN_SECRET, { jwt.sign(data, process.secrets.ACCESS_TOKEN_SECRET, {
expiresIn: expiry ? `${expiry}d` : '1d' expiresIn: expiry ? expiry : NUMBER_OF_SECONDS_IN_A_DAY
}) })

View File

@@ -1,7 +1,8 @@
import jwt from 'jsonwebtoken' import jwt from 'jsonwebtoken'
import { InfoJWT } from '../types' import { InfoJWT } from '../types'
import { NUMBER_OF_SECONDS_IN_A_DAY } from '../model/Client'
export const generateRefreshToken = (data: InfoJWT, expiry?: number) => export const generateRefreshToken = (data: InfoJWT, expiry?: number) =>
jwt.sign(data, process.secrets.REFRESH_TOKEN_SECRET, { jwt.sign(data, process.secrets.REFRESH_TOKEN_SECRET, {
expiresIn: expiry ? `${expiry}d` : '30d' expiresIn: expiry ? expiry : NUMBER_OF_SECONDS_IN_A_DAY
}) })

View File

@@ -89,8 +89,8 @@ 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(), accessTokenExpiration: Joi.number(),
refreshTokenExpiryDays: Joi.number() refreshTokenExpiration: Joi.number()
}).validate(data) }).validate(data)
export const registerPermissionValidation = (data: any): Joi.ValidationResult => export const registerPermissionValidation = (data: any): Joi.ValidationResult =>