The Good Tech Companies - DIY Real-Time Polling App Locks Down Access With Supabase and Permit.io

Episode Date: April 16, 2025

This 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)
Starting point is 00:00:00 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,
Starting point is 00:00:43 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
Starting point is 00:01:21 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
Starting point is 00:02:01 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
Starting point is 00:02:41 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.
Starting point is 00:03:10 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
Starting point is 00:03:28 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
Starting point is 00:03:41 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
Starting point is 00:04:19 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.
Starting point is 00:04:55 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.
Starting point is 00:05:26 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
Starting point is 00:06:10 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
Starting point is 00:06:36 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.
Starting point is 00:07:08 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.
Starting point is 00:07:38 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
Starting point is 00:08:08 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.
Starting point is 00:08:36 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.
Starting point is 00:08:59 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.
Starting point is 00:09:30 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.
Starting point is 00:10:04 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,
Starting point is 00:10:31 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.
Starting point is 00:11:10 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
Starting point is 00:11:54 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
Starting point is 00:12:31 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.
Starting point is 00:12:57 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
Starting point is 00:13:31 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,
Starting point is 00:14:16 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.
Starting point is 00:14:51 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.
Starting point is 00:15:22 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
Starting point is 00:15:43 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
Starting point is 00:16:07 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
Starting point is 00:16:40 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,
Starting point is 00:17:20 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.

There aren't comments yet for this episode. Click on any sentence in the transcript to leave a comment.