Skip to content

Conversation

@ebma
Copy link
Member

@ebma ebma commented Oct 31, 2025

Closes #882.

This pull request introduces Supabase-based authentication to the API, including OTP (one-time password) flows, token verification, and user session management. It adds new authentication endpoints, middleware for extracting and verifying user identity from requests, and propagates the authenticated userId throughout the business logic and data models. Several routes now optionally or mandatorily require authentication, and the system is prepared for future endpoint protection. Additionally, the codebase is updated to store and utilize the userId in key models and service layers.

Supabase Authentication Integration

  • Added Supabase configuration variables to .env.example and included @supabase/supabase-js as a dependency in package.json. [1] [2]
  • Implemented SupabaseAuthService with methods for checking user existence, sending and verifying OTPs, verifying and refreshing tokens, and retrieving user profiles. [1] [2]
  • Created AuthController with endpoints for checking email registration, requesting OTP, verifying OTP, refreshing tokens, and verifying tokens. [1] [2]
  • Added /v1/auth routes for authentication endpoints and registered them in the main API router. [1] [2] [3]

Authentication Middleware and Route Protection

  • Added requireAuth and optionalAuth middleware to extract and verify user identity from Bearer tokens, attaching userId to the request.
  • Updated BRLA, Quote, and Ramp routes to use optionalAuth middleware, allowing endpoints to access userId if provided. [1] [2] [3] [4] [5] [6] [7]

User Identity Propagation

  • Modified controllers (brla.controller.ts, quote.controller.ts, ramp.controller.ts) to store userId from the request in database records and service calls. [1] [2] [3] [4] [5] [6]
  • Updated service and type definitions to support userId as part of the request context and data models. [1] [2]

These changes collectively enable secure, user-specific flows across the API, laying the groundwork for robust authentication and authorization using Supabase.

@netlify
Copy link

netlify bot commented Oct 31, 2025

Deploy Preview for vortexfi ready!

Name Link
🔨 Latest commit 2fbed83
🔍 Latest deploy log https://app.netlify.com/projects/vortexfi/deploys/694a613dbe8ec40008c9ae0f
😎 Deploy Preview https://deploy-preview-912--vortexfi.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@netlify
Copy link

netlify bot commented Oct 31, 2025

Deploy Preview for vortex-sandbox ready!

Name Link
🔨 Latest commit 2fbed83
🔍 Latest deploy log https://app.netlify.com/projects/vortex-sandbox/deploys/694a613d268a6a00085508ba
😎 Deploy Preview https://deploy-preview-912--vortex-sandbox.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@ebma ebma requested a review from Copilot December 15, 2025 10:27
@ebma ebma marked this pull request as ready for review December 15, 2025 10:27
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 67 out of 68 changed files in this pull request and generated 11 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@ebma
Copy link
Member Author

ebma commented Dec 15, 2025

@copilot open a new pull request to apply changes based on the comments in this thread

Copy link
Contributor

Copilot AI commented Dec 15, 2025

@ebma I've opened a new pull request, #969, to work on those changes. Once the pull request is ready, I'll request review from you.

@ebma ebma requested a review from a team December 16, 2025 08:06
});
}

await SupabaseAuthService.sendOTP(email);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this operation is stateless on the backend, right? Maybe we could add an entry to the users table, to mark the last OTP timestamp or any other metadata.

In case we loose the state in the UI or we want to keep track.

// Sync user to local database (upsert)
await User.upsert({
email: email,
id: result.user_id
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the upsert only for handling new users? I assume the userId should never change but I may be wrong.

Copy link
Contributor

@gianfra-t gianfra-t left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice and complete feature, thanks @ebma ! The only thing I would like to discuss is what you think about changing the token into the cookies and avoid storing it in the local storage.
I understand there is a tradeoff in terms of security between both methods.

}),
({ event, context }) => {
// Store tokens in localStorage for session persistence
AuthService.storeTokens({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also wanted to discuss the pros/cons of using localStorage vs cookies (httpOnly) for the tokens.

I believe our application already handles httpOnly cookiens for the SIWE login, so we have an example, which seems to be the preferred way for browser apps.

Do you see this solution better in terms of security, for our case?

if (!taxIdRecord) {
// Validate that user is authenticated since userId is required in the schema
if (!req.userId) {
res.status(httpStatus.UNAUTHORIZED).json({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use the required validator here? instead of the optional, and then throwing.

apiClient.interceptors.request.use(
config => {
// Add any common headers here
// Add Authorization header if user is authenticated
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you know, if the header refreshes after the user gets authenticated?
What I mean is, if the apiClient initially starts with an authenticated state, do the headers get added after the Auth state changes?

},
EnterOTP: {
on: {
CHANGE_EMAIL: {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do we want to allow changing the email at this stage? I assume Supabase already created the user.


if (error) {
// If error is "PGRST116" (no rows returned), user doesn't exist
if (error.code === "PGRST116") {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know if it's possible, but this code seems confusing for an empty query return. Is this what the sdk recommends?

@@ -0,0 +1,110 @@
import {DataTypes, Model, Optional} from "sequelize";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are we adding this new table?

type: DataTypes.UUID
});

await queryInterface.sequelize.query(`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we keep the userId relation for this one (and any that allows for null) empty instead of using the dummy? Or do you think there is a benefit of using the dummy user here?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Account creation on Vortex

3 participants