Firebase sign user up only after successful payment

Viewed 1859

I'm trying to implement the following flow:

  1. User enter website
  2. User clicks Subscribe now
  3. User gets redirected to Stripe Checkout (because it's easier)
  4. User successfully pays
  5. User now can sign in (or even better - is automatically signed in)
  6. User is charged every month automatically and so is updated database (to control access)

Long story short: give user an access only when he paid.

I'm using Firebase for that, but it seems like there are many roadblocks/headaches:

I looked all around the web about subscription model while using Firebase, but there are almost none.

My question is: anyone implemented subscription service with Stripe (any, doesn't have to be Checkout - flow is the same) and Firebase? Or should I go for my own server and use Firebase only for database?

I really don't find it as a good UX when user has to first sign up and then pay (too much friction).

2 Answers

Using cloud functions:

  1. create a stripe customer during checkout.
stripe.customers.create({ email: 'user_email' }) // grab customer id
  1. create firebase user document and save the stripe customer id into 'users' collection.

(use userRecord.uid id into doc() id)

  firebaseAdmin.auth().createUser({
      email: 'email',
      password: 'temporary_password',
      displayName: 'fullname'
    })
    .then((userRecord) => {
      return firebaseAdminSDK.firestore()
        .collection('users').doc(userRecord.uid)
        .set({ stripe_account: 'cus_HILXPWljT9fKRA' })
    })
  • send email to user
  • send email & password back to client.

On client-side:

  1. after receiving successful message from cloud function server, let user sign in automatically
firebase.auth().signInWithEmailAndPassword(data.email, data.password)
  1. when user logs in grab the stripe_account from users collection and fetch stripe subscription status and show it to user.

  2. ask user verify its email or change password. disable all editing until user verifies its email or changes its password.

I am thinking about the following setup using the firebase Stripe extension:

  1. User fills in e-mail address and clicks submit.

  2. signInAnonymously() is called and user e-mail adress is set with updateEmail().

  3. Then a checkout sessions is created with the uid attached:

    async stripeCheckout({ state }, payload) {
      const uid = state.authUser.uid
      const ref = await this.$fire.firestore
        .collection('users')
        .doc(uid)
        .collection('checkout_sessions')
        .add({
          price: payload.price,
          success_url: SUCCES_URL,
          cancel_url: CANCEL_URL,
        });
      // Wait for the CheckoutSession to get attached by the extension
      ref.onSnapshot((snap) => {
        const { error, url } = snap.data();
        if (error) {
          // Show an error to your customer and
          // inspect your Cloud Function logs in the Firebase console.
          alert(`An error occured: ${error.message}`);
        }
        if (url) {
          // We have a Stripe Checkout URL, let's redirect.
          window.location.assign(url);
        }
      })
    }
    
  4. CANCEL_URL can be any url

  5. SUCCESS_URL will be an url + query parameter with the e-mail

  6. Behind the SUCCESS_URL you'll call sendSignInLinkToEmail()

  7. In stripe you set a custom claim in your subscription, for example: stripeRole equals premium. This claim will be added to firebase auth for subscribed users only.

  8. Your frontend can use an auth guard or middleware to check for the custom claim

  9. If you use firestore to serve content to premium members, you should use security rules like: request.auth.token.stripeRole == "premium";

Related