#Angular + Nest Google Log In CORS error

74 messages · Page 1 of 1 (latest)

hasty sage
#

Everytime I try to log in through Google from Angular, calling the GET method on the google log in route(http://localhost:3000/api/auth/google/login) It gives me a CORS error.

To start, I am able to get to Log In, redirect and get authenticated in my backend with no problem!

I even get the JWT in my response which then I thought I could use this code to retrieve and assign the token to the Authorization headers to get through my guard.

I am able to do it local but not through Google.

Here is what I am trying:

#

in my backend:

NestJs Controller

  @Get('google/login')
  @UseGuards(GoogleAuthGuard)
  handleLogin(@Request() req) {
  
  }


  @Get('google/redirect')
  @UseGuards(GoogleAuthGuard)
  async googleLoginCallback(@Req() req, @Res() res) {
    const user = req.user; // The user object should be available after Google authentication

    // Generate the Google-specific JWT
    const genUser = await this.authService.googleLogin(user);
    const authToken =  genUser.authToken;

    // Redirect to the frontend callback URL with the token as a query parameter
    return res.redirect(`http://localhost:4200?token=${authToken}`);

    
  }

  @Get('status')
  user(@Request() req) {
    console.log(req.user);
    if (req.user) {
      return { msg: 'Authenticated' };
    } else {
      return { msg: 'Not Authenticated' };
    }
  }
vital crown
#

What does your cors config look like? What is the specific cors error you're dealing with?

hasty sage
#

Angular :


    <a (click)="handleGoogleLogin()"
        class="btn btn-flex btn-outline btn-text-gray-700 btn-active-color-primary bg-state-light flex-center text-nowrap w-100">
        <img alt="Logo" src="./assets/media/svg/brand-logos/google-icon.svg" class="h-15px me-3" />
        Sign in with Google
      </a>

Component:


  handleGoogleLogin(): void {
    this.authService.loginWithGoogle().subscribe(
      (data) => {
        const authToken = data.token; 
        localStorage.setItem('authToken', authToken);
      },
      (error) => {
        console.error('Error while logging in with Google:', error);
      }
    );
  }
  

SERVICE:


 loginWithGoogle(): Observable<any> {


    return this.http.get<any>(`${this.apiUrl}/auth/google/redirect`);
    
  }

this is my error:


:4200/auth/login:1 Access to XMLHttpRequest at 'https://accounts.google.com/o/oauth2/v2/auth?response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fapi%2Fauth%2Fgoogle%2Fredirect&scope=profile%20email&client_id=688590457392-ci81rp7df9au2r97gk4pgggljqqe31iu.apps.googleusercontent.com' (redirected from 'http://localhost:3000/api/auth/google/redirect') from origin 'http://localhost:4200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
vital crown
#

And the cors config?

hasty sage
#

omw!

hasty sage
# vital crown And the cors config?
async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.enableCors();
  app.setGlobalPrefix('api');
  app.use(
    session({
      secret: 'edlnoqwihebdoqiwheblzaIBWDXUVQW',
      saveUninitialized: false,
      resave: false,
      cookie: {
        maxAge: 60000,
      },
    }),
  );
  app.use(passport.initialize());
  app.use(passport.session());
  app.useGlobalPipes(new ValidationPipe());
  bootstrapSwagger(app);
  await app.listen(3000);
}
vital crown
#

That's essentially just origin: '*' which will eventually have problems as you should be specifying the origin when you send cookies, just an FYI

hasty sage
#

I should change it to this:

