Full Stack Architecture + Auth0

Hi,

I followed the React Authentication By Example: Using React Router 6 guide here(React Authentication By Example: Using React Router 6)

Everything is working perfect until the point in which… I try to use a NodeJS Express server."

Since the guide only works for Single Page Web Applications… I’m wondering if that is the problem.

When I go to the Settings on a Regular Web Application, on the Quick Start guide, it gives me the Integrate Auth0 option by installing express. Then it gives me this example code:

const { auth } = require(‘express-openid-connect’);

const config = {
authRequired: false,
auth0Logout: true,
secret: ‘a long, randomly-generated string stored in env’,
baseURL: ‘http://localhost:4040’,
clientID: ‘clientID’,
issuerBaseURL: ‘https://RANDOM.URL
};

// auth router attaches /login, /logout, and /callback routes to the baseURL
app.use(auth(config));

// req.isAuthenticated is provided from the auth router
app.get(‘/’, (req, res) => {
res.send(req.oidc.isAuthenticated() ? ‘Logged in’ : ‘Logged out’);
});


This does not happen on the Single Page Web Application. And I’m wondering if this is not allowing me to be able to use ‘express-openid-connect’.

Every time I try to use it… it gives me a 401 (Unauthorized) error when using an axios.get function.

Then on the Network tab, the response I get is “jwt malformed”.

I’ve checked all these settings on my index.js file on the server folder:

const { auth } = require(‘express-openid-connect’);

const verifyJWT = jwt({
secret: jwks.expressJwtSecret({
cache: true,
rateLimit: true,
jwksRequestsPerMinute: 5,
jwksUri: ‘https://randomURL.us.auth0.com/.well-known/jwks.json
}),
audience: ‘https://randomURL’,
issuer: ‘https://randomURL.us.auth0.com’,
algorithms: [‘RS256’]
}).unless({path: [‘/’]})

app.use(verifyJWT);

const config = {
authRequired: false,
auth0Logout: true,
secret: process.env.secret,
baseURL: ‘http://localhost:4040/’,
clientID: ‘clientID’,
issuerBaseURL: ‘https://randomURL.us.auth0.com
};

app.use(auth(config));


I can’t seem to see the problem.

1 Like

Hello, Oscar!

Thanks for reading this guide! :muscle:

For the API server integration that you’ll create on the Auth0 Dashboard is a new “API application” as outlined on these steps:

There’s no need to use a Regular Web Application for this purpose as that’s another type of client application.

Which document did you follow to set up the API?

1 Like

