feat: add authentication using Discord oauth2 and JWT
Temporarily disabling GraphQL using Mercuris due to moving to Express (previously fastify)
This commit is contained in:
parent
782698788b
commit
fbf7272526
@ -14,6 +14,7 @@
|
||||
"preinstall": "node -e \"if(process.env.npm_execpath.indexOf('yarn') === -1) throw new Error('You must use Yarn to install, not NPM')\""
|
||||
},
|
||||
"dependencies": {
|
||||
"@fastify/passport": "^3.0.1",
|
||||
"@nestjs/common": "^10.0.0",
|
||||
"@nestjs/config": "^3.3.0",
|
||||
"@nestjs/core": "^10.0.0",
|
||||
@ -21,6 +22,7 @@
|
||||
"@nestjs/jwt": "^10.2.0",
|
||||
"@nestjs/mercurius": "^12.2.1",
|
||||
"@nestjs/passport": "^10.0.3",
|
||||
"@nestjs/platform-express": "^10.4.11",
|
||||
"@nestjs/platform-fastify": "^10.4.9",
|
||||
"@prisma/client": "5.22.0",
|
||||
"axios": "^1.7.7",
|
||||
@ -29,6 +31,9 @@
|
||||
"graphql-tools": "^9.0.4",
|
||||
"graphql-ws": "^5.16.0",
|
||||
"mercurius": "14",
|
||||
"passport": "^0.7.0",
|
||||
"passport-discord": "^0.1.4",
|
||||
"passport-jwt": "^4.0.1",
|
||||
"prisma": "^5.22.0",
|
||||
"reflect-metadata": "^0.2.0",
|
||||
"rxjs": "^7.8.1",
|
||||
@ -39,6 +44,7 @@
|
||||
"@nestjs/schematics": "^10.0.0",
|
||||
"@types/express": "^5.0.0",
|
||||
"@types/node": "^20.3.1",
|
||||
"@types/passport-discord": "^0.1.14",
|
||||
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
||||
"@typescript-eslint/parser": "^8.0.0",
|
||||
"eslint": "^9.0.0",
|
||||
|
@ -8,6 +8,7 @@ import { AppService } from "./app.service";
|
||||
import { UserModule } from "./user/user.module";
|
||||
|
||||
import { GraphqlOptions } from "./graphql/graphqlOptions";
|
||||
import { AuthModule } from './auth/auth.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
@ -18,11 +19,12 @@ import { GraphqlOptions } from "./graphql/graphqlOptions";
|
||||
global: true,
|
||||
secret: process.env.JWT_SECRET,
|
||||
}),
|
||||
GraphQLModule.forRootAsync<MercuriusDriverConfig>({
|
||||
driver: MercuriusDriver,
|
||||
useClass: GraphqlOptions,
|
||||
}),
|
||||
// GraphQLModule.forRootAsync<MercuriusDriverConfig>({
|
||||
// driver: MercuriusDriver,
|
||||
// useClass: GraphqlOptions,
|
||||
// }),
|
||||
UserModule,
|
||||
AuthModule,
|
||||
],
|
||||
providers: [AppService],
|
||||
})
|
||||
|
33
src/auth/Strategy/discord.strategy.ts
Normal file
33
src/auth/Strategy/discord.strategy.ts
Normal file
@ -0,0 +1,33 @@
|
||||
import { Injectable } from "@nestjs/common";
|
||||
import { JwtService } from "@nestjs/jwt";
|
||||
import { PassportStrategy } from "@nestjs/passport";
|
||||
import { Profile, Strategy } from "passport-discord";
|
||||
|
||||
@Injectable()
|
||||
export class DiscordStrategy extends PassportStrategy(Strategy, "discord") {
|
||||
constructor(private jwtService: JwtService) {
|
||||
super({
|
||||
clientID: process.env.DISCORD_CLIENT_ID,
|
||||
clientSecret: process.env.DISCORD_CLIENT_SECRET,
|
||||
callbackURL: process.env.DISCORD_CALLBACK_URL,
|
||||
scope: ["identify", "email"]
|
||||
});
|
||||
}
|
||||
|
||||
async validate(
|
||||
_accessToken: string,
|
||||
_refreshToken: string,
|
||||
profile: Profile,
|
||||
done: Function,
|
||||
) {
|
||||
const jwtPayload = {
|
||||
id: profile.id,
|
||||
username: profile.username,
|
||||
email: profile.email,
|
||||
};
|
||||
|
||||
const jwt = this.jwtService.sign(jwtPayload);
|
||||
|
||||
done(null, { jwt });
|
||||
}
|
||||
}
|
19
src/auth/Strategy/jwt.strategy.ts
Normal file
19
src/auth/Strategy/jwt.strategy.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import { Injectable } from "@nestjs/common";
|
||||
import { PassportStrategy } from "@nestjs/passport";
|
||||
import { Profile } from "passport-discord";
|
||||
import { Strategy, ExtractJwt } from "passport-jwt";
|
||||
|
||||
@Injectable()
|
||||
export class JWTStrategy extends PassportStrategy(Strategy) {
|
||||
constructor() {
|
||||
super({
|
||||
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
|
||||
ignoreExipration: false,
|
||||
secretOrKey: process.env.JWT_SECRET,
|
||||
});
|
||||
}
|
||||
|
||||
async validate(profile: Profile): Promise<any> {
|
||||
return profile;
|
||||
}
|
||||
}
|
36
src/auth/auth.controller.ts
Normal file
36
src/auth/auth.controller.ts
Normal file
@ -0,0 +1,36 @@
|
||||
import { Controller, Get, Req, Res, UseGuards } from "@nestjs/common";
|
||||
import { AuthGuard } from "@nestjs/passport";
|
||||
import { URLSearchParams } from "node:url";
|
||||
|
||||
@Controller("auth")
|
||||
export class AuthController {
|
||||
@Get("providers")
|
||||
Providers() {
|
||||
const discordOauth2Params = new URLSearchParams({
|
||||
client_id: process.env.DISCORD_CLIENT_ID,
|
||||
response_type: "code",
|
||||
redirect_uri: process.env.DISCORD_CALLBACK_URL,
|
||||
scope: "identify email",
|
||||
});
|
||||
|
||||
return {
|
||||
discord: {
|
||||
url: `https://discord.com/oauth2/authorize?${discordOauth2Params.toString()}`,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@Get("discord/callback")
|
||||
@UseGuards(AuthGuard("discord"))
|
||||
CallbackDiscord(@Req() req, @Res() res) {
|
||||
const { user } = req;
|
||||
|
||||
res.send(user);
|
||||
}
|
||||
|
||||
@Get("profile")
|
||||
@UseGuards(AuthGuard("jwt"))
|
||||
Profile(@Req() req) {
|
||||
return req.user;
|
||||
}
|
||||
}
|
12
src/auth/auth.module.ts
Normal file
12
src/auth/auth.module.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { Module } from "@nestjs/common";
|
||||
import { AuthController } from "./auth.controller";
|
||||
import { AuthService } from "./auth.service";
|
||||
|
||||
import { DiscordStrategy } from "./Strategy/discord.strategy";
|
||||
import { JWTStrategy } from "./Strategy/jwt.strategy";
|
||||
|
||||
@Module({
|
||||
controllers: [AuthController],
|
||||
providers: [AuthService, DiscordStrategy, JWTStrategy],
|
||||
})
|
||||
export class AuthModule {}
|
4
src/auth/auth.service.ts
Normal file
4
src/auth/auth.service.ts
Normal file
@ -0,0 +1,4 @@
|
||||
import { Injectable } from "@nestjs/common";
|
||||
|
||||
@Injectable()
|
||||
export class AuthService {}
|
@ -1,12 +1,8 @@
|
||||
import { NestFactory } from "@nestjs/core";
|
||||
import { AppModule } from "./app.module";
|
||||
import {
|
||||
FastifyAdapter,
|
||||
NestFastifyApplication,
|
||||
} from "@nestjs/platform-fastify";
|
||||
|
||||
async function bootstrap() {
|
||||
const app = await NestFactory.create(AppModule, new FastifyAdapter());
|
||||
const app = await NestFactory.create(AppModule);
|
||||
|
||||
app.enableCors({
|
||||
origin: "*",
|
||||
|
Loading…
Reference in New Issue
Block a user