Can you access user app_metadata from the front end with next.js?

I created a support ticket with Auth0 about this but figured it would be a good idea to see if someone here has also tried to do something similar.

I am building a subscription Web App with Next.js and stripe. I am trying to limit user access to my application based on if the user has an active subscription or not. My web app requires all users to register before they can access any content and once they register and log in I have some auth0 actions which create a stripe customer id for them and check stripe to see if they have an active subscription. If they do have an active subscription the action will add 'subscription_status': 'active' or 'subscription_status': 'not-active' to the users app_metadata if they do not have an active subscription.

What I would like to do is within my application, access this app_metadata so that I can use state to show/hide a <p> tag that shows 'You have an active subscription' if the users app_metadata has 'subscription_status': 'active' and 'You do not have an active subscription' if the users app_metadata has 'subscription_status': 'not-active'

Is there a way I can just access this data from the front end like I can with the useUser() hook and just do a console.log(user.app_metadata)?

for reference this is what I would like to do in my code:

import { useEffect, useState } from "react";
import {useUser, } from "@auth0/nextjs-auth0";


export default function Subscriber() {
  // use state to determine if the user is a subscriber
  // initially the user will be considered a non subscriber by default
  const [subscription, setSubscription] = useState(false);

  // get the user infor from auth0
  const { user } = useUser();

  useEffect(() => {
    // get the subscription status from the user app metadata from auth0 and set the state accordingly
    if (user.app_metadata.subscription_status === 'active') {
      setSubscription(true);
    } else {
      setSubscription(false);
    }
  }, []);


  return (
    <>
      <div>
        <p>
          {/*if the user is a subscriber then show is a subscriber else show is not a subscriber*/}
          {subscription ? 'is a subscriber' : 'is not a subscriber'}
        </p>
      </div>
    </>
  );
}

is what I am trying to do even possible? If so I would love some guidance on how to achieve the desired result.

Edit: I wonder if having a user store in Airtable with the subscription_status as a field would actually be better suited for this. Then I could just call airtable right from the application and get what I need.

I found out how to do this and will be posting the solution because this was an absolute nightmare for me to accomplish and hopefully this saves someone else some time.

:star::star::star:
Solution:
:star::star::star:

If you have data that you would like to store in the user_metadata or app meta_data which you would like to access inside of your application do this:

  1. Go to your Auth0 user dashboard > Actions > Library > Build Custom
  2. Reformat this template to your needs. I was utilizing stripe but you can put literally anything in here
exports.onExecutePostLogin = async (event, api) => {
  // initialize stripe
  const stripe = require('stripe')(event.secrets.STRIPE_SECRET_KEY)

  // determine if the customer / Auth0 user has an active subscription
  const subscription_status = await stripe.subscriptions.list({customer: event.user.app_metadata.stripe_customer_id})

  // if the user does not have active subscription set the metadata attribute subscription_status = false
  // if the user has an active subscription set the metadata attribute subscription_status = true
  if (subscription_status.data.length === 0){
    api.user.setAppMetadata('subscription_status', false)
  } else {
    api.user.setAppMetadata('subscription_status', true)
  }

  // here I also added in the subscription status to the user metadata in stripe to have easier access to it
  await stripe.customers.update(
    event.user.app_metadata.stripe_customer_id,
    {metadata: {subscription_status: event.user.app_metadata.subscription_status}}

  )
};
  1. Save and Deploy the action.
  2. In the menu go to Actions > Flows > Login: and add in the action you just created to your flow and click on Apply

After this you will have the data populated correctly every time a user logs in to your application. In my case the users subscription status is checked on every log in and adjusted accordingly as needed.

Okay cool! now you have the data populated correctly but HOW do we access this data? (Something which was not clear to me at all during this process).

I am building a Next.js app so within one of my components I just wanted to render some text based on if a user was a subscriber or not here is an example component just in case it helps anyone

export default function Example(){

    return (
      <>
        <div>
         // render 'You are a subscriber' if the user is a subscriber else render 'You are not a subscriber'
           {isSubscriber ? 'You are a Subscriber' : 'You are not a Subscriber'}
        </div>
      </>
)
}

BUT, lets get back to the matter at hand… ACCESSING EITHER THE APP_METADATA OR THE USER_METADATA.

The next thing you will have to do is get a MANAGEMENT API ACCESS TOKEN you can do this by going to the Auth0 dashboard > Applications > APIs > Auth0 Management API > API Explorer

(if you have not set up the Auth0 Management API you will have to do that before proceeding. Here is a link on how to do just that.

We will need the token which is shown here but first lets set up our component so that we can utilize this token

Let’s add in a useEffect hook in order to call the API end point and add in some state variables in order to keep track of if the user is a subscriber or not so that we can render our text on the page.

NOTE: This is the final component / answer / whatever you want to call it on how to access the information from your application! COPY IT, SAVE IT, BOOKMARK IT JUST DON’T LOSE IT :joy:

import React, {useEffect, useState} from "react";

export default function Example(){
    const [isSubscriber, setIsSubscriber] = useState(false)

    useEffect( () => {

        const axios = require("axios").default;

        const options = {
            method: 'GET',
            url: 'https://YOUR-TENANT-DOMAIN/api/v2/users',
            params: {q: 'email:"some-example@email.com"', search_engine: 'v3'},
            headers: {authorization: 'Bearer THIS WILL BE THE TOKEN YOU GOT FROM THE ABOVE STEP'}
        };
       // in my case I needed the app_metadata which held the users subscription status. But you can access anything you need similar to this
        axios.request(options).then(function (response) {
            if(response.data[0]['app_metadata']['subscription_status'] === true){
                setIsSubscriber(true);
            }
        }).catch(function (error) {
            console.error(error);
        });
}, [] )

    return (
        <>
            <div>
                // this will render the first line of text if the user is a subscriber and the second line of text if they are not a subscriber
                {isSubscriber ? 'You are a Subscriber' : 'You are not a Subscriber'}
            </div>
        </>

)

}

And that’s it. You’ve successfully retrieved your stored user_metadata / app_metadata and updated state variable with it. I really hope this helped someone avoid the nightmare which I had to go through in order to obtain the data from the user_metadata / app_metadata.

Now go build something amazing!.. or finish building something amazing! :joy:

CHEERS :beers:

4 Likes

Hey there @thekoala, bravo! :clap: :clap: Thanks a bunch for sharing this with the community :slight_smile:

I’ll add some color to this by sharing the following doc which outlines how metadata works in user profiles:

In addition to the Management API, you can also access user metadata via the /user
info
endpoint (need the user’s access token), as well as via custom claims in the user id and/or access token. For example, here’s an action that will add both user_metadata and app_metadata to the user’s id token which can be extracted by your app post login:

exports.onExecutePostLogin = async (event, api) => {
  const namespace = 'https://my-app.example.com';
  if (event.authorization) {
    api.idToken.setCustomClaim(`${namespace}/user_metadata`, event.user.user_metadata);
    api.idToken.setCustomClaim(`${namespace}/app_metadata`, event.client.metadata);
  }
};

Thanks again for your engagement with this, I’m sure it will be beneficial to other users :metal:

Cheers!

4 Likes

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