Skip to content

Commit

Permalink
Fixed Cookie Session Authentication
Browse files Browse the repository at this point in the history
  • Loading branch information
R1c4rdCo5t4 committed Jun 21, 2024
1 parent b2387c2 commit 75585c8
Show file tree
Hide file tree
Showing 7 changed files with 28 additions and 39 deletions.
5 changes: 1 addition & 4 deletions code/client/src/contexts/auth/AuthContext.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import Cookies from 'js-cookie';
import { auth, githubAuthProvider, googleAuthProvider } from '@config';
import { createContext, ReactNode, useEffect, useState } from 'react';
import { signInWithPopup, signOut, User, type AuthProvider as Provider, inMemoryPersistence } from 'firebase/auth';
Expand Down Expand Up @@ -39,8 +38,7 @@ export function AuthProvider({ children }: AuthProviderProps) {
const { user } = await signInWithPopup(auth, provider);
const userInfo = { name: user.displayName!, email: user.email! };
const idToken = await user.getIdToken();
const csrfToken = Cookies.get('csrfToken')!;
await sessionLogin(idToken, csrfToken, user.uid, userInfo);
await sessionLogin(idToken, user.uid, userInfo);
} catch (e) {
publishError(e as Error);
}
Expand All @@ -51,7 +49,6 @@ export function AuthProvider({ children }: AuthProviderProps) {
const loginWithGithub = () => loginWithProvider(githubAuthProvider);

const logout = async () => {
console.log('logging out');
await sessionLogout();
await signOut(auth);
navigate('/');
Expand Down
4 changes: 2 additions & 2 deletions code/client/src/services/auth/authService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { User, UserData } from '@notespace/shared/src/users/types';
import { HttpCommunication } from '@services/communication/http/httpCommunication';

function authService(http: HttpCommunication) {
async function sessionLogin(idToken: string, csrfToken: string, id: string, data: UserData) {
await http.post('/users/login', { idToken, csrfToken, id, ...data });
async function sessionLogin(idToken: string, id: string, data: UserData) {
await http.post('/users/login', { idToken, id, ...data });
}

async function sessionLogout() {
Expand Down
9 changes: 1 addition & 8 deletions code/client/src/ui/pages/landing/Landing.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
flex-direction: column;
justify-content: center;
align-items: center;
gap: 8vh;
gap: 20vh;

div {
display: flex;
Expand Down Expand Up @@ -34,11 +34,4 @@
color: white;
}
}

p {
position: absolute;
bottom: 5%;
left: 50%;
transform: translate(-50%, 0);
}
}
21 changes: 12 additions & 9 deletions code/client/src/ui/pages/landing/Landing.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,20 @@ function Landing() {

return (
<div className="landing">
<h1>Welcome to NoteSpace</h1>
<div>
<button onClick={loginWithGoogle}>
Login With Google
<img src={googleIcon} alt="Google Icon" />
</button>
<button onClick={loginWithGithub}>
Login with GitHub
<FaGithub />
</button>
<h1>Welcome to NoteSpace</h1>
<div>
<button onClick={loginWithGoogle}>
Login With Google
<img src={googleIcon} alt="Google Icon" />
</button>
<button onClick={loginWithGithub}>
Login with GitHub
<FaGithub />
</button>
</div>
</div>

<p>Please choose a provider to continue</p>
</div>
);
Expand Down
18 changes: 7 additions & 11 deletions code/server/src/controllers/http/handlers/usersHandlers.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,24 @@
import PromiseRouter from 'express-promise-router';
import { Request, Response } from 'express';
import { CookieOptions, Request, Response } from 'express';
import { UsersService } from '@services/UsersService';
import { httpResponse } from '@controllers/http/utils/httpResponse';
import { UserData } from '@notespace/shared/src/users/types';
import { enforceAuth } from '@controllers/http/middlewares/authMiddleware';
import admin from 'firebase-admin';
import { UnauthorizedError } from '@domain/errors/errors';

function usersHandlers(service: UsersService) {
const sessionLogin = async (req: Request, res: Response) => {
const { id, idToken, csrfToken, ...data } = req.body;
// guard against CSRF attacks
if (csrfToken !== req.cookies.csrfToken) {
httpResponse.unauthorized(res).send();
return;
}
const { id, idToken, ...data } = req.body;

// session login - create session cookie, verifying ID token in the process
try {
const expiresIn = 60 * 60 * 24 * 5 * 1000; // 5 days
const sessionCookie = await admin.auth().createSessionCookie(idToken, { expiresIn });
const options = { maxAge: expiresIn, httpOnly: true, secure: true };
const options: CookieOptions = { maxAge: expiresIn, httpOnly: true, secure: true, sameSite: 'none' };
res.cookie('session', sessionCookie, options);
} catch (e) {
httpResponse.unauthorized(res).send();
return;
throw new UnauthorizedError('Failed to login user');
}

// register user in database if not already registered
Expand Down Expand Up @@ -71,7 +67,7 @@ function usersHandlers(service: UsersService) {

const router = PromiseRouter({ mergeParams: true });
router.post('/login', sessionLogin);
router.post('/logout', sessionLogout);
router.post('/logout', enforceAuth, sessionLogout);
router.get('/:id', getUser);
router.get('/', getUsers);
router.put('/:id', enforceAuth, updateUser);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import admin from 'firebase-admin';
import { NextFunction, Request, Response } from 'express';
import { httpResponse } from '@controllers/http/utils/httpResponse';
import { LoggedUser } from '@notespace/shared/src/users/types';
import { ErrorLogger } from '@src/utils/logging';

declare global {
// eslint-disable-next-line @typescript-eslint/no-namespace
Expand All @@ -12,26 +13,26 @@ declare global {
}
}

// middleware that injects the user object into the request if it has a valid session cookie
export async function authMiddleware(req: Request, res: Response, next: NextFunction) {
const sessionCookie = req.cookies.session || '';
console.log('sessionCookie:', sessionCookie);
const sessionCookie = req.cookies.session;
if (!sessionCookie) {
return next();
}
try {
const idToken = await admin.auth().verifySessionCookie(sessionCookie, true);
console.log('idToken:', idToken);
const { uid, displayName, email } = await admin.auth().getUser(idToken.uid);
req.user = { id: uid, email: email!, name: displayName! };
next();
} catch (error) {
console.error('Error verifying token:', error);
ErrorLogger.logError('Request with invalid session token');
return httpResponse.unauthorized(res).send({ error: 'Invalid session token, please login again' });
}
}

export async function enforceAuth(req: Request, res: Response, next: NextFunction) {
if (!req.user) {
ErrorLogger.logError('Unauthorized request');
return httpResponse.unauthorized(res).send({ error: 'Unauthorized' });
}
next();
Expand Down
1 change: 0 additions & 1 deletion code/server/src/services/WorkspacesService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ export class WorkspacesService {
}

async addWorkspaceMember(wid: string, email: string) {
console.log('addWorkspaceMember', email);
const { userId, userInWorkspace } = await this.userInWorkspace(wid, email);
if (userInWorkspace) throw new ConflictError('User already in workspace');
await this.databases.workspaces.addWorkspaceMember(wid, userId);
Expand Down

0 comments on commit 75585c8

Please sign in to comment.