#
app.use(
    CorsMiddleware({
      origin: 'http://localhost:4200',
      allowedHeaders: ['Content-Type', 'Authorization'],
      methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
      credentials: true, 

    }),
  );```
#

?

hasty sage
vital crown
hasty sage
#

do you have a better suggestion? Ive been doing this since 8:30am and have tried many ways with no resolution

#

changed and still doing this:

login:1 Access to XMLHttpRequest at 'https://accounts.google.com/o/oauth2/v2/auth?response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fapi%2Fauth%2Fgoogle%2Fredirect&scope=profile%20email&client_id=688590457392-ci81rp7df9au2r97gk4pgggljqqe31iu.apps.googleusercontent.com' (redirected from 'http://localhost:3000/api/auth/google/redirect') from origin 'http://localhost:4200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

vital crown
hasty sage
#

yes, is this the wrong approach?

#

Because I want to get the data from that request

#

so I can assign my AuthToken

#

it returns my authToken as part of the response

vital crown
#

You should be navigating the urser to that URL, whether in the same tab or a new one. I would expect a redirect to actually take you there, rather than try to get just the data, unless you've already gotten the auth token form the OAuth provider

#

If you are doing a get call with the auth token, then the UI should send the token to the server and the server should make a new GET to the OAuth provider's API as to ignore the cross origin restriction from the browser, as server to server doesn't havethe same restriction

hasty sage
#

can you help me with an example of this

#

I feel stupid

vital crown
#

Don't use redirect on the server when you send the auth token to the server, just make a new GET with axios or whatever HTTP client you fancy

#

I have a general different flow that I prefer, but it uses cookies and sessions rather than JWTs and I currently don't have a public example\

hasty sage
#

But to get through my guard, I have to have it in agular right?

hasty sage
#

the token

#

my angular is protected, without checking if im an user i dont get through

#

i thought i needed my token in the frontend to check if its true

vital crown
#

What token? The JWT from your server of the auth token from your OAuth provider's server?

hasty sage
#

JWT

#

are there two? Should I not be using Jwt?

vital crown
#

It all really depends. A "token" is just a string that the server "knows"* about. JWTs are tokens in a very specific format that should be stateless and contain the information to validate them minus the signing secret. The auth token from the OAuth provider can be used to get more information about the user from the OAuth provider, and should only be used with the OAuth provider, not for general authentication purposes. Refresh tokens are usually tokens that are used when the original access token is expired and needs to be renewed

  • by "knows", in this case I mean that the server can validate its authenticity
hasty sage
#

Man! I am back to square one. So everything I have done is wrong.

#

Im getting my google user, its creating in the backend, everything is good, but I cannot use any of that to go through my guard in the frontend.

#

Do you know where I can learn about this?

#

I am stuck 😦

#

or to even save in my interceptor.

vital crown
hasty sage
#

yes

#

one sec

vital crown
#

So what's your check in the front end for "is logged in" because you should just be able to keep using that

hasty sage
#
"firstName": "Ken",
"lastName": "Flores",
"profilePicture": "https://lh3.googleusercontent.com/a/AAcHTtc-1BPuRo2ruhNRXksebJ2oBEhJHaQoSgOJEsbByDR52w=s96-c",
"authProvider": "google",
"__v": 0
},
"authToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJnb29nbGUiLCJlbWFpbCI6ImtmbG9yZXNAd2VhcmVyYWRpYW50LmNvbSIsImlhdCI6MTY5MDg0NDc4OSwiZXhwIjoxNjkwODQ0ODQ5fQ.Fq5ylCAb73s8-0OHfhzvzeiYKYbzGdyJh1IByVwjSIs"

#

How does it know where that information is? Because I dont know how to give the frontend the authToken

#

That is the response when I go through the log in process in the backend

vital crown
hasty sage
#

after this route


  @Get('google/redirect')
  @UseGuards(GoogleAuthGuard)
  async googleLoginCallback(@Req() req) {
    const user = req.user; // The user object should be available after Google authentication

    // Generate the Google-specific JWT
    const genUser = await this.authService.googleLogin(user);

    const authToken =  genUser.authToken;

    // Redirect to the frontend callback URL with the token as a query parameter
    // return res.redirect(`http://localhost:4200?token=${authToken}`);

    return this.authService.googleLogin(user);
  }

#

is there a package to get it?

vital crown
#

There's a lot of state management packages. Take your pick

#

I haven't been in the angular world much recently so I can't really suggest much

hasty sage
#

If you have a project with Google I have no problem breaking my code.

I rather just learn one good way to understand than just keep trying like this

#

State Management from Angular or Nest

#

Shouldnt it be saved with Nest

vital crown
hasty sage
#

ok sorry

vital crown
vital crown
# hasty sage Shouldnt it be saved with Nest

There should be a user record in the database. But your front end needs to keep track of the user as well, unless you just want to constantly ask the backend "what user is this?" every time you load up a new component

hasty sage
#

Got it! Should I just google that then? Angular user state management>

vital crown
#

This isn't necessarily specific to storing the user, just angular state management should do

hasty sage
#

ok thank you!

#

As far as the importing the token

#

it should be sending jwt through a cookie right

hasty sage
#

Im still working on this. I have set a cookie, but now I have no Idea what to do in the angular side lol

vital crown
#

What kind of cookie is it? HttpOnly?

hasty sage
#

yes

vital crown
#

You can't read HttpOnly cookies in JS (React, Angular, Vue, or otherwise). You need to actually return some user data after authentication to put it in the local store

hasty sage
#

beautiful

#

lol

#

I have probably watched 25 videos by now and none are clear on what to do with authentication with NestJS and Angular

vital crown
#

Don't look specifically for Nest + Angular. Look at Node authetnication with a frontend. Nest is just a Node framework at the end of the day, and each of the major three front end framework have their own way™️ of doing things, but it's all very similar