Next x Nest - Using Supabase & Google OAuth in NestJS
Tags: webdev, nestjs, nextjs, passport
Published: 2023-09-02 11:02:20

Shall we pick up right where we left off from? The last article in this series was cut short due to excess length. We covered how to use Next Auth and Supabase with Google OAuth provider in NextJS in the last article. In this article, we will:
1.	Create a Backend in NestJS.
2.	Integrate Supabase into it using Prisma.
3.	Use a Passport to Integrate Google OAuth Strategy for Authentication (AuthN).
4.	Explore how to simultaneously use JWT Strategy in NestJS for Authorization (AuthZ).
5.	Make our NextJS frontend interact with the NestJS backend.

Before we proceed, I’d like to state that the Code for this mini-project is open-sourced in this Github Repo:

{%embed https://github.com/abhik-99/Trivial-Kanban %}

## Housekeeping
We first need to install Passport, Passport’s Google OAuth & JWT Strategy, and NestJS-specific Passport wrapper. For this reason, run the **`npm i passport passport-jwt passport-google-oauth20 @nestjs/jwt @nestjs/passport`**. This will install the dependencies. Next, we need to install the dev dependencies. Running ` npm i -D @types/passport-google-oauth20 @types/passport-jwt` will take care of that.

Also, we will be using environment variables in our NestJS backend project. For this, we need to install `@nestjs/config` and its dependencies. Run **`npm i @nestjs/config joi`**. For good measure, we will also be adding health checks to our backend. For this, we will use `@nestjs/terminus`. Unfortunately, that does not come built-in so as to make things lighter. We need to run `npm i @nestjs/terminus`. We will cover adding health checks in the last section of this article once we are done integrating the DB.

### Using Environment variables in NestJS
Just using environment variables is as easy as importing `ConfigModule` from `@nestjs/config` and adding it to our `app.module.ts`. But with NestJS, we can do so much more. NestJS allows us to check the environment file and make sure that certain env variables exist before we start the app. That’s where `joi` comes in.

While it might make more sense to some to create a new `DynamicModule` to wrap the `ConfigModule`, we are going to stick to the simpler solution and add our configuration to the `ConfigModule` all inside the `AppModule`. Our `app.module.ts` file would look something like this right about now.

```typescript
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { ConfigModule } from '@nestjs/config';
import * as Joi from 'joi';

@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true,
      validationSchema: Joi.object({
        DATABASE_URL: Joi.string().required(),
        DIRECT_URL: Joi.string().required(),
        GOOGLE_CLIENT_ID: Joi.string().required(),
        GOOGLE_CLIENT_SECRET: Joi.string().required(),
        GOOGLE_CALLBACK_URL: Joi.string().required(),
        APP_JWT_SECRET: Joi.string().required()
      }),
    })
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}


```

In the above code, we import `ConfigModule` inside `AppModule`. We tell NestJs that we want the `ConfigModule` (and in effect, the `ConfigService`) to be made available globally in the app using `isGlobal: true`. This will save us from adding the `ConfigModule` to every module in our NestJS backend app. Next, we define the schema of our env file. We tell NestJS that our ENV file should contain the variables with the conditions specified inside the `validationSchema` property. We use Joi to create a type-checker here. This is similar to Zod or Yup in the frontend.

`DATABASE_URL` & `DIRECT_URL` are for Supabase. `GOOGLE_CLIENT_ID`, `GOOGLE_CLIENT_SECRET`, and `GOOGLE_CALLBACK_URL` can be obtained from the GCP console. This was covered in the previous article. These env variables will be used Google OAuth using Passport. `APP_JWT-SECRET` is the secret we will use for minting and managing the authZ JWT token. With this schema defined, our `backend` app won’t start unless we have a `.env` will all the values marked as `required()` in the validation schema.

This completes our housekeeping part. We will now dive into the major topics of this article.

## Adding Passport and Google OAuth to NestJS
At this point, we already have a NestJS backend project setup in our Monorepo. We are able to run it in dev mode using Turborepo. We won’t directly get into the nitty-gritty details of creating a Backend for the Kanban Board. First, we will add AuthN and AuthZ to our backend app. The backend creation would come in the next article where we would build a GraphQL backend for our Kanban Board. By the time that article concludes, we would have a NestJS backend using GraphQL with authentication.

We need to import the `PassportModule` and `JwtModule` into our App Module. This will register them and tell NestJs that every time we use Passport or its corresponding functionality, NestJS can pick them up from here. Our `app.module.ts` file would now look like this:


```typescript
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { ConfigModule } from '@nestjs/config';
import * as Joi from 'joi';
import { PassportModule } from '@nestjs/passport';
import { JwtModule } from '@nestjs/jwt';

@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true,
      validationSchema: Joi.object({
        DATABASE_URL: Joi.string().required(),
        DIRECT_URL: Joi.string().required(),
        GOOGLE_CLIENT_ID: Joi.string().required(),
        GOOGLE_CLIENT_SECRET: Joi.string().required(),
        GOOGLE_CALLBACK_URL: Joi.string().required(),
        APP_JWT_SECRET: Joi.string().required()
      }),
    }),
    PassportModule,
    JwtModule.register({
      global: true,
    }),
  ],
  controllers: [AppController],
  providers: [AppService, GoogleStrategy, JwtStrategy],
})
export class AppModule {}


```

### Creating Google OAuth Strategy & Guard in Nest
Next, we move towards making a Google Login for our NestJS backend. The obvious question here could be “Why create a NestJS login if Login is already handled by NextJS & Next Auth” – Well the answer to that is to make sure someone can access our backend independent of the frontend. We will have Google OAuth-based Login on the backend and just as we did on the frontend, we will use the Authentication to get an `id_token` and an `access_token` from Google. This will complete the AuthN part. For the AuthZ part, we will mint a custom JWT (let’s call that `auth_token`, similar to what we did for the frontend. The `auth_token` is what we will check for in our other routes through the Guard we will make in the next section. This AuthZ token will be interoperable with the Frontend.

Firstly, we need to create a Strategy. The heavy lifting is really done by NestJs and Passport. We just to need to assemble the stuff. We will use the `clientID`, `clientSecret` values from what we got from the GCP console in the previous article. `callbackURL` in our case would be *http://localhost:3001/auth/google-redirect*. After authentication, google will redirect to this route on our backend with all the Google User profile data. We will need to create this route. It will be in our `AuthModule` covered below. The code below shows the contents of our strategy. We will call this file `google.strategy.ts` and place it in a new directory called `strategies` inside the `src` folder of the `backend` folder. Keep in mind that we need to pass the same names for the strategy and the guard for that strategy. So for instance, in the code, below at line 12 we tell Passport and Nest to use the Google `Strategy` and to call this whole strategy-guard collection as `google`.


```typescript
import { PassportStrategy } from '@nestjs/passport';
import {
  GoogleCallbackParameters,
  Profile,
  Strategy,
  VerifyCallback,
} from 'passport-google-oauth20';
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';

@Injectable()
export class GoogleStrategy extends PassportStrategy(Strategy, 'google') {
  constructor(configService: ConfigService) {
    super(
      {
        clientID: configService.get('GOOGLE_CLIENT_ID'),
        clientSecret: configService.get('GOOGLE_CLIENT_SECRET'),
        callbackURL: configService.get('GOOGLE_CALLBACK_URL'),
        scope: ['email', 'profile', 'openid'],
      },
      async (
        accessToken: string,
        refreshToken: string,
        params: GoogleCallbackParameters,
        profile: Profile,
        done: VerifyCallback,
      ) => {
        const { expires_in, id_token } = params;
        const {
          id,
          name,
          emails,
          photos,
          _json: { email_verified },
        } = profile;
        const user = {
          providerAccountId: id,
          email: emails[0].value,
          email_verified,
          firstName: name.givenName,
          lastName: name.familyName,
          picture: photos[0].value,
          accessToken,
          refreshToken,
          id_token,
          expires_in,
        };
        done(null, user);
      },
    );
  }
}


```

In the code above, apart from the values from GCP console, we tell Google OAuth that we want the email, profile, and conformance with the OpenID standard (and the related data). In the `async()` method, Google will send all the profile data. We need a select few things to create a user which would conform to the User table in our Supabase instance. We are picking the `expires_in` and `id_token` passed in `params` along with the `id`, `name`, `emails`, and `photos` from `profile` parameter. We also pick the `emails_verified` found in the `_json` property of the returned Google user profile. Between lines 36 and 47, we construct the `user` object with what we need on the Supabase table and invoke the `done` callback to signify that the first step of the authN is complete.

For the `http-google-oauth.guard.ts` file, we just need to add the below code to get it done. This guard below is where our user authentication starts. Keep in mind that we need to pass in the `google` key to the `AuthGuard` class at line 5. 


```typescript
import { Injectable } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';

@Injectable()
export class HttpGoogleOAuthGuard extends AuthGuard('google') {
  constructor() {
    super({
      accessType: 'offline',
    });
  }
}

```
Our flow would, thus, consist of the user going to the login link. The auth controller from `AuthModule` will get invoked at this link. This controller will have this guard on it. The user would be re-directed to Google Login page. On completion, the user will be redirected to our app at the `callbackURL` specified. At the `callbackURL`, the controller from `AuthModule` will use the Google strategy defined above to get the data, check if a user with that email exists in our database. If such a user exists then mint the user a `auth_token`. If it’s a new user, then save the user in the DB and then mint a JWT. Put the above guard in a separate folder called `guards` at the same level as that of `strategies`.

We will need to import the GoogleStrategy in our `app.module.ts` file. This we will cover in the later sections.

### Creating a JWT Auth Strategy & Guard in NestJs
After the Google Strategy, it's time for the JWT strategy. In the same `strategies` folder as above, create a file called `jwt.strategy.ts` and paste the code below. Explanations follow.


```typescript
import { ExtractJwt, Strategy } from 'passport-jwt';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy, 'jwt') {
  constructor(configService: ConfigService) {
    super({
      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
      ignoreExpiration: false,
      secretOrKey: configService.get("APP_JWT_SECRET"),
    });
  }

  async validate(payload: any) {
    return { userId: payload.sub, username: payload.username };
  }
}

```

Between lines 8 and 14, we define the constructor. Here we import the `configService`. We pick the `APP_JWT_SECRET` from our env variables and pass that on as the JWT encryption/decryption key through the `secretOrKey` arg to `super()`. We tell Passport that if the JWT has expired then it should not be allowed and also to extract the JWT from the headers at lines 11 and 10 respectively. This means that the JWT `auth_token` needs to be sent through the `authorization` header key and needs to be in a format like `Bearer <JWT Token>`. 

The `validate()` function receives the decoded JWT details and we just restructure it a bit before returning. The return from this function gets populated into `user` object inside our HTTP request. This completes the Strategy. Note how we pass the ‘jwt` here.

Next, in the `guards` folder create a file called `http-jwt-auth.guard.ts`. This file will contain the code below. Note how similar to the strategy above, we pass the same `jwt` to `AuthGuard` class thereby telling NestJS to associate this guard to the strategy of the same name.


```typescript
import { ExecutionContext, Injectable } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { AuthGuard } from '@nestjs/passport';
import { IS_PUBLIC_KEY } from 'src/decorators';

@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {
  constructor(private reflector: Reflector) {
    super();
  }
  canActivate(context: ExecutionContext) {
    const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [
      context.getHandler(),
      context.getClass(),
    ]);
    const isGoogleLogin = this.reflector.getAllAndOverride<boolean>("google-login", [
      context.getHandler(),
      context.getClass(),
    ]);
    if (isPublic || isGoogleLogin) {
      return true;
    }
    return super.canActivate(context);
  }
}


```

We pass in a `reflector` because we need to access the request here. The return from `canActivate()` determines if a request to invoke a controller can actually activate the code controller code or be rejected. If this function returns `true`, then the request is allowed to pass through. Otherwise it is stopped.

We have used something new here. It’s the `IS_PUBLIC_KEY`. We will define this in the next section. Basically, for public routes, this key will be set to true in the request metadata for public routes through a controller decorator. Similarly, for the Google Login route, we will allow the function to return `true`. So, if we find that the incoming request is for a public route or for our login route then it is allowed otherwise it needs to go through the JWT Auth pipeline to find out if it's coming from an authenticated user who is authorized to access our routes.

### Decorators for Routes in NestJS
If you have a basic knowledge of NestJS, you’d know what decorator tags are. We will need to define custom decorators to pick up the decoded JWT user object from requests and for public routes. Create a `decorators` folder on the same level as `strategies` and `guards` and then follow the explanations below.

#### Public Route Decorator
Public routes will have their controllers attached to this decorator so that the user can just pass through. The Code content for the `public.decorator.ts` is really simple for this as shown below. We just set the Metadata of the request so that the `isPublic` is set to `true` once the user request enters the NestJS pipeline.


```typescript
import { SetMetadata } from '@nestjs/common';

export const IS_PUBLIC_KEY = 'isPublic';
export const Public = () => SetMetadata(IS_PUBLIC_KEY, true);

```

#### HTTP Auth User Decorator
We need to create a `@HttpUser` decorator which will pick the `user` (coming from the decoded JWT) object from the HTTP request. This will be used for authenticated routes that require the logged-in user details. For this, create a file called `http-user.decorator.ts` and paste the code below.


```typescript
import { createParamDecorator, ExecutionContext } from '@nestjs/common';

export const HttpUser = createParamDecorator(
  (_data: unknown, ctx: ExecutionContext) => {
    const request = ctx.switchToHttp().getRequest();
    return request.user;
  },
);


```

In the above code, we get the `ExecutionContext`. This allows us access to the request and response objects in NestJS (though we only need to use the request part here). At line 5 we get the request and then at line 6 send the `user`. We could have used the `data` argument for custom operations. But that’s not needed here.

#### GraphQL Auth User Decorator
Similar to the decorator for extracting decoded `user` from HTTP requests, we need one for GraphQL requests. We need to put the code below inside `graphql-user.decorator.ts`. The code below does exactly what the decorator above does but for GraphQL requests.

```typescript
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
import { GqlExecutionContext } from '@nestjs/graphql';

export const GraphQLUser = createParamDecorator(
  (_data: unknown, context: ExecutionContext) => {
    const ctx = GqlExecutionContext.create(context);
    return ctx.getContext().req.user;
  },
);

```

## Adding Supabase to Nest
Now, we will add Supabase to our NestJS project. We will be using Prisma to connect to our Supabase Instance. At the heart of Supabase is a Postgres instance and Prisma can be used to connect to it and run queries with ease. Run `npm i -D prisma` to add it to our project and then run `npx prisma init` to initialize Prisma in our NestJS project. Additionally, we will also need the Prisma client to use Prisma in our project. So go ahead and run `npm i @prisma/client`.

> Note how `prisma` is a dev dependency but `@prisma/client` is not a dev dependency.

### Difference between DATABASE_URL and DIRECT_URL in Supabase


![Supabase](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/28epnj0mn8uqbzpdcuw7.png)

`DIRECT_URL` (1.) allows us to directly connect to the Supabase instance without our connection being pooled. It is like an admin link to connect to the underlying Postgres DB. It is good for migrations and introspections. It connects directly to Port **5432**.

But `DATABASE_URL` (2.) is the more general link to connect to DB to run queries. The connections through this link are pooled. These are good for in-code usage. This does not connect to port 5432 but a mapped port and link which can be different for every Supabase user.

### Creating a Prisma Module in NestJS
There is an NPM package called `nestjs-prisma` which can be used to provide connectivity between a NestJS and a DB using Prisma within a matter of seconds. It also comes with a Global Exception Filter to handle Prisma query-related errors. But I find creating a custom module to be a better way. So that’s what we are going to do here.

We don’t need controllers since the `PrismaModule` we are about to create won’t handle any endpoints. We just need a module and a service to encapsulate the business logic. So, we need to run two separate Nest CLI commands successively - `nest g module prisma` and `nest g service prisma –no-spec`. This will create a folder called `prisma` inside our `src` folder. 

We just to slightly edit the `prisma.module.ts` file by adding the `@Global()` decorator to the `PrismaModule` we just created as shown below. Along with this, we will also add `PrismaService` to the list of `exports`. This will allow us to use the service in any module without importing it.

```typescript
import { Global, Module } from '@nestjs/common';
import { PrismaService } from './prisma.service';

@Global()
@Module({
  providers: [PrismaService],
  exports: [PrismaService]
})
export class PrismaModule {}


```

For our `PrismaService`, we need it to inherit from `PrismaClient` (imported from `@prisma/client`) and then connect lazily to the DB. This can be done using the code below. Between lines 8 and 14, we provide the Database URL to Prisma for connection. This URL is available in the Supabase settings under *Connection pooling custom configuration* subsection in the *Database* tab (add the connection string with the password to our `.env` file). The code below shows our `prisma.service.ts` file.

```typescript
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { PrismaClient } from '@prisma/client';

@Injectable()
export class PrismaService extends PrismaClient {
  constructor(configService: ConfigService) {
    super({
      datasources: {
        db: {
          url: configService.get('DATABASE_URL'),
        },
      },
    });
  }

}


```

### Schema Introspection with Prisma
We won’t be defining the Schema. We won’t be copy-pasting it either. We will be using this cool feature called **DB Introspection**. Prisma will connect to the Postgres DB inside Supabase and automatically fill the `schema.prisma` file with the Schema of the tables inside the DB instance.

But to connect to the DB instance and introspect, we will not be using the `DATABASE_URL`. We will be using the `DIRECT_URL`. This can also be found in the Supabase settings in the **Database** tab under the *Connection String* sub-section. Add this to our `.env` file and then inside the `schema.prisma` file at the base of our `backend` project, add it to the `datasource`. Our `schema.prisma` file will look like this.

```
generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider  = "postgresql"
  url       = env("DATABASE_URL")
  directUrl = env("DIRECT_URL")
}
```

After this, we need to run `npx prisma db pull` and leave the rest to Prisma. When this command completes, our `schema.prisma` file will be populated with the schema of the tables already in our Supabase instance.

So now we have our schema ready and our project connected to the Supabase instance we created in the last article. 

## Authentication Endpoints (AuthModule)
After all of these steps, we will now move towards amalgamating what we have done in this sub-section. That starts with the creation of the `AuthModule`. In NestJs, you can easily create a set of controller endpoints, abstract the logic to a service, and create a complete module to use these through just a single line of code. Run `nest g resource auth –no-spec` to create the `AuthModule`. Keep in mind that our AuthModule will consist of REST API endpoints only and we only need 2 custom controllers which we will define ourselves below so no need to create the CRUD endpoints through this CLI.

On completion of the above command, an `AuthModule` will be created and imported into our main `AppModule`. Since we used the `--no-spec` file with the Nest CLI, no test files will be created. We will a Data Transfer Object or DTO to hold the Google User profile information. For this reason, create a `dto` folder inside the `auth` folder if you don’t have any, and then create a file called `google-login.dto.ts`. This file will contain our Google Profile info as given below.

```typescript
export class GoogleLoginUserDto {
  providerAccountId: string;
  email: string;
  email_verified: string;
  firstName: string;
  lastName: string;
  picture: string;
  accessToken: string;
  refreshToken: string;
  id_token: string;
  expires_in: number;
}


