Search code examples
oauth-2.0jwtpassport.jsgoogle-oauthfacebook-oauth

Passport & JWT & Google/Facebook Strategy - How do I combine JWT and Google/Facebook Strategy?


This question is for anyone who is familiar with

  • Node.js
  • Express
  • Passport
  • JWT Authentication with passport (JSON Web Tokens)
  • Facebook OAuth2.0 OR Google OAuth2.0

I have been doing some online courses and understand how to do the two following things:

  1. Authentication using Passport Local Strategy + JWT Tokens
  2. Authentication using Passport Google/Facebook Strategy + Cookie/sessions.

I am trying to combine the content from these two courses basically. I want to use Google Strategy + JWT Authentication. I want to use JWT instead of cookies because my app is going to be a web/mobile/tablet app, and I need to be accessing the api from different domains.

There are two issues I am having with this: To kick off the Google/facebook OAuth pipelines, you need to call either '/auth/facebook' or '/auth/google'. Both Oauth flows work basically the same so when I say '/auth/google' from now on, I am referring to either. Now the issue I'm having is: On the client, do I call the '/auth/google' route with a href button link or an axios/ajax call? If I use the href or axios/ajax approach I am still getting problems with both solutions.

The href approach problem: When I assign an <a> tag with a href to '/auth/google' the authentication works perfectly fine. The user gets pushed through the Google Auth flow, they log in and the '/auth/google/callback' route gets called. The problem I have now is how do I correctly send the JWT token back to the client from '/auth/google/callback'?

After a lot of googling I have seen that people have simply passed the the JWT back to the client from the oauth callback in the redirect query param. For example:

res.redirect(301, `/dashboard?token=${tokenForUser(req.user)}`);

The issue I have with this is that now the the ability to authenticate is saved in my browser history! I could log out (destroying the token saved in localStorage), and then simply look at my browser url history, go back to the url that contains the token in the query param, and I would automatically log in again without having to go through the Google Strategy! This is a huge security flaw and is obviously the incorrect way to approach it.

The axios/ajax approach problem: Now before I explain the problem with this issue, I know for sure that If I get this working, it will solve all issues I was having with the previous href problem. If I manage to call '/google/auth' from an axios.get() call and receive the JWT in the response body, I will not be sending the token as url param, and it will not get saved in the browser history! Perfect right? well there is still some problems with this approach :(

When try to call axios.get('/auth/google') I get the following error:

enter image description here

How I've tried to solve the problem:

  • I installed cors to my npm server, and added app.use(cors()); to my index.js.
  • I took a stab and added "http://localhost:3000" to the "Authorised JavaScript origins" in Google developer console.

Neither of these solutions solved the issue, so now I really feel stuck. I want to use the axios/ajax approach, but I'm not sure how to get past this cors error.

Sorry for such a long message, but I really felt I had to give you all the information in order for you to properly help me.

Thanks again, looking forward to hear from you!


Solution

  • I solved this in this way:

    1. On Front-End (can be mobile app) I made login request to Google (or Facebook) and after the user selected his account and logged in I got back response that contained google auth token and basic user info.
    2. Then I sent that google auth token to backend where my API sent one more request to the Google API to confirm that token. (See step 5)
    3. After successful request comes you get basic user info and e-mail. At this point, you can assume that user login via Google is good since google check returned that it's okay.
    4. Then you just signup or login user with that email and create that JWT token.
    5. Return token to your client and just use it for future requests.

    I hope it helps. I implemented this multiple times and it showed like a good solution.