Calling the Continue Action Post-Paywall

My Auth0 App utilizes a paywall to make first time users that login to be sent to a stripe paywall
I set up a customer id for them and redirect them to a checkout page that when a button is clicked, it redirects them to a stripe paywall - > all using an auth0 action

but when trying to call the /continue route to continue the authentication, I get redirected to a generic error page
I send along a redirect state to the checkout page that is used in the /continue parameters and save it under session token (I have also saved it under state and it makes no difference)
the checkout page makes a stripe paywall that redirects to a success URL of localhost:3000/continue… with the state/session token
I have confirmed that I am sending back the same exact session_token or state too that I put as the original state

but I get redirected to the error page like I said before and the auth doesn’t continue
I simply want to make this run for first time users logging in and just log the users in after they have paid
the app works fine without the paywall action
the auth0 continue action doesn’t even get called and at least log an error in the local app server
no logs even in the auth0 log

here’s the code:


exports.onExecutePostLogin = async (event, api) => {
  try {
    // Your existing logic for creating a Stripe customer

    const sessionToken = api.redirect.encodeToken({
      secret: event.secrets.REDIRECT_STATE,
      payload: {
        customerId: event.user.app_metadata.stripe_customer_id,

    // Redirect the user to the Stripe checkout page with session_token query parameter
    api.redirect.sendUserTo('http://localhost:3000/checkout', { 
        session_token: sessionToken, 
        redirect_uri: `http://localhost:3000/continue`,


  } catch (error) {

      "We could not create your account, problem with stripe redirection.\n" +
        "Please contact support for assistance."

exports.onContinuePostLogin = async (event, api) => {
  try {
    //api.redirect.sendUserTo('http://localhost:3000'); // Replace with your desired page URL

    // Access the session_token query parameter from the URL
    const stateToken = event.query.session_token;
    console.log('continuing flow')
    // Validate the token using the provided options
    let decodedToken = api.redirect.validateToken({
      secret: event.secrets.REDIRECT_STATE,
      tokenParameterName: 'session_token', // Ensure this matches the parameter name
    // Check if the payload is valid
    if (decodedToken) {
      // Log the payload for debugging
      console.log('Valid payload:', decodedToken);

      // Log in the user using Auth0 action
      await api.auth.loginWithCredentials({
      // Redirect the user to the desired page after successful login
    } else {
      console.error('Invalid session token');
        "We could not log you in due to an invalid session token.\n" +
        "Please contact support for assistance."
  } catch (error) {

      "We could not log you in, problem with coming back to app from Stripe.\n" +
        "Please contact support for assistance."


import React from 'react';
import { useAuth0 } from '@auth0/auth0-react';
import Stripe from 'stripe';
import queryString from 'query-string';
import jwt, { JwtPayload } from 'jsonwebtoken'; // Import the JWT library

const stripe = new Stripe('rk_test_51NOmOvHwLkK28gsPFWpd2flfcAWf9f2yvMTpB7D3m2s0rAFc21CIEPwtRS9Uz0NqfieZ5MY7xcAYgCuNCIzbzrYE004d5XPiyV', {
  apiVersion: '2022-11-15',

const Checkout = () => {
  const { user } = useAuth0();
  //const [customerId, setCustomerId] = useState(null);

  //const customerId = user?.app_metadata?.stripe_customer_id;
  const priceId = '***********************' //blurred out
  const successUrl = 'http://localhost:3000/authorize'
  const cancelUrl = 'http://localhost:3000/about'

  async function createCheckoutSession() {
    // Parse the URL to get state and redirect_uri
    const parsedUrl = queryString.parse(;
    const sessionToken = parsedUrl.session_token;
    const customerId = parsedUrl.customerId;
    const redirectUri = parsedUrl.redirect_uri;
    // Check if the state and redirectUri exist
    if (sessionToken && redirectUri) {
      // Create the checkout session with state in the success_url
      const session = await stripe.checkout.sessions.create({
        customer: user?.app_metadata?.stripe_customer_id,
        payment_method_types: ['card'],
        line_items: [{ price: priceId, quantity: 1 }],
        mode: 'subscription',
        success_url: `${redirectUri}?session_token=${sessionToken}`,
        cancel_url: cancelUrl,

      if (session.url) {
        window.location.href = session.url; // Redirect to Stripe checkout page

  return (

      {/* Render your component's content */}
      <button onClick={createCheckoutSession}>Checkout for our ECOmium Plan!</button>

export default Checkout;

Hi @secomm,

I think there is some confusion here about how and where Actions function. An Action is basically a serverless function, running in a cloud instance somewhere, not on your machine.

When you call api.redirect.sendUserTo('http://localhost:3000/checkout' in an Action, you are referencing the cloud server’s localhost, not the localhost on your machine.

You need to set up a publicly accessible domain for the Action to point to.

so if i do this but replace all the URLs with my production domain and run the paywall redirect action, it will be able to call the continue action?

thank you so much @dan.woda , it finally makes sense why the action itself just couldn’t be called from the localhost

1 Like

Exactly, that should work.

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