I have implemented the Auth0 React SDK along with the Authorization Code Flow with PKCE to obtain an access token in my React Single Page Application (SPA) for making API calls to my protected backend routes.
I chose the Authorization Code Flow with PKCE because SPAs are considered public apps, not confidential ones. Therefore, we cannot obtain an access token using the standard Authorization Code Flow.
When I use the loginWithRedirect() function, everything works smoothly after users are authenticated. However, after implementing the Authorization Code Flow with PKCE, which involves generating a link for user authentication and authorization with a code verifier and code challenge, users are redirected repeatedly to the redirect URL. Furthermore, the redirected links contain different values for the code query parameter each time.
Here is the link of the Authorization Code Flow with PKCE
Below is my code and the screenshot that demonstrates the problem.
Auth0Provider setup
import { Auth0Provider } from "@auth0/auth0-react";
import React from "react";
export const Auth0ProviderComponent = ({
children,
}: {
children: React.ReactNode;
}) => {
// const navigate = useNavigate();
const domain = import.meta.env.VITE_AUTH0_ISSUER_BASE_URL;
const clientId = import.meta.env.VITE_AUTH0_CLIENT_ID;
const redirectUri = import.meta.env.VITE_BASE_FRONTEND_URL;
if (!(domain && clientId && redirectUri)) {
return null;
}
return (
<Auth0Provider
domain={domain}
clientId={clientId}
authorizationParams={{
redirect_uri: redirectUri,
}}
>
{children}
</Auth0Provider>
);
};
main.tsx
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App.tsx";
import "./index.css";
import { Auth0ProviderComponent } from "./components/Auth0ProviderComponent.tsx";
ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<Auth0ProviderComponent>
<App />
</Auth0ProviderComponent>
</React.StrictMode>
);
App.tsx
import { useEffect, useState } from "react";
import "./App.css";
import { useAuth0 } from "@auth0/auth0-react";
import CryptoJS from "crypto-js";
function App() {
const { isAuthenticated, isLoading, user } = useAuth0();
function base64URLEncode(input: any) {
const words = CryptoJS.enc.Utf8.parse(input);
const base64 = CryptoJS.enc.Base64.stringify(words);
return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
}
function sha256(input: any) {
const words = CryptoJS.enc.Utf8.parse(input);
const hash = CryptoJS.SHA256(words);
return hash.toString(CryptoJS.enc.Base64);
}
useEffect(() => {
if (!isLoading && !isAuthenticated && !user) {
//Create verifier
const randomBytes = CryptoJS.lib.WordArray.random(32); // 32 bytes
const verifier = base64URLEncode(
randomBytes.toString(CryptoJS.enc.Base64)
);
// Use the previously generated verifier to create the challenge code
const challenge = base64URLEncode(sha256(verifier));
//Generate link to authenticate and authorize users
const config = {
response_type: "code",
client_id: import.meta.env.VITE_AUTH0_CLIENT_ID,
code_challenge: challenge,
code_challenge_method: "S256",
redirect_uri: import.meta.env.VITE_BASE_FRONTEND_URL,
audience: import.meta.env.VITE_AUTH0_CLIENT_AUDIENCE,
scope: "read:user-resources",
};
const generatedLink = `https://${
import.meta.env.VITE_AUTH0_ISSUER_BASE_URL
}/authorize?${new URLSearchParams(config).toString()}`;
//Use the link
window.location.href = generatedLink;
}
if (!isLoading && isAuthenticated && user) {
alert("successfully log in");
}
}, [isAuthenticated, isLoading, user]);
return (
<>
<h1>Home page</h1>
</>
);
}
export default App;
Infinite loop in which users are redirected to this redirect uri with different values of the code query.
When I log isAuthenticated and user states, they are always false and undefined respectively.
I am very grateful for your helps. It has been quite a long time that I have been stuck with this bug. Thanks a lot.