From 36fbccb286331bb4226b336e14825e593413c50c Mon Sep 17 00:00:00 2001 From: Philipp Dormann Date: Sat, 12 Dec 2020 11:55:45 +0100 Subject: [PATCH 1/9] =?UTF-8?q?=F0=9F=9A=A7=20implementation=20in=20AuthCo?= =?UTF-8?q?ntroller@login?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ref #25 --- src/controllers/AuthController.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/controllers/AuthController.ts b/src/controllers/AuthController.ts index c2002a3..1d7418a 100644 --- a/src/controllers/AuthController.ts +++ b/src/controllers/AuthController.ts @@ -1,4 +1,4 @@ -import { Body, JsonController, Post } from 'routing-controllers'; +import { Body, JsonController, Post, Res } from 'routing-controllers'; import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; import { IllegalJWTError, InvalidCredentialsError, JwtNotProvidedError, PasswordNeededError, RefreshTokenCountInvalidError, UsernameOrEmailNeededError } from '../errors/AuthError'; import { UserNotFoundError } from '../errors/UserErrors'; @@ -21,10 +21,13 @@ export class AuthController { @ResponseSchema(PasswordNeededError) @ResponseSchema(InvalidCredentialsError) @OpenAPI({ description: 'Create a new access token object' }) - async login(@Body({ validate: true }) createAuth: CreateAuth) { + async login(@Body({ validate: true }) createAuth: CreateAuth, @Res() response: any) { let auth; try { auth = await createAuth.toAuth(); + response.cookie('lfk_backend__refresh_token', auth.refresh_token, { maxAge: 900000, httpOnly: true }); + response.cookie('lfk_backend__refresh_token_expires_at', auth.refresh_token_expires_at, { maxAge: 900000, httpOnly: true }); + return response.send(auth) } catch (error) { throw error; } From 0e003d2dc4140f9200cb0d8906a7dcd77db53d50 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Sat, 12 Dec 2020 18:32:48 +0100 Subject: [PATCH 2/9] Set cookies to secure ref #25 --- src/controllers/AuthController.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controllers/AuthController.ts b/src/controllers/AuthController.ts index 1d7418a..cab00a6 100644 --- a/src/controllers/AuthController.ts +++ b/src/controllers/AuthController.ts @@ -25,8 +25,8 @@ export class AuthController { let auth; try { auth = await createAuth.toAuth(); - response.cookie('lfk_backend__refresh_token', auth.refresh_token, { maxAge: 900000, httpOnly: true }); - response.cookie('lfk_backend__refresh_token_expires_at', auth.refresh_token_expires_at, { maxAge: 900000, httpOnly: true }); + response.cookie('lfk_backend__refresh_token', auth.refresh_token, { maxAge: 900000, httpOnly: true, secure: true }); + response.cookie('lfk_backend__refresh_token_expires_at', auth.refresh_token_expires_at, { maxAge: 900000, httpOnly: true, secure: true }); return response.send(auth) } catch (error) { throw error; From db5da3d3c25a687d301da5b6aa28daff8cb0c5f4 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Sat, 12 Dec 2020 18:34:22 +0100 Subject: [PATCH 3/9] Removed useless return ref #25 --- src/controllers/AuthController.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/controllers/AuthController.ts b/src/controllers/AuthController.ts index cab00a6..dfd0a3c 100644 --- a/src/controllers/AuthController.ts +++ b/src/controllers/AuthController.ts @@ -31,7 +31,6 @@ export class AuthController { } catch (error) { throw error; } - return auth } @Post("/logout") From c07d40ae93581b48a4e5bd0e87e0d8a41c365ec6 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Sat, 12 Dec 2020 19:01:31 +0100 Subject: [PATCH 4/9] Added cookie-parser to app.use ref #25 --- package.json | 3 ++- src/loaders/express.ts | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 6715b59..6821661 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "class-validator": "^0.12.2", "class-validator-jsonschema": "^2.0.3", "consola": "^2.15.0", + "cookie-parser": "^1.4.5", "cors": "^2.8.5", "dotenv": "^8.2.0", "express": "^4.17.1", @@ -82,4 +83,4 @@ ], "delay": "2500" } -} \ No newline at end of file +} diff --git a/src/loaders/express.ts b/src/loaders/express.ts index 32a28cd..fc3dbc4 100644 --- a/src/loaders/express.ts +++ b/src/loaders/express.ts @@ -1,10 +1,11 @@ +import cookieParser from "cookie-parser"; import { Application } from "express"; - /** * Loader for express related configurations. * Currently only enables the proxy trust. */ export default async (app: Application) => { app.enable('trust proxy'); + app.use(cookieParser()); return app; }; From 615b54ec4f12c79d4ced3c13eb159411087ed510 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Sat, 12 Dec 2020 19:13:18 +0100 Subject: [PATCH 5/9] Removed secure flag and added expiry basd on ht refresh token ref#25 --- src/controllers/AuthController.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controllers/AuthController.ts b/src/controllers/AuthController.ts index dfd0a3c..467e64a 100644 --- a/src/controllers/AuthController.ts +++ b/src/controllers/AuthController.ts @@ -25,8 +25,8 @@ export class AuthController { let auth; try { auth = await createAuth.toAuth(); - response.cookie('lfk_backend__refresh_token', auth.refresh_token, { maxAge: 900000, httpOnly: true, secure: true }); - response.cookie('lfk_backend__refresh_token_expires_at', auth.refresh_token_expires_at, { maxAge: 900000, httpOnly: true, secure: true }); + response.cookie('lfk_backend__refresh_token', auth.refresh_token, { expires: new Date(auth.refresh_token_expires_at * 1000), httpOnly: true }); + response.cookie('lfk_backend__refresh_token_expires_at', auth.refresh_token_expires_at, { expires: new Date(auth.refresh_token_expires_at * 1000), httpOnly: true }); return response.send(auth) } catch (error) { throw error; From aca3eaaeea482f3fbeeb8fc69e5e9a7c5297bbc5 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Sat, 12 Dec 2020 19:25:40 +0100 Subject: [PATCH 6/9] Now w/ working cookie based refresh ref #25 --- src/controllers/AuthController.ts | 11 ++++++++--- src/models/actions/RefreshAuth.ts | 5 +++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/controllers/AuthController.ts b/src/controllers/AuthController.ts index 467e64a..bed5942 100644 --- a/src/controllers/AuthController.ts +++ b/src/controllers/AuthController.ts @@ -1,4 +1,4 @@ -import { Body, JsonController, Post, Res } from 'routing-controllers'; +import { Body, CookieParam, JsonController, Post, Res } from 'routing-controllers'; import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; import { IllegalJWTError, InvalidCredentialsError, JwtNotProvidedError, PasswordNeededError, RefreshTokenCountInvalidError, UsernameOrEmailNeededError } from '../errors/AuthError'; import { UserNotFoundError } from '../errors/UserErrors'; @@ -58,13 +58,18 @@ export class AuthController { @ResponseSchema(UserNotFoundError) @ResponseSchema(RefreshTokenCountInvalidError) @OpenAPI({ description: 'refresh a access token' }) - async refresh(@Body({ validate: true }) refreshAuth: RefreshAuth) { + async refresh(@CookieParam("lfk_backend__refresh_token") refresh_token: string, @Res() response: any, @Body({ validate: true }) refreshAuth: RefreshAuth) { + if (refresh_token && refresh_token.length != 0) { + refreshAuth.token = refresh_token; + } let auth; try { auth = await refreshAuth.toAuth(); + response.cookie('lfk_backend__refresh_token', auth.refresh_token, { expires: new Date(auth.refresh_token_expires_at * 1000), httpOnly: true }); + response.cookie('lfk_backend__refresh_token_expires_at', auth.refresh_token_expires_at, { expires: new Date(auth.refresh_token_expires_at * 1000), httpOnly: true }); } catch (error) { return error; } - return auth + return response.send(auth) } } diff --git a/src/models/actions/RefreshAuth.ts b/src/models/actions/RefreshAuth.ts index dacca59..afd22fe 100644 --- a/src/models/actions/RefreshAuth.ts +++ b/src/models/actions/RefreshAuth.ts @@ -1,4 +1,4 @@ -import { IsString } from 'class-validator'; +import { IsOptional, IsString } from 'class-validator'; import * as jsonwebtoken from 'jsonwebtoken'; import { getConnectionManager } from 'typeorm'; import { config } from '../../config'; @@ -8,7 +8,8 @@ import { Auth } from '../responses/ResponseAuth'; export class RefreshAuth { @IsString() - token: string; + @IsOptional() + token?: string; public async toAuth(): Promise { let newAuth: Auth = new Auth(); From 6aa1e0d573e01926de83c410da300e02d2d902ec Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Sat, 12 Dec 2020 19:26:04 +0100 Subject: [PATCH 7/9] Cleaned up some errors ref #25 --- src/controllers/AuthController.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controllers/AuthController.ts b/src/controllers/AuthController.ts index bed5942..55ce048 100644 --- a/src/controllers/AuthController.ts +++ b/src/controllers/AuthController.ts @@ -46,7 +46,7 @@ export class AuthController { try { logout = await handleLogout.logout() } catch (error) { - return error; + throw error; } return logout } @@ -68,7 +68,7 @@ export class AuthController { response.cookie('lfk_backend__refresh_token', auth.refresh_token, { expires: new Date(auth.refresh_token_expires_at * 1000), httpOnly: true }); response.cookie('lfk_backend__refresh_token_expires_at', auth.refresh_token_expires_at, { expires: new Date(auth.refresh_token_expires_at * 1000), httpOnly: true }); } catch (error) { - return error; + throw error; } return response.send(auth) } From 30928180e63ad0dbfcf1a94440fc0a6ebd6394f1 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Sat, 12 Dec 2020 19:27:56 +0100 Subject: [PATCH 8/9] Switched to prefering body provided tokens over cookie tokens ref #25 --- src/controllers/AuthController.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllers/AuthController.ts b/src/controllers/AuthController.ts index 55ce048..7d551a4 100644 --- a/src/controllers/AuthController.ts +++ b/src/controllers/AuthController.ts @@ -59,7 +59,7 @@ export class AuthController { @ResponseSchema(RefreshTokenCountInvalidError) @OpenAPI({ description: 'refresh a access token' }) async refresh(@CookieParam("lfk_backend__refresh_token") refresh_token: string, @Res() response: any, @Body({ validate: true }) refreshAuth: RefreshAuth) { - if (refresh_token && refresh_token.length != 0) { + if (refresh_token && refresh_token.length != 0 && refreshAuth.token == undefined) { refreshAuth.token = refresh_token; } let auth; From ac2da0af63d2d6fcd4436b03f61b4eac495c1959 Mon Sep 17 00:00:00 2001 From: Nicolai Ort Date: Sat, 12 Dec 2020 19:50:12 +0100 Subject: [PATCH 9/9] Now w/ working logout ref #25 --- src/controllers/AuthController.ts | 12 +++++++++--- src/models/actions/HandleLogout.ts | 5 +++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/controllers/AuthController.ts b/src/controllers/AuthController.ts index 7d551a4..d6d8d81 100644 --- a/src/controllers/AuthController.ts +++ b/src/controllers/AuthController.ts @@ -41,14 +41,20 @@ export class AuthController { @ResponseSchema(PasswordNeededError) @ResponseSchema(InvalidCredentialsError) @OpenAPI({ description: 'Create a new access token object' }) - async logout(@Body({ validate: true }) handleLogout: HandleLogout) { + async logout(@Body({ validate: true }) handleLogout: HandleLogout, @CookieParam("lfk_backend__refresh_token") refresh_token: string, @Res() response: any) { + if (refresh_token && refresh_token.length != 0 && handleLogout.token == undefined) { + handleLogout.token = refresh_token; + } + let logout; try { logout = await handleLogout.logout() + await response.cookie('lfk_backend__refresh_token', "expired", { expires: new Date(Date.now()), httpOnly: true }); + response.cookie('lfk_backend__refresh_token_expires_at', "expired", { expires: new Date(Date.now()), httpOnly: true }); } catch (error) { throw error; } - return logout + return response.send(logout) } @Post("/refresh") @@ -58,7 +64,7 @@ export class AuthController { @ResponseSchema(UserNotFoundError) @ResponseSchema(RefreshTokenCountInvalidError) @OpenAPI({ description: 'refresh a access token' }) - async refresh(@CookieParam("lfk_backend__refresh_token") refresh_token: string, @Res() response: any, @Body({ validate: true }) refreshAuth: RefreshAuth) { + async refresh(@Body({ validate: true }) refreshAuth: RefreshAuth, @CookieParam("lfk_backend__refresh_token") refresh_token: string, @Res() response: any) { if (refresh_token && refresh_token.length != 0 && refreshAuth.token == undefined) { refreshAuth.token = refresh_token; } diff --git a/src/models/actions/HandleLogout.ts b/src/models/actions/HandleLogout.ts index 5ecab38..37c30c4 100644 --- a/src/models/actions/HandleLogout.ts +++ b/src/models/actions/HandleLogout.ts @@ -1,4 +1,4 @@ -import { IsString } from 'class-validator'; +import { IsOptional, IsString } from 'class-validator'; import * as jsonwebtoken from 'jsonwebtoken'; import { getConnectionManager } from 'typeorm'; import { config } from '../../config'; @@ -8,7 +8,8 @@ import { Logout } from '../responses/ResponseLogout'; export class HandleLogout { @IsString() - token: string; + @IsOptional() + token?: string; public async logout(): Promise { let logout: Logout = new Logout();