```

Next, move to the `auth.controller.ts` file and replace the contents of the file with the code below. In the code below, we define two endpoint routes at lines 15 and 18. Both of them will handle GET requests so they are annotated with the `@Get()` decorator. The `AuthController` will serve the base endpoint `/auth`. In line 9, we tell NestJS to set `google-login` metadata key as `true` for every request directed towards the `AuthModule` controller. This will allow the requests to by-pass the global JWT guard that we will set in a few moments.

At line 10, we are telling NestJS that any requests to this Controller are supposed to first pass through `HttpGoogleOAuthGuard` that we defined in the above sub-section. This can be observed from the `@Controller(‘auth’)` decorator at line 11 below. 

```typescript
import { Controller, Get, Req, SetMetadata, UseGuards } from '@nestjs/common';
import { AuthService } from './auth.service';
import { Request } from 'express';
import { HttpUser } from 'src/decorators';
import { HttpGoogleOAuthGuard } from 'src/guards';
import { GoogleLoginUserDto } from './dto/google-login.dto';


@SetMetadata('google-login', true)
@UseGuards(HttpGoogleOAuthGuard)
@Controller('auth')
export class AuthController {
  constructor(private readonly authService: AuthService) {}
  @Get()
  async googleAuth(@Req() _req: Request) {}

