Understanding JWT, sessions, etc

Hi all,
Another noob question from me, appreciate all the help I’ve gotten here so far. I’m working on a Redwood web app that has a custom python backend API for a lot of things I need to compute, itegration with other 3rd party services, etc. I’m still using the built-in Prisma/GraphQL stuff for regular DB lookups on the frontend, of course. And I’m using the Clerk integration for user auth.

I’m simply trying to pass along whatever session info I need to the backend so that I can work with the data of a particular user in a secure way. I’m seeing what looks like conflicting info online about what session info is included by default when making calls to my service. I thought I might get JWT stuff “for free” when making calls to my API, but I don’t see any relevant headers coming through when I log stuff in my server.

On the server side (in Flask) I do this in my development environment:

  from flask_cors import CORS
  cors = CORS(app, supports_credentials=True,
              # origins="http://localhost:8910"
              resources={r"/*": {"origins": "http://localhost:8910"}})

And on the client I’m making a fetch call like this:

    const backendUrl = 'http://0.0.0.0:5000/"

    const response = await fetch(backendUrl + 'api/user_lookup', {
      method: 'POST',
      credentials: 'include',
      // headers: {
      //  Authorization: `Bearer ${auth_token}`,
      //},
    })

I thought credentials: 'include' would do something for me, but I don’t see anything come through. I can pass in an auth_token by hand (that I look up via help from useAuth) as commented-out above, but I don’t think that should be necessary.

I’m sure I’m doing some basic thing wrong or else my mental model is fouled up. Can someone suggest the basic workflow that’s supposed to be used to simply make an API call to my own server and pass along authentication/session data so that I can verify the session/user associated with the call?

(Also to add a little more context: the specific thing I’m trying to do is to implement an API call that lets me perform Plaid integration for the logged-in user. Plaid has a great tutorial for doing all the work necessary to get a Plaid token I can store in my DB that is associated with the user’s Plaid accounts… but in their tutorial they store the retrieved Plaid token in a global variable and that’s it. I want to write the Plaid token to my DB in a row with the user’s ID, for future reference. But to do this safely I need to verify inside my flask API call that I have a valid user session with my Clerk user, and call a Clerk API to validate my session token, etc etc)

It depends on what auth provider you’re using. If you’re using the vanilla dbAuth provider (which uses a database table to store auth data), there’s no JWT token in play - it just uses a cookie to hold the session key. Other auth providers handle the token in vendor-specific ways.

Thanks — I’m using the Clerk auth provider that is part of Redwood. I think it uses a JWT token but maybe I misunderstood?

If there is a JWT token does it get passed along automatically when I call “fetch” or do I always have to build these headers myself somehow?

Clerk sets their JWT token as the value of the Authorization header. I haven’t looked at the code of the Redwood Clerk plugin, but the docs mention that it is a wrapper around Clerk React (Clerk’s SDK and client-side library). If you decode the base64url key assigned to your Authorization headers, you should at least see an id key (which Clerk builds all of their JWT tokens with by default.

Are you seeing the Authorization header in your browser inspector for all network calls from the web client? It should be being added by the Redwood-provided auth functions.

Are you wanting to make the Plaid call from the backend? The general auth docs might help, and also the docs on writing a custom provider since there’s some detail in there about how to set whether the user is authenticated.

Thanks – checking out the network calls in the inspector was helpful. Indeed, I was getting the JWT keys for free in internal frontend-side calls, but my “fetch” call to my python backend had no headers, etc. I ended up just grabbing the JWT auth token and passing it along explicitly in fetch. (I thought there was more “magic” that would do that for me, but I guess that’s not the case).

I was also having a somewhat misleading CORS error that was coming back and confusing matters, but I sorted all that out by managing headers and such myself.

Glad you got it working. I’d probably use axios, so I could just set the Auth header once in a central place and create an instance:

const axiosInstance = axios.create({
  headers: {
    Authorization : `Bearer ${your_token}`
  }
})

Sounds like maybe you were in no-cors fetch mode, which is the default mode for fetch(). In that mode the method has to be HEAD, GET or POST, and the headers can only be simple headers (Accept, Accept-Language, Content-Language, and Content-Type). You probably need cors mode to fetch from a third-party URL.

What was the syntax to retrieve the JWT token server-side? I know how to do it client-side, but didn’t find it readily for the backend.

Oh wow – I didn’t know fetch() had a no-cors mode. I’ll look into that, maybe that is the issue. But I like the idea of just using axios instead.

As far as the JWT token goes: I just set the Authorization header with the “Bearer ” and then grabbed it myself from the header like this, using flask’s “request” in python:

from flask import request
...
auth_token = request.headers.get('authorization').replace('Bearer ', '')

Thanks!

1 Like