• Blog
  • Documentation
  • Courses
  • Changelog
  • AI Starters
  • UI Kit
  • FAQ
  • Supamode
    New
  • Pricing

Launch your next SaaS in record time with Makerkit, a React SaaS Boilerplate for Next.js and Supabase.

Makerkit is a product of Makerkit Pte Ltd (registered in the Republic of Singapore)Company Registration No: 202407149CFor support or inquiries, please contact us

About
  • FAQ
  • Contact
  • Verify your Discord
  • Consultation
  • Open Source
  • Become an Affiliate
Product
  • Documentation
  • Blog
  • Changelog
  • UI Blocks
  • Figma UI Kit
  • AI SaaS Starters
License
  • Activate License
  • Upgrade License
  • Invite Member
Legal
  • Terms of License
  • Auth Overview
  • Global Configuration
    • Setting up your Firebase Project
    • Setting up Firebase Functions
  • Writing data to Firestore
  • Commands
  • Introduction
  • Production Checklist
  • Introduction
  • Overview
  • Stripe Configuration
  • Running Tests
  • Introduction
  • Setting up Firebase Auth
  • Fetching data from Firestore
  • Technical Details
  • Extending Organizations
  • Stripe Webhooks
  • CI Tests
  • Initial Setup
  • React Hooks
  • Auth Flow
  • API requests
  • Code Style
  • Clone the repository
  • Security Rules
  • User Permissions
  • Limitations
  • Project Structure
  • Third-Party Providers
  • Reading data from Storage
  • Running the application
  • Subscription Permissions
  • One-Time Payments
  • Running the App
  • Email Link Authentication
  • Uploading data to Storage
  • Security Rules
  • Migrate to Lemon Squeezy
  • Project Configuration
  • Multi-Factor Authentication
  • Writing your own Fetch
  • Translations and Locales
  • Coding Conventions
  • Environment Variables
  • Architecture and Folder Structure
    • Structure your Application
    • Data Model
  • Requiring Email verification
  • Sending Emails
  • Tailwind CSS and Styling
  • Validating API payload with Zod
  • Authentication
  • Onboarding Flow
  • Logging
  • Development: adding custom features
  • Prevent abuse with AppCheck
  • Enable CORS
  • Encrypting Secrets
  • User Roles
  • Firestore: Data Fetching
  • Custom React Hooks
  • Custom React Hooks
  • Firestore: Data Writing
  • Troubleshooting
  • Forms
  • Application Pages
  • API Routes
  • API Routes Validation
  • Translations
  • Adding pages to the Marketing Site
  • Deploying to Production
  • Updating to the latest version
This kit is no longer maintained.

Subscription Permissions | Remix Firebase SaaS Kit

Learn how to gate access to certain features or pagess based on the organization's subscription

Makerkit provides some utilities to retrieve the current organization's subscription: you can use these utilities to allow or gate access to specific features, pages, or to perform certain actions.

  1. On the client side, we can use the hook useIsSubscriptionActive
  2. On the server-side, we can use the functions isOrganizationSubscriptionActive and getOrganizationSubscription

Client Side Gating

Let's assume we want to allow only users who belong to paying organizations to perform a certain action:

src/lib/organizations/permissions.ts
function isAdmin(
role: MembershipRole
) {
return role === MembershipRole.Admin;
}

Now, combine this function with other conditions:

src/lib/organizations/permissions.ts
export function useCreateNewThing(
userRole: MembershipRole,
) {
const isPayingUser = useIsSubscriptionActive();
return isPayingUser && isAdmin(userRole);
}

As you may know, I recommend adding all the permissions logic to the file permissions.ts (or similar files), and never inline it: this makes it easy to store logic in one single place rather than scattered across the application.

Inlining logic in our code will make it hard to track logic down and debugging it.

Once defined out logic functions in permissions.ts, we can then use these in our components to hide the sections that users do not have access to:

tsx
function Feature() {
const userRole = useCurrentUserRole();
const canCreateThing = useCreateNewThing(userRole);
if (!canCreateThing) {
return <div>Sorry, you do not have access to this feature. Subscribe?</div>
}
return <FeatureContainer />;
}

Firestore Rules

Another essential thing to take into account is securing our Firestore rules using the organization's subscription.

For example, let's assume your application requires organizations to be paying customers to write to a certain collection:

js
function getOrganizationSubscription() {
let organization = getOrganization(organizationId);
return organization.subscription;
}
function isPayingOrganization(subscription) {
return subscription != null && (subscription.status == 'paid' || subscription.status == 'trialing');
}
function isProPlan(subscription) {
let organization = getOrganization(organizationId);
return subscription.stripePriceId == 'pro-plan-id';
}
function canWriteToCollection(organizationId) {
let subscription = getOrganizationSubscription();
return isPayingOrganization(subscription) && isProPlan(subscription);
}
match /organizations/{organizationId} {
match /tasks/{task} {
allow create: canWriteToCollection(organizationId);
allow list: if userIsMemberByOrganizationId(organizationId);
}
}

Server Side Gating

When gating access on the server side, we can use two utilities that allow us to get the organization's subscription by its ID.

Using Firestore utilities

When you need to check the user's subscription in your API functions, you can use the functions isOrganizationSubscriptionActive and getOrganizationSubscription exported from src/lib/server/organizations/memberships.ts.

For example, let's assume we have an API handler that performs an action:

tsx
export default async function action({ request }) {
const organization = await parseOrganizationCookie(request);
const isSubscriptionActive =
await isOrganizationSubscriptionActive(organization);
if (!isSubscriptionActive) {
return throwForbiddenError();
}
// all good! perform action
}
On this page
  1. Client Side Gating
    1. Firestore Rules
  2. Server Side Gating
    1. Using Firestore utilities