Always clear cookies on logout / auth failure.
This commit is contained in:
parent
61f2cde690
commit
1e1da54087
3 changed files with 52 additions and 3 deletions
src
40
src/helpers/cookies.ts
Normal file
40
src/helpers/cookies.ts
Normal file
|
@ -0,0 +1,40 @@
|
|||
import { Response } from 'express';
|
||||
|
||||
import { Optional } from '../types';
|
||||
import { ValidationError } from '../errors';
|
||||
|
||||
const setCookie = (res: Response, params: {
|
||||
name: string,
|
||||
value: string,
|
||||
expiresAt?: Optional<Date>,
|
||||
path?: string,
|
||||
}) => {
|
||||
params.path = params.path || '/';
|
||||
if (params.expiresAt) {
|
||||
try {
|
||||
params.expiresAt = new Date(params.expiresAt);
|
||||
} catch (error) {
|
||||
throw new ValidationError(`Invalid expiresAt: ${error}`);
|
||||
}
|
||||
}
|
||||
|
||||
let cookie = `${params.name}=${params.value}; Path=${params.path}; HttpOnly; SameSite=Strict`;
|
||||
if (params.expiresAt) {
|
||||
cookie += `; Expires=${params.expiresAt.toUTCString()}`;
|
||||
}
|
||||
|
||||
res.setHeader('Set-Cookie', cookie);
|
||||
}
|
||||
|
||||
const clearCookie = (res: Response, name: string) => {
|
||||
setCookie(res, {
|
||||
name,
|
||||
value: '',
|
||||
expiresAt: new Date(0),
|
||||
});
|
||||
}
|
||||
|
||||
export {
|
||||
clearCookie,
|
||||
setCookie,
|
||||
};
|
|
@ -2,6 +2,7 @@ import { Request, Response } from 'express';
|
|||
|
||||
import Route from '../Route';
|
||||
import { Unauthorized, } from '../../errors';
|
||||
import { clearCookie } from '../../helpers/cookies';
|
||||
|
||||
abstract class ApiRoute extends Route {
|
||||
protected version: string;
|
||||
|
@ -13,7 +14,9 @@ abstract class ApiRoute extends Route {
|
|||
protected static handleError(req: Request, res: Response, error: Error) {
|
||||
// Handle API unauthorized errors with a 401+JSON response instead of a redirect
|
||||
if (error instanceof Unauthorized) {
|
||||
res.status(401).json({
|
||||
res.status(401)
|
||||
clearCookie(res, 'session');
|
||||
res.json({
|
||||
error: error.message,
|
||||
});
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import { Request, Response } from 'express';
|
|||
import ApiV1Route from './Route';
|
||||
import { ValidationError } from '../../../errors';
|
||||
import { AuthInfo, authenticate } from '../../../auth';
|
||||
import { clearCookie, setCookie } from '../../../helpers/cookies';
|
||||
|
||||
class Auth extends ApiV1Route {
|
||||
constructor() {
|
||||
|
@ -47,7 +48,12 @@ class Auth extends ApiV1Route {
|
|||
}
|
||||
|
||||
session = await $repos.userSessions.create(user.id, expiresAtDate);
|
||||
res.setHeader('Set-Cookie', `session=${session.getToken()}; Path=/; HttpOnly; SameSite=Strict`);
|
||||
setCookie(res, {
|
||||
name: 'session',
|
||||
value: session.getToken(),
|
||||
expiresAt: expiresAtDate,
|
||||
});
|
||||
|
||||
res.json({
|
||||
session: {
|
||||
token: session.getToken(),
|
||||
|
@ -69,7 +75,7 @@ class Auth extends ApiV1Route {
|
|||
await session.destroy();
|
||||
}
|
||||
|
||||
res.setHeader('Set-Cookie', 'session=; Path=/; HttpOnly; SameSite=Strict; Max-Age=0');
|
||||
clearCookie(res, 'session');
|
||||
res.status(204).send();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue