Securing Gatsby with Auth0

Go ahead and open an issue on the GitHub issues page. That way I can link both this thread and that GitHub issue in Slack to them.

Awesome, I opened the issue https://github.com/auth0/auth0.js/issues/1102

Thanks again. There might be something In the newer version of Gatsby that i causing this bug.

1 Like

So, we successfully deployed Auth0 and Gatsby on a production site. However, we ran into a frustrating bug. Basically, after as user logs in with Auth0, if the user then refreshes the page for whatever reason, a 404 Error appears, that the Auth0 authentication can’t be accessed. If you navigate the site without refreshing pages you are fine, but the minute you try to refresh the page, which happens quite often with users, the page is gone and there is a 404 error. Now I know this has to do with React Router somehow and how it processes the app, but the application demo with Auth0 and Gatsby uses React Router (@reach/router), so I’m wondering how we are supposed to fix this problem on a production site?

@ddsgadget are you using a connection/social provider like Google to login by chance? If you are you’ll need to register and create production keys with that provider. The Auth0 dev keys for those connections don’t work in production and won’t work with the silent auth. Click on the instructions for the right provider here for a tutorial on how to do it: https://auth0.com/docs/connections/identity-providers-social

No, we are not using Google login. The only thing that changed is that we were using “passwordless” login, and it was working fine actually. Then we switched to Database authentication (as we needed additional functionality), and the app simply stopped working. So we switched back to “passwordless” and now we continue to have problems. After a user logs in, if they refresh the page, it shows a 400 error (Failed to load resource: the server responded with a status of 400 ). The resource that fails to load is the auth0 url (domain/authorize?client_id) etc. The strange thing is that if you never refresh the page, it navigates fine and you are logged in. But, if you refresh, then it just doesn’t load the auth0.

So we have run many more tests. The error we get on a page refresh is:
**invalid_request** : The specified redirect_uri 'https://www.OURWEBSITE.com/callback' does not have a registered origin.

Obviously, ourwebsite.com is changed to our website. This is a strange error, because the callback works fine without a page refresh, so why would the callback not work on a page refresh?? Our settings are fine and we have the callback page, and when a user clicks on the website, the callback is called without any errors.

Just a quick update, we believe we have solved the problem, by dropping the trailing slash from our origin URL. So we had it as: http://www.ourwebsite.com/ - but when we change the origin URL to http://www.ourwebsite.com , without the ‘/’- it seems to work fine.

Perfect to hear that!

@sam.julien Do you have any updates on the article to set up Gatsby with auth0-spa-js?

Also, wanted to flag comment #29 from @dmitriy.movch

Am I correct, anybody can set the flag isLoggedIn to ‘true’ in local storage in his browser and get access to the route /account and he doesn’t need to login? It is not secure.

In testing my site, I easily bypassed Auth0 by manually setting isLoggedIn to true in the browser devtools. Then I was able to continue to access ‘protected’ pages since isAuthenticated() ONLY checks if isLoggedIn is true. It was surprisingly easy to figure out how get around authentication.

Are there more checks I can run as part of isAuthenticated()? Should I be calling checkSession()? Should I be using a nonce as mentioned in the docs and in Mitigate Replay Attacks When Using the Implicit Flow? Is there a way to verify the accessToken and idToken in the following way?

export const isAuthenticated = () => {
  if (!inBrowser) {
    return;
  }
  const isLoggedIn = localStorage.getItem(IS_LOGGED_IN) === 'true';
  const hasValidAccessToken = validateToken(tokens.accessToken);
  const hasValidIdToken = validateToken(tokens.idToken);

  return isLoggedIn && hasValidAccessToken && hasValidIdToken;
};

const validateToken = (token) => {
  // validate JWT?
  // send to Auth0 for validation?
  // call checkSession and make sure the tokens and/or nonce match up?
}

It just seems like there’s a lot of room for improvement here and I’m not sure where to start :sweat_smile:

Another bug I found is when a user goes to the website and logs in. isLoggedIn is set to true. Then, let’s say the user forgets to log out and then returns a few days later. isLoggedIn is still set to true, but the session and token have all expired. The user is still able to get to ‘protected’ pages since isAuthenticated() only checks if isLoggedIn is true.