  @Get('google-redirect')
  googleAuthRedirect(@HttpUser() user: GoogleLoginUserDto) {
    return this.authService.googleLogin(user);
  }
}

```

Through the above code, we define the authN flow. Any login requests will come to `/auth` (GET) endpoint and be handled by the controller at line 15. Without any effort of ours, the user will be redirected to the Google Login page. After their login, they will be re-directed from Google to `/auth/google-redirect` endpoint which will be handled by the controller at line 18. This controller will receive the Google User profile data and will load that into the `GoogleLoginUserDto` for us with the help of `@HttpUser()` decorator which we defined before. We pass this user data to the `googleLogin()` method of the `AuthService` inside `auth.service.ts` file. The contents of the `auth.service.ts` are shown below.

```typescript
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { JwtService } from '@nestjs/jwt';
import { PrismaService } from 'src/prisma/prisma.service';
import { GoogleLoginUserDto } from './dto/google-login.dto';

@Injectable()
export class AuthService {
  constructor(
    private jwtService: JwtService,
    private configService: ConfigService,
    private prisma: PrismaService,
  ) {}
  async googleLogin(user: GoogleLoginUserDto) {
    if (!user) {
      throw new UnauthorizedException('No user from google');
    }
    const {
      firstName,
      lastName,
      email,
      email_verified,
      expires_in,
      picture,
      providerAccountId,
      accessToken,
      refreshToken,
      id_token,
    } = user;
    const userData = await this.prisma.users.findFirst({
      where: { email},
      include: { accounts: true },
    });
    if (!userData) {
      const newUserData = await this.prisma.users.create({
        data: {
          name: `${firstName} ${lastName}`,
          email: email,
          emailVerified: email_verified? (new Date()).toISOString(): null,
          image: picture,
          accounts: {
            create: {
              type: 'oauth',
              provider: 'google',
              providerAccountId: providerAccountId,
              access_token: accessToken,
              refresh_token: refreshToken,
              id_token: id_token,
              expires_at: expires_in,
            },
          },
        },
      });
      const access_token = await this.signJwt(
        newUserData.id,
        id_token,
        accessToken,
        expires_in,
      );
      return { access_token };
    }
    const access_token = await this.signJwt(
      userData.id,
      id_token,
      accessToken,
      expires_in,
    );
    return { access_token };
  }
  signJwt(
    userId: string,
    id_token: string,
    access_token: string,
    expires_at: number,
    expiresIn = '1d',
  ): Promise<string> {
    const payload = {
      sub: userId,
      id_token,
      access_token,
      expires_at,
    };
    return this.jwtService.signAsync(payload, {
      expiresIn,
      secret: this.configService.get('APP_JWT_SECRET'),
    });
  }
}


