Building a membership site with Auth0 and Stripe?

Here’s the goal:

  1. Use Auth0 for ID management
  2. Use Stripe to sell memberships to a website
  3. Use custom social logins to grant/remove access to premium areas with third-party services (namely Discord through role granting/removal)
  4. Somehow keep this all in sync

The kicker: the core website is a static site built on Jekyll. So there is no database or back-end code that can be used.

Tying Auth0 to Discord and team is fairly straightforward.

Setting up pages for the memberships in Stripe is fairly straightforward. I believe it’s not difficult to set up a webhook in Stripe that would update the metadata for a user in Auth0 as memberships are created/cancelled.

Two questions here:

  1. Is it possible with rules to keep roles updated in Discord?

  2. Is it possible to manage access to webpages on the static site based on the metadata from Auth0?

Hopefully, I’ve posed this correctly. If it’s unclear, please ask more questions. I’m still exploring this.

Hey @joebuhlig - welcome to the Auth0 Community!

  1. Rules can post to an external datasource, but bear in mind that the success of your authentication flow will be dependant on the response of the datasource. If for some reason the responses of the external datasource are delayed, or the external datasource does not emit a response back, the whole authentication flow would fail, unless you catch those specific errors, but then you could end up out of sync.
  2. It is feasible, but it all depends on how your application is set up. The ID Token can be enriched so that the /userinfo endpoint shows that information, and then you could leverage it in your application. Again, that would depend on how you set up the application, rather than Auth0.

Let me know if this helps!

2 Likes

Figured it was time for an update on this. I think I have most of the mechanics solved. I created a rule that appends the Stripe customer id in the metadata for the user. That is then used to append the user profile with a subscription status whenever a checkSession is run. So that effectively lets me use Auth0 to check the subscription status of a user on page load.

So far it’s looking really good. I have to finish the import of users with their customer ids from Stripe and wire up all the appropriate Stripe webhook endpoints and then I’m golden!

1 Like

Hey Joe,

Thanks for sharing updates as you go along - that’s great to hear! Looking forward to hearing if we were able to solve your requirements for the final solution, and maybe you can Show your Auth0!

@joebuhlig I know this is an older topic but I’m working on something similar. I got my rule setup for appending the stripe customer ID to the user metadata. I’m not sure the best place to put the logic for checking the stripe subscription status… is this in your rule to or do you have it in your web app code? It would be amazing if you could share a bit more about checking the stripe subscription and even share some sample code if you have it!

Thanks,
Ky

I’m appending the subscription data via Auth0 and then validating it on the client side. Here’s how I’m adding it to the user data:

var stripe_customer = stripe.customers.retrieve(user.app_metadata.stripe_customer_id, {expand: ['subscriptions']}).then(function(result){
      var subscriptions = [];
      for (var subscription in result.subscriptions.data) {
        subscriptions.push({"id" : result.subscriptions.data[0].plan.id, "active": result.subscriptions.data[0].plan.active}); 
      }
      context.idToken['https://analogjoe.com/subscriptions'] = subscriptions;
      if (context.request.geoip) {
        context.idToken['https://analogjoe.com/country'] = context.request.geoip.country_name;
        context.idToken['https://analogjoe.com/timezone'] = context.request.geoip.time_zone;
      }
      return callback(null, user, context);
    });

And then I’m checking it on the client side like so:

webAuth.checkSession({
    responseType: 'token',
    scope: "openid profile",
    redirectUri: 'https://' + window.location.hostname
  },
    function(err, result) {
      console.log(err);
      if (result) {
        console.log(result);
        webAuth.client.userInfo(result.accessToken, function(err, user) {
          if (user["https://analogjoe.com/subscriptions"]) {
            var accessGranted = false;
            var subscriptions = user["https://analogjoe.com/subscriptions"];
            subscriptions.forEach(function(subscription){
              if (subscription["active"]) {
                $('.protected-notice').hide();
                $('.protected').addClass('accessGranted');
                accessGranted = true;
                $('#login-button').hide();
                $('#user-avatar img').attr('src', user['picture']);
                $('#user-avatar').show();
              }
            });
            if (!accessGranted) {
              protectedContent();
            };
          } else {
            protectedContent();
          }
        });
      }
      else {
        protectedContent();
      }
    }
  );

The protectedContent() function is where I remove all the pieces that require payment.

Are there ways to subvert this and clean it all up? Certainly.

Do I see it as an issue worth the time to prevent? Nope. :wink:

If you want to see the site itself, you can find it here: https://analogjoe.com