SPA + API: getTokenSilently not producing a JWT

I have a React SPA and a Python Flask API stack going. On my Auth0 config, I have created an SPA application and a also an API application.

I am using the code in the React Quickstart tutorial as a template and am able to login to my React SPA. But when I execute getTokenSilently in order to pass the tokens to my Flask API, the tokens are not JWT-compliant and thus being rejected by Flask.

Reading these forums, I understand I need to pass in the audience and scope. Here are my questions:

  1. Are the audience and scope passed in the initial SPA authentication? I am using loginWithRedirect for my initial authentication. and have tried passing audiencce/scope in it but that is is failing. Do I need to modify the boilerplate code from Quickstart in order to enable loginWithRedirect to use audience/scope?

  2. Are the audience/scope passed in GetTokenSilently also in addition to the initial loginWithRedirect?

I have gone through all the articles but am simply unable to find an updated document that lays out this architecture that is relevant in the the auth0 SPA framework.

1 Like

Here is the code in my main react-auth0-spa.js file. This is the same code as the one in the React QuickStart

    // src/react-auth0-spa.js
    import React, { useState, useEffect, useContext } from "react";
    import createAuth0Client from "@auth0/auth0-spa-js";

    const DEFAULT_REDIRECT_CALLBACK = () =>
      window.history.replaceState({}, document.title, window.location.pathname);

    export const Auth0Context = React.createContext();
    export const useAuth0 = () => useContext(Auth0Context);
    export const Auth0Provider = ({
      children,
      onRedirectCallback = DEFAULT_REDIRECT_CALLBACK,
      ...initOptions
    }) => {
      const [isAuthenticated, setIsAuthenticated] = useState();
      const [user, setUser] = useState();
      const [auth0Client, setAuth0] = useState();
      const [loading, setLoading] = useState(true);
      const [popupOpen, setPopupOpen] = useState(false);

      useEffect(() => {
        const initAuth0 = async () => {
          const auth0FromHook = await createAuth0Client(initOptions);
          setAuth0(auth0FromHook);

          if (window.location.search.includes("code=") &&
              window.location.search.includes("state=")) {
            const { appState } = await auth0FromHook.handleRedirectCallback();
            onRedirectCallback(appState);
          }

          const isAuthenticated = await auth0FromHook.isAuthenticated();

          setIsAuthenticated(isAuthenticated);

          if (isAuthenticated) {
            const user = await auth0FromHook.getUser();
            setUser(user);
          }

          setLoading(false);
        };
        initAuth0();
        // eslint-disable-next-line
      }, []);

      const loginWithPopup = async (params = {}) => {
        setPopupOpen(true);
        try {
          await auth0Client.loginWithPopup(params);
        } catch (error) {
          console.error(error);
        } finally {
          setPopupOpen(false);
        }
        const user = await auth0Client.getUser();
        setUser(user);
        setIsAuthenticated(true);
      };

      const handleRedirectCallback = async () => {
        setLoading(true);
        await auth0Client.handleRedirectCallback();
        const user = await auth0Client.getUser();
        setLoading(false);
        setIsAuthenticated(true);
        setUser(user);
      };
      return (
        <Auth0Context.Provider
          value={{
            isAuthenticated,
            user,
            loading,
            popupOpen,
            loginWithPopup,
            handleRedirectCallback,
            getIdTokenClaims: (...p) => auth0Client.getIdTokenClaims(...p),
            loginWithRedirect: (...p) => auth0Client.loginWithRedirect(...p),
            getTokenSilently: (...p) => auth0Client.getTokenSilently(...p),
            getTokenWithPopup: (...p) => auth0Client.getTokenWithPopup(...p),
            logout: (...p) => auth0Client.logout(...p)
          }}
        >
          {children}
        </Auth0Context.Provider>
      );
    };

Here is my loginWithRedirect call:

                onClick={() => loginWithRedirect({
                    redirect_uri: 'http://localhost:3000/home'
                })}>

And finally here is my getTokenSilently call:

const {isAuthenticated, loginWithRedirect, logout} = useAuth0()


        let options = {
            audience: 'http://localhost/5000',
            scope: 'read:records',
            responseType: 'token id_token'
        }
        let token = await getTokenSilently(options)

I do have the same issue with auth0-spa-js: I do retrieve an access token, but its not a valid JWT (according to jwt.io).

Hm. So in my case, the problem was not setting explicitly the audience and matching scope for both getTokenSilently and createAuth0Client.

2 Likes

Thanks for sharing that with the rest of community!