```

In the service above, we will need: 
1.	`JwtService` for minting a new `auth_token` (used for authZ) to the user.
2.	`PrismaService` to query the Supabase DB to find if it’s a new user or not. 
3.	`ConfigService` to fetch the JWT secret (`APP_JWT_SECRET` env variables).

We define these in the constructor of the `AuthService` class. These will be injected by the NestJS runtime. We use the `private` shorthand to make it class-scoped. Inside the `googleLogin()` function, we check if Google has passed us a valid user or not at line 15. If not, then terminate the request. 

If a valid user profile has been sent from Google, then at line 30 we query the Supabase DB’s `User` table to find if we have a user with the same email as sent by Google. If we don’t then it's safe to assume that it’s a new user. So, with the check at line 34, we insert the user into our `User` Table and create an entry in the `Account` table. We then create our `auth_token` called `access_token` and send it back as the response. If the user already exists, then we simply mint a authZ JWT and send it back regardless between lines 62 and 68.

Between lines 70 and 87, we define a wrapper for JWT minting. This wrapper, called `signJwt()`, takes the user ID from our `User` table, the opaque `access_token`, `id_token` & `expires_at` passed by Google to use and uses these as a payload to create a new JWT.

### Importing Strategies and Attaching Guards
Now before we finish off the `AuthModule`, there are a couple of things still pending. We need to add the JWT Auth Guard we created Globally. We also need to import the Google OAuth Strategy and JWT Strategy in our `AppModule` so that it is recognized app-wide.

For registering our Auth guard globally, we can just register it locally in any of the modules as a provider. Since we have created an `AuthModule`, that’s where we are going to add it to. Our `AuthModule` would, thus, look something like this:

```typescript
import { Module } from '@nestjs/common';
import { AuthService } from './auth.service';
import { AuthController } from './auth.controller';
import { APP_GUARD } from '@nestjs/core';
import { JwtAuthGuard } from 'src/guards';

