diff --git a/apps/api/.env.sample b/apps/api/.env.sample index 6ef15e4..72ef032 100644 --- a/apps/api/.env.sample +++ b/apps/api/.env.sample @@ -2,3 +2,6 @@ DATABASE_URL = "postgres://postgres:postgres@localhost:5432/disworse" POSTGRES_DB = 'disworse' POSTGRES_USER = 'postgres' POSTGRES_PASSWORD = 'postgres' +GOOGLE_CLIENT_ID = '' +GOOGLE_CLIENT_SECRET = '' +GOOGLE_CALLBACK_URL = 'http://localhost:3333/api/auth/google/redirect' \ No newline at end of file diff --git a/apps/api/package.json b/apps/api/package.json index 6138e00..2538bec 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -30,11 +30,15 @@ "@nestjs/config": "^3.2.3", "@nestjs/core": "^10.0.0", "@nestjs/graphql": "^12.2.0", + "@nestjs/passport": "^10.0.3", "@nestjs/platform-express": "^10.0.0", + "@types/passport-google-oauth20": "^2.0.16", "argon2": "^0.41.1", - "nestjs-zod": "^3.0.0", "drizzle-orm": "^0.33.0", "graphql": "^16.9.0", + "nestjs-zod": "^3.0.0", + "passport": "^0.7.0", + "passport-google-oauth20": "^2.0.0", "pg": "^8.13.0", "postgres": "^3.4.4", "reflect-metadata": "^0.2.0", diff --git a/apps/api/src/modules/auth/auth.controller.ts b/apps/api/src/modules/auth/auth.controller.ts index 617c6f0..ff1a70e 100644 --- a/apps/api/src/modules/auth/auth.controller.ts +++ b/apps/api/src/modules/auth/auth.controller.ts @@ -1,11 +1,12 @@ -import { Body, Controller, Post } from "@nestjs/common"; +import { Body, Controller, Post, Get, Req, UseGuards } from "@nestjs/common"; import { SerializedUser } from "../../common/serialized-types/user"; import { AuthService } from "./auth.service"; import { SignupDto } from "./dto/signup.dto"; +import { AuthGuard } from '@nestjs/passport'; @Controller("auth") export class AuthController { - constructor(private readonly authService: AuthService) {} + constructor(private readonly authService: AuthService) { } @Post("signup") async signup(@Body() signupDto: SignupDto) { @@ -13,4 +14,15 @@ export class AuthController { return new SerializedUser(user); } + + @Get('google') + @UseGuards(AuthGuard('google')) + async googleAuth(@Req() req: Request) { + } + + @Get('google/redirect') + @UseGuards(AuthGuard('google')) + googleAuthRedirect(@Req() req: Request) { + return this.authService.googleLogin(req); + } } diff --git a/apps/api/src/modules/auth/auth.module.ts b/apps/api/src/modules/auth/auth.module.ts index 0204c4b..ac9aa4c 100644 --- a/apps/api/src/modules/auth/auth.module.ts +++ b/apps/api/src/modules/auth/auth.module.ts @@ -1,9 +1,10 @@ import { Module } from "@nestjs/common"; import { AuthController } from "./auth.controller"; import { AuthService } from "./auth.service"; +import { GoogleStrategy } from './google.strategy'; @Module({ - providers: [AuthService], + providers: [AuthService, GoogleStrategy], controllers: [AuthController], }) export class AuthModule {} diff --git a/apps/api/src/modules/auth/auth.service.ts b/apps/api/src/modules/auth/auth.service.ts index 7222d7a..8c93297 100644 --- a/apps/api/src/modules/auth/auth.service.ts +++ b/apps/api/src/modules/auth/auth.service.ts @@ -6,7 +6,7 @@ import { SignupDto } from "./dto/signup.dto"; export class AuthService { private readonly logger = new Logger(AuthService.name); - constructor() {} + constructor() { } async signup(signupDto: SignupDto) { const user = signupDto; // TODO: fake signup till we have user model @@ -24,5 +24,14 @@ export class AuthService { ); return user; } + + googleLogin(req: any) { + if (!req.user) { + return 'No user from google' + } + return { + message: 'User information from Google', + user: req.user, + } + } } -1; diff --git a/apps/api/src/modules/auth/google.strategy.ts b/apps/api/src/modules/auth/google.strategy.ts new file mode 100644 index 0000000..4b38fb5 --- /dev/null +++ b/apps/api/src/modules/auth/google.strategy.ts @@ -0,0 +1,32 @@ +import { Injectable } from '@nestjs/common'; +import { PassportStrategy } from '@nestjs/passport'; +import { Strategy, VerifyCallback } from 'passport-google-oauth20'; + +@Injectable() +export class GoogleStrategy extends PassportStrategy(Strategy, 'google') { + constructor() { + super({ + clientID: process.env.GOOGLE_CLIENT_ID, + clientSecret: process.env.GOOGLE_CLIENT_SECRET, + callbackURL: process.env.GOOGLE_CALLBACK_URL, + scope: ['email', 'profile'], + }); + } + + async validate( + accessToken: string, + refreshToken: string, + profile: any, + done: VerifyCallback, + ): Promise { + const { name, emails, photos } = profile; + const user = { + email: emails[0].value, + firstName: name.givenName, + lastName: name.familyName, + picture: photos[0].value, + accessToken, + }; + done(null, user); + } +}