Skip to content

Commit

Permalink
oidc auth is served
Browse files Browse the repository at this point in the history
  • Loading branch information
Rayahhhmed committed Nov 4, 2023
2 parents cabba4a + cef8051 commit 77265c4
Show file tree
Hide file tree
Showing 8 changed files with 149 additions and 79 deletions.
43 changes: 37 additions & 6 deletions client/src/components/navbar/Navbar.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Description, Info, Security, Settings as SettingsIcon } from '@mui/icons-material';
import { AppBar, Button, Toolbar, Typography, useMediaQuery, useTheme } from '@mui/material';
import { styled } from '@mui/system';
import React, { useContext, useState } from 'react';
import React, { useContext, useEffect, useState } from 'react';

import notanglesLogoGif from '../../assets/notangles.gif';
import notanglesLogo from '../../assets/notangles_1.png';
Expand Down Expand Up @@ -52,16 +52,46 @@ const Weak = styled('span')`
const Navbar: React.FC = () => {
const [currLogo, setCurrLogo] = useState(notanglesLogo);
const { term, termName, year } = useContext(AppContext);
const userData: User = {};
const userData = {};
const [user, setUser] = useState(userData);
const theme = useTheme<ThemeType>();
const isMobile = useMediaQuery(theme.breakpoints.down('sm'));

useEffect(() => {
async function runAsync() {
try {
const response = await fetch('http://localhost:3001/api/auth/user', {
credentials: 'include',
});
const userResponse = await response.text();
console.log(userResponse);
if (userResponse !== '') {
console.log(userResponse);
setUser(JSON.parse(userResponse));
} else {
setUser({});
}
} catch (error) {
console.log(error);
}
}
// Execute the created function directly
runAsync();
// https://stackoverflow.com/a/55854902/1098564
// eslint-disable-next-line
}, []);
const login = () => {
window.location.replace('http://localhost:3001/api/auth/login');
};
const logout = () => {
window.location.replace('http://localhost:3001/api/auth/logout');
const logout = async () => {
try {
const response = await fetch('http://localhost:3001/api/auth/logout', {
credentials: 'include',
});
} catch (error) {
console.log(error);
}
window.location.replace('http://localhost:5173');
setUser({});
};
// https://stackoverflow.com/a/32108184/1098564
const isEmpty = (obj: Object) => {
Expand All @@ -82,6 +112,7 @@ const Navbar: React.FC = () => {
Notangles
<Weak>{isMobile ? term : termName.concat(', ', year)}</Weak>
</NavbarTitle>

<CustomModal
title="About"
showIcon={<Info />}
Expand All @@ -102,7 +133,7 @@ const Navbar: React.FC = () => {
</Button>
) : (
<Button color="warning" onClick={logout}>
Logout
{user} Logout
</Button>
)}
</Toolbar>
Expand Down
4 changes: 4 additions & 0 deletions client/src/interfaces/Users.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export interface User {
<<<<<<< HEAD
id_token?: string;
access_token?: string;
refresh_token?: string;
Expand All @@ -7,4 +8,7 @@ export interface User {

export interface UserInfo {
name?: string;
=======
zid: string;
>>>>>>> NTGL-be-oidc-cleanup
}
52 changes: 14 additions & 38 deletions server/src/auth/auth.controller.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,28 @@
import {
Controller,
Get,
Logger,
Request,
Res,
UseGuards,
} from '@nestjs/common';
import { Controller, Get, Request, Res, UseGuards } from '@nestjs/common';
import { Response } from 'express';

import { LoginGuard } from './login.guard';
import { Issuer } from 'openid-client';
import { AuthDto } from './dtos';
const REDIRECT_LINK = 'http://localhost:5173/';
import { log } from 'console';
import { REDIRECT_LINK } from 'src/constants';
import { AuthService } from './auth.service';

@Controller('auth')
export class AuthController {
constructor(private authService: AuthService) {}

@UseGuards(LoginGuard)
@Get('/login')
login() {}

@Get('/user')
user(@Request() req) {

return req.user;
user(@Request() req, @Res() res: Response) {
if (req.user) {
return res.json(req.user.userinfo.sub);
}

return res.json(req.user);
}

@UseGuards(LoginGuard)
Expand All @@ -32,31 +33,6 @@ export class AuthController {

@Get('/logout')
async logout(@Request() req, @Res() res: Response) {
console.log("logout");
const id_token = req.user ? req.user.id_token : undefined;
req.logout((err) => {
if (err) {
console.log(err + "omahgod errors");
}
req.session.destroy(async (error: any) => {
const TrustIssuer = await Issuer.discover(
`${process.env.OAUTH2_CLIENT_PROVIDER_OIDC_ISSUER}/.well-known/openid-configuration`,
);
const end_session_endpoint = TrustIssuer.metadata.end_session_endpoint;
console.log(id_token);
if (end_session_endpoint) {
res.redirect(
end_session_endpoint +
'?post_logout_redirect_uri=' +
process.env
.OAUTH2_CLIENT_REGISTRATION_LOGIN_POST_LOGOUT_REDIRECT_URI +
(id_token ? '&id_token_hint=' + id_token : ''),
);
} else {
res.redirect(REDIRECT_LINK);
}
});
});

this.authService.logout(req, res);
}
}
44 changes: 42 additions & 2 deletions server/src/auth/auth.service.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,44 @@
import { Injectable } from '@nestjs/common';
import {
Controller,
Get,
Injectable,
Request,
Res,
UseGuards,
} from '@nestjs/common';
import { Response } from 'express';
import { LoginGuard } from './login.guard';
import { Issuer } from 'openid-client';
import { AuthDto } from './dtos';
import { log } from 'console';
import { REDIRECT_LINK } from 'src/constants';

@Injectable()
export class AuthService {}
export class AuthService {
async logout(@Request() req, @Res() res: Response): Promise<void> {
const id_token = req.user ? req.user.id_token : undefined;

const TrustIssuer = await Issuer.discover(
`${process.env.OAUTH2_CLIENT_PROVIDER_OIDC_ISSUER}/.well-known/openid-configuration`,
);

if (!id_token || !TrustIssuer) {
return res.redirect(REDIRECT_LINK);
}

req.logout((err) => {
req.session.destroy(async (error: any) => {
const end_session_endpoint = TrustIssuer.metadata.end_session_endpoint;
if (end_session_endpoint) {
res.redirect(
end_session_endpoint +
'?post_logout_redirect_uri=' +
process.env
.OAUTH2_CLIENT_REGISTRATION_LOGIN_POST_LOGOUT_REDIRECT_URI +
(id_token ? '&id_token_hint=' + id_token : ''),
);
}
});
});
}
}
33 changes: 22 additions & 11 deletions server/src/auth/oidc.strategy.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
// auth/oidc.strategy.ts
import { UnauthorizedException } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { Strategy, Client, UserinfoResponse, TokenSet, Issuer } from 'openid-client';
import {
Strategy,
Client,
UserinfoResponse,
TokenSet,
Issuer,
} from 'openid-client';
import { AuthService } from './auth.service';

export const buildOpenIdClient = async () => {
const TrustIssuer = await Issuer.discover(`${process.env.OAUTH2_CLIENT_PROVIDER_OIDC_ISSUER}/.well-known/openid-configuration`);
const TrustIssuer = await Issuer.discover(
`${process.env.OAUTH2_CLIENT_PROVIDER_OIDC_ISSUER}/.well-known/openid-configuration`,
);
const client = new TrustIssuer.Client({
client_id: process.env.OAUTH2_CLIENT_REGISTRATION_LOGIN_CLIENT_ID,
client_secret: process.env.OAUTH2_CLIENT_REGISTRATION_LOGIN_CLIENT_SECRET,
Expand All @@ -16,11 +24,15 @@ export const buildOpenIdClient = async () => {
export class OidcStrategy extends PassportStrategy(Strategy, 'oidc') {
client: Client;

constructor(private readonly authService: AuthService, client: Client) {
constructor(
private readonly authService: AuthService,
client: Client,
) {
super({
client: client,
params: {
redirect_uris: process.env.OAUTH2_CLIENT_REGISTRATION_LOGIN_REDIRECT_URI,
redirect_uris:
process.env.OAUTH2_CLIENT_REGISTRATION_LOGIN_REDIRECT_URI,
scope: process.env.OAUTH2_CLIENT_REGISTRATION_LOGIN_SCOPE,
},
passReqToCallback: false,
Expand All @@ -32,21 +44,20 @@ export class OidcStrategy extends PassportStrategy(Strategy, 'oidc') {

async validate(tokenset: TokenSet): Promise<any> {
const userinfo: UserinfoResponse = await this.client.userinfo(tokenset);

try {
const id_token = tokenset.id_token
const access_token = tokenset.access_token
const refresh_token = tokenset.refresh_token
console.log(tokenset);
const id_token = tokenset.id_token;
const access_token = tokenset.access_token;
const refresh_token = tokenset.refresh_token;
const user = {
id_token,
access_token,
refresh_token,
userinfo,
}
// console.log(user);
};
return user;
} catch (err) {
throw new UnauthorizedException();
}
}
}
}
7 changes: 5 additions & 2 deletions server/src/auth/session.serializer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ export class SessionSerializer extends PassportSerializer {
serializeUser(user: any, done: (err: Error, user: any) => void): any {
done(null, user);
}
deserializeUser(payload: any, done: (err: Error, payload: string) => void): any {
deserializeUser(
payload: any,
done: (err: Error, payload: string) => void,
): any {
done(null, payload);
}
}
}
4 changes: 4 additions & 0 deletions server/src/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export const REDIRECT_LINK = 'http://localhost:5173';
export interface User {
zid: string;
}
41 changes: 21 additions & 20 deletions server/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,34 +6,35 @@ import * as session from 'express-session';
import * as passport from 'passport';
import { PrismaClient } from '@prisma/client';


async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.setGlobalPrefix('api');
app.enableCors();
app.enableCors({
origin: 'http://localhost:5173', // Replace with your frontend domain
credentials: true, // Allow credentials (e.g., cookies) to be sent with the request
});
app.useGlobalPipes(new ValidationPipe());
app.use(session ({
store: new PrismaSessionStore(
new PrismaClient(),
{
checkPeriod: 2 * 60 * 1000, //ms
app.use(
session({
store: new PrismaSessionStore(new PrismaClient(), {
checkPeriod: 2 * 60 * 1000, //ms
dbRecordIdIsSessionId: true,
dbRecordIdFunction: undefined,
}
), // where session will be stored
secret: process.env.SESSION_SECRET, // to sign session id
resave: false,
saveUninitialized: false,
rolling: true, // keep session alive
cookie: {
maxAge: 30 * 60 * 1000, // session expires in 1hr, refreshed by `rolling: true` option.
httpOnly: false, // so that cookie can't be accessed via client-side script
sameSite: true
}
}));
}), // where session will be stored
secret: process.env.SESSION_SECRET, // to sign session id
resave: false,
saveUninitialized: false,

rolling: true, // keep session alive
cookie: {
secure: false,
maxAge: 30 * 60 * 1000, // session expires in 1hr, refreshed by `rolling: true` option.
httpOnly: true, // so that cookie can't be accessed via client-side script
},
}),
);
app.use(passport.initialize());
app.use(passport.session());


await app.listen(3001); // reminder to change it back to 3001
}
Expand Down

0 comments on commit 77265c4

Please sign in to comment.