@Module({
  controllers: [AuthController],
  providers: [
    AuthService,
    {
      provide: APP_GUARD,
      useClass: JwtAuthGuard,
    },
  ],
})
export class AuthModule {}


```

Finally, we can import our strategies into our main app module. With all the changes we have done above, our app module with the strategies would come to look something like the code given below:

```typescript
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { ConfigModule } from '@nestjs/config';
import { AuthModule } from './auth/auth.module';
import * as Joi from 'joi';
import { GoogleStrategy } from './strategies';
import { PassportModule } from '@nestjs/passport';
import { JwtModule } from '@nestjs/jwt';
import { JwtStrategy } from './strategies/jwt.strategy';
import { PrismaModule } from './prisma/prisma.module';

@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true,
      validationSchema: Joi.object({
        DATABASE_URL: Joi.string().required(),
        DIRECT_URL: Joi.string().required(),
        GOOGLE_CLIENT_ID: Joi.string().required(),
        GOOGLE_CLIENT_SECRET: Joi.string().required(),
        GOOGLE_CALLBACK_URL: Joi.string().required(),
        APP_JWT_SECRET: Joi.string().required()
      }),
    }),
    AuthModule,
    PassportModule,
    JwtModule.register({
      global: true,
    }),
    PrismaModule,
  ],
  controllers: [AppController],
  providers: [AppService, GoogleStrategy, JwtStrategy],
})
export class AppModule {}