My attempt to fix this is the following:

  1. in gatsby-browser.js, componentDidMount calls silentAuth()
  2. silentAuth() calls checkSession()
  3. checkSession calls setSession() with an error since the session is expired
  4. my fix: in the if (err) block of setSession(), set isLoggedIn to false
  5. now isAuthenticated() returns false
  6. when the user tries to go to /account, it calls login()

Does this sound like the right way to fix this?

Hey there @dc.gaudium!

I’m sure @sam.julien will look at it once he’s online

Hmmm… Quickly glancing through the docs for the auth0-spa SDK, it looks like it solves a lot of the problems I mentioned. If the Gatsby-specific SPA article is still in the works, I’m looking at the following articles:

Looks like those are good places to start. @sam.julien Are there any other articles that would help or other articles that I’m missing?

Hey @dc.gaudium, thanks for following up. Yes, the SPA SDK will solve nearly everything we’ve mentioned in this thread. We’re coming out with a new article on Gatsby auth this week, so stay tuned for that. It will be used in conjunction with the new React SDK.

Another resource that may help is my talk on auth in Gatsby from Byteconf React: https://www.youtube.com/watch?v=GdsKB6_6pdk

The slides and sample code and stuff is all here: http://samj.im/byteconf-react

That talk is not specific to Auth0 but shows the same approach we use for the SPA SDK. Just know that the new React SDK will abstract away the need to create your own context and hooks.

Hello. I have done everything on tutorial. On local works perfect. But when I deploy to Netlify or Vercel. Login page only showing loading. I have done all the credentials true. And local build also not working. Can anyone know the issue?

Thanks, for the post. We took this solution and applied it to the auth0-lock. It works for gastby-develop and the lock shows up just fine on the localhost. However, on gatsby-build, the build is successful, but the lock is failing to load. We get the following error.
Uncaught (in promise) Error: page resources for /signup/ not found. Not rendering React at production-app.js:128
We have signup component which renders fine, but inside that component, it is not able to import these:

import { Auth0Lock, Auth0LockPasswordless } from "auth0-lock"
At this point we are stuck. Not sure how to proceed.

Additional information is that we had to apply resolutions as suggested from this post. Otherwise, it would break immediately. I am not sure if the resolution is causing any issues. If anyone had any luck running auth0-lock with Gatsby, please kindly chime in. Thank you!

Hello,
I am trying to get Auth0-Lock working on our Gatsby site. It works great on the local. However, after publishing the site, it is not redirecting.
Essentially, what we found was it is not firing the lock.on('authenticated', function(authResult) {....
We followed the instructions from the blog post (https://auth0.com/blog/securing-gatsby-with-auth0/) and created this repo with our modifications: https://github.com/GreenOn/auth0-lock-gatsby.

And here is the hosted site: http://gatsby-auth0-lock-test.s3-website.us-east-2.amazonaws.com/.
We tried all kinds of things, but unable to get our site redirected. Could anyone take a look and help, please?
Thanks!
Pramod

The above message was merged into this thread not to complicate communication. Thanks!

1 Like

We had to comment out the loaders.null() part out of the gatsby-node-js file to get rid of the Uncaught (in promise) Error: page resources for /signup/ not found.

// exports.onCreateWebpackConfig = ({ stage, loaders, actions }) => {
  //   if (stage === "build-html") {
  //     /*
  //      * During the build step, `auth0-js` will break because it relies on
  //      * browser-specific APIs. Fortunately, we don’t need it during the build.
  //      * Using Webpack’s null loader, we’re able to effectively ignore `auth0-js`
  //      * during the build. (See `src/utils/auth.js` to see how we prevent this
  //      * from breaking the app.)
  //      */
  //     actions.setWebpackConfig({
  //       module: {
  //         rules: [
  //           {
  //             test: /auth0-lock/,
  //             use: loaders.null(),
  //           },
  //         ],
  //       },
  //     })
  //   }
  // }

Now we at least get the lock.show() getting fired but no luck in getting the lock.on working.
Again, it works on the localhost but not on the hosted site.

–> Reproducible Repo and Hosted Site.

I think we figured this out. On the localhost, it is a like a singlepage app, so after successfully logging in, it was able to find lock object on any page. However, on the production site, it is converting everything to static pages. So, lock object is only available on the signin page. When it returns to the index page, since the auth.js file out of utils is not referenced there, it doesn’t do anything. So, to solve the problem, auth.js reference was added to the index.js file and it works fine now. This was a bit tricky and glad that it is finally working.

1 Like

Perfect! Glad to hear that!