Well, first of all, thank you for The Guide. I followed the prior one too and got a working Timeline app running( https://timeline-cal.herokuapp.com/ ) that I made as practice for this next project.

Since this new guide came out I decided to update to React 18 and React Router v6. So I appreciate you making the guide for sure.

I feel like there’s a bit of confusion regarding a couple of things.

  1. The Application CategorizationS used by Auth0: Native, Single Page Web Application, Regular Web Applications and Machine to Machine Applications. The definitions, to me, as someone who has the intention to make something, are clear; yet for some reason, from my dev mindset, I do wonder what the backend differences are when selecting each different one -or- if there are any.

I do notice that there are differences in the UI/UX and options for each once selecting them. So that makes me wonder if there are any other actual backend differences.

The reason I say this is because when trying to tackle the JWT MALFORMED problem I found a few posts where people mentioned that I was probably getting an obfuscated token, and that certain Applications could do that. That in turn got me thinking that maybe by selecting Single Page Web Application… I was going to be unable to get a jwt token because it was going to give me an obfuscated one.

This is after first trying to follow The Guide but selecting Regular Web Application instead. I tried it this way and it did not work. Something was not allowing me to do it. It was a month ago so I don’t remember what it was. But I had to restart it and actually select Single Page Web Application.


  1. The Express.js Code Sample guide… I have tried to follow but it wants me to create a new project.

Since I am uploading this to Heroku… I need to have a Client Folder and a Server Folder structure.

The Guide contains a JSON API that I can make work no problem.

The problem occurs for me… when I try to now run an Axios.get call to a PostgreSQL server.

I suspect that it wants to authenticate every route request and I just haven’t figured out how to properly configure the axios.get function with the appropiate headers. But in the prior guide I was able to do this without it requiring an authentication on each request.

Since the prior Guide used a prior version of Router… there was actually a /login and /logout route. In the new guide those are gone. That means that /userinfo is also gone.

/profile works but that one is asking the auth0 for the info… that works fine.

when I try to redirect the axios.get request to my PostgreSQL server… it tells me that either the jwt is malformed or I get “Invalid Compact JWS”.

I’ve tried to troubleshoot this with Postman but Postman does not allow to use an Audience so… I’ve been trying from VSCode but no matter the settings on the .env files… it doesn’t seem to be able to go around those two jwt errors.

I’m thinking the

const apiRouter = express.Router();

is no longer relevant in this new Guide. On the server side at least.

The thing is that before…

app.get(‘/profile’, requiresAuth(), (req, res) => {
res.send(JSON.stringify(req.oidc.user));
});

I could use requiresAuth() to authenticate the request… but now… I don’t know if that is the case.

I’ll keep trying to make it work. I just don’t know where the problem is at the moment.

1 Like

Oscar, thank you so much for this detailed response and for highlighting the areas that may be confusing for developers looking to use Auth0 to protect their different application types.

I want to ensure that we provide you with a proper answer so I am sharing your post with my other teammates.

From the high-level, I can share that your deploy model is interesting: You want to deploy both the client and server at the same time to Heroku. Are you creating a monorepo for your full-stack application?

Is your backend application serving your client application?

I believe that the situation we have at hand relates more to system design/application architecture. To provide you with better support, do you mind if we move this question to its own Community topic? :slight_smile: Thanks!

1 Like

Dan,

I don’t mind moving this question to its own community topic.

Should I create a new topic for it?

I do have only one repository for the full stack application.

In the end I only push the server folder to Heroku since the client build is sent inside that folder in the public folder. So, I would assume that the answer to… is my backend application serving the client application… is yes.

This is what I’m already doing in the timeline app that I sent link to.


Something interesting I noticed just now… is that when I run the Test for the API… I get a different access_token than the one I get on my app when trying to do the axios.get function.

The one from the Test on the manage.auth0.com site looks like a proper jwt key.

The one from my app, when I getAccessTokenSilently() … I get one that has two points and - and _ in it. characters…[TWO POINTS]characters-characters-characters_characters-characters.characters_characters

I’ve noticed that if you request an access token without an audience, you get an opaque token. It’s still a valid access token, but it’s not a JWT. If you request an access token with an audience, you get an access token that’s a JWT.

2 Likes

That much I know.

The thing is… when I use this query from my App:

//Get Portfolios
async function getUserPortfolios(user_id) {

  if (!user_id) {
    console.log("The User is not logged in")
  }

  try {
    const token = await getAccessTokenSilently();
    console.log(token) // --> At this point the token I get is obfuscated.
    const res = await axios.get(`http://localhost:6060/portfolios?user_id=${user_id}`, {
    headers: {
      authorization: `Bearer ${token}`
    }

  })
  const userPortfolios = res.data; 
  // console.log(res);
  setUserPortfolios(Object.values(userPortfolios));
  } catch (error) {
    console.log(error.message)
  }
}
  
  useEffect(() => {
    getUserPortfolios(user_id);
    }, [isAuthenticated]);

So the real token never reaches the server in order for it to be authenticated.

I get one that has two points and - and _ in it.

Like this: " characters…[TWO POINTS]characters-characters-characters_characters-characters.characters_characters "

I figured it out with the help of a friend.

So… I was using ‘express-openid-connect’ on my server side and even though I was sending the audience through that middleware… it was giving me an opaque token with the wrong JWT format.

I changed it to

const { auth } = require(‘express-oauth2-jwt-bearer’);

and used validateAccessToken. That gave me the right JWT format and got it working.

Thanks though.

These links helped:

//

If anybody is gonna use axios on a project like this here’s a code chunk that might save you some time:

app.get('/route', validateAccessToken, async function (req, res) {
  console.log("called /route")
  const VARIABLE = req.query.VARIABLE
  try {
    const data = await pool.query(`SELECT * FROM table WHERE VARIABLE = $1;`, [VARIABLE])
      // console.log(data.rows)    
    res.json(data.rows)  
    // res.send(response)
    // res.send('Secured events Resource');
  } catch (error) {
    res.send(error.message)
  }
});
2 Likes

Wooohoooo thanks for sharing it with the rest of community! Teamwork makes the dreamwork!

1 Like

:muscle: I am glad to hear, Oscar! This answer will definitely help people in the same situation in the future. Thanks for sharing your solution.

1 Like

Hey, guys…

So… hahaha sorry to come back to this… but…

Since now I’m using

const { auth } = require('express-oauth2-jwt-bearer');

On my server side… Because of this, I can’t use requiresAuth() as middleware to get the auth0 id on the server side in order to be able to send user specific database queries.

With what I was doing before, using:

const { requiresAuth } = require('express-openid-connect');

I just needed to do this to get the auth0 id:

 app.get('/route', requiresAuth(), (req, res) => {
   res.send(JSON.stringify(req.oidc.user));
 });

But now… since don’t have openid-connect on const { auth } = ‘’ , I can’t do this. I can’t ask for the auth0 id on my server side.

Is there a way for me to ask for the auth0 id using ‘express-oauth2-jwt-bearer’ ?

Or is it possible to configure both express-oauth2-jwt-bearer and express-openid-connect at the same time?

1 Like

Nevermind…

I just found this document and found a way to get the auth0. Thanks.

app.get('/api/messages',
    (req, res, next) => {
      const auth = req.auth;
      auth.header; // The decoded JWT header.
      auth.payload;  // The decoded JWT payload.
      auth.token; // The raw JWT token.
    }
);

You just need to access what’s in the payload to get it:

app.get('/route',
    (req, res, next) => {
      const auth = req.auth;

      auth.payload.sub;  // Gives you the auth0 id on the server
     
    }
);
2 Likes

No worries! Thanks for sharing it with the rest of community!

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.