diff --git a/src/api/oauth/refresh.ts b/src/api/oauth/refresh.ts index ccea5ce..84d6648 100644 --- a/src/api/oauth/refresh.ts +++ b/src/api/oauth/refresh.ts @@ -13,12 +13,24 @@ import { JWTExpDur } from "../../keys"; import RefreshToken from "../../models/refresh_token"; import { getEncryptionKey } from "../../helper/user_key"; +// TODO: +/* +For example, the authorization server could employ refresh token +rotation in which a new refresh token is issued with every access +token refresh response. The previous refresh token is invalidated but retained by the authorization server. If a refresh token is +compromised and subsequently used by both the attacker and the +legitimate client, one of them will present an invalidated refresh +token, which will inform the authorization server of the breach. +*/ + +const refreshTokenValidTime = moment.duration(6, "month"); + const RefreshTokenRoute = Stacker(GetClientAuthMiddleware(false, false, true), async (req: Request, res: Response) => { let grant_type = req.query.grant_type || req.body.grant_type; if (!grant_type || grant_type === "authorization_code") { let code = req.query.code || req.body.code; let c = await ClientCode.findOne({ code: code }) - if (!c) { + if (!c || moment(c.validTill).isBefore()) { throw new RequestError(req.__("Invalid code"), HttpStatusCode.BAD_REQUEST); } @@ -33,7 +45,7 @@ const RefreshTokenRoute = Stacker(GetClientAuthMiddleware(false, false, true), a permissions: c.permissions, token: randomBytes(16).toString("hex"), valid: true, - validTill: moment().add(6, "months").toDate() + validTill: moment().add(refreshTokenValidTime).toDate() }); await RefreshToken.save(token); await ClientCode.delete(c); @@ -63,7 +75,11 @@ const RefreshTokenRoute = Stacker(GetClientAuthMiddleware(false, false, true), a if (!refresh_token) throw new RequestError(req.__("refresh_token not set"), HttpStatusCode.BAD_REQUEST); let token = await RefreshToken.findOne({ token: refresh_token }); - if (!token) throw new RequestError(req.__("Invalid token"), HttpStatusCode.BAD_REQUEST); + if (!token || !token.valid || moment(token.validTill).isBefore()) + throw new RequestError(req.__("Invalid token"), HttpStatusCode.BAD_REQUEST); + + token.validTill = moment().add(refreshTokenValidTime).toDate(); + await RefreshToken.save(token); let user = await User.findById(token.user); let client = await Client.findById(token.client)