```

This completes our addition of Authentication and Authorization to our backend. It should be able to access the same Database as our frontend NextJS app does with Next Auth. This would mean all our user data is in one place and a user can independently login from the frontend and backend. This opens up avenues like using the backend for Mobile App (something that we won’t cover). 

## Testing out Backend
The coding part of creating an authentication and authorization flow is not complete. We will now begin testing our NestJS application to make sure everything works as we expect.

In the video demo below, we run `npm run dev` to start the Turbo dev server. Our NestJS backend starts at port `3001` of localhost. As per the design, we have 3 routes. Since the JWT Auth guard is being used globally, all route requests will pass through it unless the route controller is annotated with `@Public()` decorator. If you try to access `http://localhost:3001/`, it will give you an Unauthorized Message as shown in the video below.

{% embed https://youtu.be/dp8ZT_Wr_Mk %}

We first need to head over to `http://localhost:3001/auth`. From there, we will be redirected to Google Login as shown above. After Google login, we are redirected to `http://localhost:3001/auth/google-redirect`. This route controller takes in the Google OAuth profile sent back to our app and mints a JWT token. The `access_token` sent in our video is in fact the NextJS frontend app’s `auth_token` counterpart.

When we attach this as the bearer token in auth header, we see that we are shown the **”Hello World!”** message on `http://localhost:3001`. This means our backend is working just as expected. You can try to head over to Supabase to verify if the user is created or not.

## Frontend & Backend Interaction in a NextJS and NestJS app

![Image depicting NextJS interacting with NestJS](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ja8bin66uh2zlkaaj13w.png)

The image above depicts the interaction diagram of our mini-project thus far. The Users come with their Authentication request and then
1.	On the frontend, NextJS + Next-Auth handles it using the `GoogleProvider`.
2.	On the backend, NestJS + Passport handles it using the `GoogleStrategy`.
This provides two independent but co-operating avenues for AuthN.

### Making the Next App Work with Nest Authentication
Now to make these interact, we will make a slight change to our `SignoutButton` component in the  `_components` directory of our `frontend` NextJS project. We will make it so that the ` SignoutButton ` component logs the `auth_token` if the user is authenticated. We will take this `auth_token` JWT and use it as a bearer to access `http://localhost:3001`, i.e., the protected Nestjs `backend` route. If we receive a successful response then we can be sure that the `auth_token` is fulfilling its purpose as AuthZ token. Our `SignoutButton` component will look like this:

```typescript
"use client";
import { signIn, signOut, useSession } from "next-auth/react";
import React from "react";

const SignoutButton = () => {
  const { data: session } = useSession();
  console.log("Session data", session)
  if (session?.user) {
    return (
      <div className="flex gap-4 ml-auto">
        <p className="text-sm tracking-tight text-sky-400">
          {session.user.name}
        </p>
        <button onClick={() => signOut()}>Sign Out</button>
      </div>
    );
  }
  return <button onClick={() => signIn()}>Sign in</button>;
};

export default SignoutButton;


```

While at it, we will also use a new Google User to sign in from our front end. This will make sure that Supabase creates a new record which will then be accessed independently from our backend as shown in the video demo below:

{% embed https://youtu.be/B60FTSIrbDw %}

## Conclusion
This concludes our long blog post. We finish what we had started in the first article of this series. With this, we have completed the Authentication and Authorization flow. We now have a NextJS app utilizing Next Auth and Google Provider which can interact with a NestJS backend app.

From the next article onwards, we will start building the core of our project. We will start with the backend and then move to the frontend. Until then keep building awesome things!