The Good Tech Companies - DIY Real-Time Polling App Locks Down Access With Supabase and Permit.io
Episode Date: April 16, 2025This story was originally published on HackerNoon at: https://hackernoon.com/diy-real-time-polling-app-locks-down-access-with-supabase-and-permitio. Learn how to add Sup...abase authentication and authorization to a fullstack Next.js app with Supabase Edge Functions and a Policy Decision Point (PDP). Check more stories related to programming at: https://hackernoon.com/c/programming. You can also check exclusive content about #supabase, #edge-functions-on-supabase, #supabase-auth-tutorial, #permit.io-integration, #build-nextjs-polling-app, #nextjs-permit.io-setup, #auth-role-based-access, #good-company, and more. This story was written by: @permit. Learn more about this writer by checking @permit's about page, and for more stories, please visit hackernoon.com. A full-stack guide to building a secure, real-time polling app with authentication, per-user permissions, and dynamic policy checks—using Supabase + Permit.io.
Transcript
Discussion (0)
This audio is presented by Hacker Noon, where anyone can learn anything about any technology.
DIY real-time polling app locks down access with SuperBase and Permit.
EO by Permit, EO by Gabriel L. Maner SuperBase makes it easy to add authentication to your app
with built-in support for email, OAuth, and MagicLinks. But while SuperBase Auth handles
who your USERS are, you often need an authorization layer as well.
SuperBase offers a great backend with built-in auth and row-level security, RLS, managing fine-grained permissions,
especially ones based on relationships between users and data, as far from easy.
You may want to restrict actions like editing or deleting data to resource owners,
prevent users from voting on their own content, or enforce different permissions for different user roles. This tutorial walks through
how to implement SuperBase authentication and authorization in a next JS application.
We'll start with SuperBase Auth for login and session management, then add authorization rules
using relationship-based access control, Reback, Enforced through
SuperBase Edge functions and a local policy decision point, PDP. By the end,
you'll have a real-time collaborative polling app that supports both public
and protected actions and a flexible authorization system you can evolve as
your app grows. What we're building in this guide, we'll build a real-time
polling app using SuperBase and Next. JS that showcases both authentication and authorization in action.
The app allows users to create polls, vote on others, and manage only their own content.
It demonstrates how to implement SuperBase Auth for login, signup, and how to enforce
authorization policies that control who can vote, edit, or delete.
We'll use SuperBase's core features, Auth, Postgres, RLS, Real-time, and Edge functions,
combined with a relationship-based access control, Reback, modeled toneforce per user
and per resource access rules.
TechStack Supabase, back-end as a service for database, authentication, real-time, and
edge functions.
Next, JS, front-end framework for building the app UI and API roots.
Permit, I-O, for Reback, to define and evaluate authorization logic via PDP.
SuperBase CLI, to manage and deploy edge functions locally and in production.
Prerequisites node, JS installed, SuperBase account, account, permit, io account, familiarity with react, next
js, starter project repo, what can this app do?
the demo application is a real-time polling platform built with next
js and supabase, where users can create polls and vote on others
any user, authenticated or not, can view the list of public polls only authenticated users can create polls and vote on others. Any user, authenticated or not, can view the list of public polls.
Only authenticated users can create polls and vote. A user cannot vote on a poll they created.
Only the creator of a poll can edit or delete it.
Tutorial Overview
We'll follow these general steps 1. Set up SuperBase project, Schema, Auth, and RLS.
2. Build core app features like poll creation and voting.
3.
Model authorization rules define roles and rules in permit.
EO.
4.
Create superbase edge functions for syncing users, assigning roles, and checking permissions.
5.
Enforce policies in the app frontend using those edge functions.
Let's get started setting up superase in the project. Optional.
Clone the starter template
I've already created a starter
template on GitHub with all the
code you need to start so we can
focus on implementing SuperBase
and permit.
EO, you can clone the project
by running the following command
once you have cloned the project.
Navigate to the project directory
and install the dependencies
creating a new project in
SuperBase to get started. Go to https://superbase.com and sign in or create an
account. Click new project and fill in your project name, password, and region.
Once created, go to project settings right-pointing arrow API and note your
project URL in an on key. You'll need them later. Backslash dot. Setting up authentication and database in SuperBase will use
SuperBase's built-in email, password auth. In the sidebar, go to authentication
right-pointing arrow providers. Enable the email provider. Optional, disable email
confirmation for testing, but keep it enabled for production. Creating the
database schema this app uses three main tables, and
use the SQL editor in the SuperBase dashboard and run the following enabling row-level security,
RLS. Enable RLS for each table and define policies.
To use SuperBase's real-time features, in the sidebar, go to Table Editor.
For each of the three tables, click the three dots right-pointing arrow at a table.
Toggle, Enable real-time, Save changes.
Implementing SUPABASE email authentication in the app in this demo app.
Anyone can view the list of polls available on the app, both active and expired.
To view the details of a poll, manage, or vote on any poll, the user must be logged
in.
We will be using email and password as means of authentication for this project.
In your next JS project, store your SuperBase credentials in.
Update your login component to handle both sign up and login via email.
Password here.
We are using SuperBase's method to log in a user and the method to sign up a new user with their email and password.
We are also storing the user's name in the field in the user's metadata.
You can also use to log users out and redirect them here.
We are using the method from SuperBase to log out the user and redirect them to the homepage.
Listening for changes in the user's authentication state allows us to update the UI based on the user's authentication status. This allows you to show,
hide UI elements like login, logout buttons. Conditionally restrict access to protected pages,
like voting or managing polls. Ensure only authenticated users can perform restricted actions.
We'll use to listen to these events and update the app accordingly.
In the file, track global auth state, restrict access on protected pages on
pages like poll details or poll management.
You should also listen for authentication state changes to prevent
unauthenticated users from accessing them.
Here's how it looks in.
And a similar pattern applies in.
Where users should only see their own PulseF logged in these patterns ensure your UI reflects the user's current
authentication status and form the basis for the authorization checks we'll add later.
For example, you'll later use this object when calling the edge function to determine
whether a user is allowed to vote or manage a specific poll.
Building the polling app functionality with SuperBase configured and authentication working, we can now build the core functionality of the polling app functionality. With SuperBase configured and authentication working,
we can now build the core functionality of the polling app.
In this section, we'll cover creating new polls,
fetching and displaying polls in real-time, implementing a voting system.
This gives us the basic app behavior that we'll soon protect with fine-grained permissions.
Creating new polls users must be logged in to create polls.
Each poll includes a question, an expiration date, and a set of options.
We also record who created the poll so we can later use that relationship for access control.
Inside, fetch the authenticated user, and use SuperBase to insert the poll and its options we'll later call an edge function here to assign the creator role and permit. EO, fetching and displaying
polls polls are divided into active
not yet expired and passed
expired. You can fetch them
using superbase queries filtered by the
current timestamp and set up real time
subscriptions to reflect changes instantly.
Example from viewing
and managing user polls here, we are
fetching active and passed polls from the table
in superbase. We are also setting up a real time subscription managing user polls here, we are fetching active and past polls from the table in SuperBase.
We are also setting up a real-time subscription to listen for changes in the table so that we can update the UI with the latest poll data. To differentiate between active and past polls,
we are comparing the expiry date of each poll with the current date.
Update the page to fetch and display only polls created by the user here.
We only fetch polls created by the user and listen for real-time updates on the table
so that the UI is updated with the latest poll data.
Also, update the component so that if a logged-in user is the poll creator, icons for editing
and deleting the poll will be displayed to them on the poll.
So now, on a poll card, if the logged-in user is the poll creator, icons for editing and
deleting the poll will be displayed to them.
This allows the user to manage only their polls.
Implementing the poll voting system the voting logic enforces.
Only one vote per user per poll.
Creators cannot vote on their own polls.
Votes are stored in the table.
Results are displayed and updated in real time.
Let's break down how this works in the component.
Fetch the logged in user.
We need the current user's ID to determine voting eligibility and record their vote.
Load poll details and check voting status.
Once we have the user, we fetch the poll itself, including options and vote counts.
Whether this user has already voted.
We also call these again later in real time updates.
Listen for real time updates. We subscribe to changes again later in real-time updates. Listen for real-time
updates we subscribe to changes in the table, scoped to this poll. When a new vote is cast,
we fetch updated poll data and voting status. Handle the vote submission IF the user hasn't
voted and is allowed to vote, we'll add a permission check later. We insert their vote.
Display the poll results we calculate the total number of votes and a countdown to the expiration time.
You can then use this to display progress bars or stats.
With this setup in place, your voting system is fully functional.
But right now, anyone logged in could technically try to vote, even on their own poll.
Next, we'll add authorization checks using PERMIT.
I.O. and SuperBase Edge functions toneforce those rules.
Before we do that, let's first look at the type of authorization layer we are going to implement.
Understanding REBAC, Relationship-Based Access Control.
SuperBase handles authentication and basic row-level permissions well,
but it doesn't support complex rules like preventing users from voting on their own polls.
Assigning per-resource roles, like resource roles like creator for a specific poll,
managing access via external policies.
To support these kinds of relationship-based permissions,
we'll implement Rebac with Permit.
EO, Relationship-Based Access Control, Rebac,
is a model for managing permissions based on the relationships
between users and resources.
Instead of relying solely on roles or attributes, as in RBAC or ABAC,
Reback determines access by evaluating how a user is connected to the resource they're trying to access.
In this tutorial, we apply Reback to a polling app.
A user who created a poll is the only one who can manage, edit, delete it.
A user cannot vote on their own poll.
Other authenticated users can vote once per poll.
By modeling these relationships in Permit.io, we can define fine-grained access rules that
go beyond SuperBase's built-in row-level security, RLS.
We'll enforce them at runtime using Superbase edge functions and permits policy engine.
For more on Reback, Checkout Permit, IOS Reback Docs, Access Control Design, for our polling app, we will define,
1. Resource with Resource Specific Actions, Polls.
2. Roles for granting permission levels based on a user's relationship with the resources.
Authenticated. Can perform and actions in polls.
Can not, or actions in polls. Creator. Can perform and actions in polls. Can not or actions in polls. Creator. Can and actions in polls. Can perform and actions in votes. Cannot use on their own polls.
Setting up permit. EO. Let's walk through setting up the authorization model in permit.
Create a new project in permit. IO name it something something like Define the Resource go to the Policy right-pointing arrow Resources tab. Click Create Resource, name it and add the
actions. Enable Reback for the resource under Reback Options, define the
following roles. Click Save, navigate to the Roles tab to view the roles from the
resources we just created. Note that Permit created the default roles that
are unnecessary for this tutorial
Define access policies go to the policy right pointing arrow policies tab
Use the visual matrix to define can and polls can and polls optional
You can configure vote permissions as part of this or via a second resource if you model votes separately add
Resource instances go to directory right
pointing arrow instances. Add individual poll IDs as resource instances. You'll automate this later
when new polls are created. Assign roles to users per poll, E G is of. This structure gives us the
power to write flexible access rules and enforce them per user, per poll. Now that we have completed
the initial setup on the permit dashboard, let's use it in
our application.
Next, we'll connect permit.
IO to our SuperBase project via Edge functions that.
Sync new users.
Assign creator roles.
Check access on demand.
Setting up permit in the polling application permit offers multiple ways to integrate with
your application, but we'll use the container PDP for this tutorial.
You have to host the container online to access it in SuperBase Edge Functions.
You can use services like Railway, COM, once you have hosted it, save the URL for your
container.
Obtain your permit API key by clicking, Projects, in the permit dashboard sidebar navigating to the project you are working on
clicking the three dots and selecting copy API key creating super base edge function
apis for authorization super base edge functions are perfect for integrating third-party services
like permit eo we'll use them to enforce our reback rules at runtime by checking whether users are
allowed to perform specific actions on polls. Create functions in SuperBase initialize SuperBase in your project and create three
different functions using the command. These will be the starting point for your functions.
This will create a folder in the folder along with the endpoints. Now, let's write the codes for each
endpoint. Syncing users to permit, Io on sign up. This function listens for
supabase's auth event. When a new user signs up, Wessync their identity to permit.
Io and assign them the default role. Assigning the creator role. Once a user creates a poll,
this function is called to. Sync the poll as a new permit. Io resource instance. Assign the user
the role for that poll. Checking permissions,
this function acts as the gatekeeper. It checks whether a user is allowed top perform a given
action on a specific poll. Local testing start your SuperBase dev server to test the functions
locally. You can then hit your functions at, example, integrating authorization checks in
the UI. Now that we've created our authorisation logic with permit,
IO and exposed it via SuperBase Edge functions,
it's time to enforce those checks inside the app's components.
In this section, we'll update key UI components to call those functions
and conditionally allow or block user actions like voting or managing polls
based on permission checks.
Assign Creator role after poll creation.
After creating a poll and saving it to superbase,
we call the function to. Sync the new poll as a resource and permit. I.O. Assign the current user
the role for that specific poll, restrict voting based on permissions before allowing a user to
vote on a poll. We call the function to verify they have the permission on the resource.
This is how we enforce the rule. A creator cannot vote on their own poll.
Check voting permission, disable vote buttons
if user isn't allowed show a message
if the user is not allowed to vote.
Control access to edit, delete.
We also restrict poll management actions, edit and delete
by checking if the user has the permission on that poll.
Check management permissions
conditionally show management buttons.
Replace with testing the integration once integrated.
You should see the following behaviors in the app.
Logged out users can view polls but not interact.
Authenticated users can vote on polls they didn't create.
Creators cannot vote on their own polls.
Only creators see edit, delete options on their polls.
You should be able to see the applications changes by going to the
browser. On the home screen, users can view the list of active and past polls,
whether they are a logged in or not. However, when they click on a poll, they
will not be able to view the poll details or vote on it. Instead, they will
be prompted to log in. Once logged in, the user can view the details of the poll and vote on it.
However, if the user is the creator of the poll, they will not be able to vote on it.
They will see a message indicating that they cannot vote on their own poll.
They will also be allowed to manage any poll that they create.
Conclusion
In this tutorial, we explored how to implement SuperBase authentication and authorization in a real-world Next.
Js application, we started by setting up SuperBase Auth for login and signup,
created a relational schema with row-level security, and added dynamic authorization logic using Reback.
With the help of SuperBase Edge functions and a policy decision point, PDP,
we enforced permission checks directly from the front end.
By combining SuperBase Auth with flexible access control, we were able to
authenticate users via email and password, restrict voting and poll
management to authorized users, prevent creators from voting on their own polls,
assign and evaluate user roles based on relationships to data.
This setup gives you a scalable foundation for building apps that require both authentication and fine-grained authorization.
Further reading permit, I-O Reback Guide, Permit Plus Authentication Providers, Permit Elements, Embedded UI for Role Management, Data Filtering with Permit, Audit Logs, Got Questions?
Join our Slack community, where hundreds of developers are building and discussing authorization.
Thank you for listening to this Hacker Noon story, read by Artificial Intelligence.
Visit HackerNoon.com to read, write, learn and publish.