Skip to main content
Every deployed Vybe app is protected by authentication. There are no public URLs — users must be authenticated members of your organization with appropriate access rights before they can reach your app. This page explains how the authentication flow works and how you can use the current user’s identity in your app code.

The authentication flow

When someone visits a deployed app, Vybe handles authentication automatically:
1

User visits the app URL

The user navigates to your deployed app at <app-slug>-<org-slug>.vybe.build.
2

Vybe checks authentication

The Vybe middleware checks whether the user has an active session (a valid authentication cookie).
3

Redirect to login (if needed)

If the user is not authenticated, they are redirected to the Vybe login page. After signing in, they are sent back to the original app URL.
4

Access check

Once authenticated, Vybe verifies that the user has access to this specific app based on the app’s access level and any user-level grants.
5

Token injection

If the user passes the access check, Vybe mints a short-lived Vybe User Token (VUT) and injects it — along with user identity headers — into the request before forwarding it to your app.
6

App receives the request

Your app receives the request with the user’s identity context available in the request headers.

Identifying the current user

When a request reaches your app, the current user’s email is available in the request headers. You can use this to personalize the app experience, filter data, or implement user-specific logic.

In an API route

// app/api/my-tasks/route.ts
import { sql } from '@/lib/db';

export async function GET(request: Request) {
  const userEmail = request.headers.get('x-vybe-user-email');

  const tasks = await sql`
    SELECT * FROM tasks WHERE assignee_email = ${userEmail}
  `;

  return Response.json(tasks);
}

In a server component

// app/dashboard/page.tsx
import { headers } from 'next/headers';
import { sql } from '@/lib/db';

export default async function DashboardPage() {
  const headersList = await headers();
  const userEmail = headersList.get('x-vybe-user-email');

  const myProjects = await sql`
    SELECT * FROM projects WHERE owner_email = ${userEmail}
  `;

  return (
    <div>
      <h1>My Projects</h1>
      {myProjects.map((project) => (
        <div key={project.id}>{project.name}</div>
      ))}
    </div>
  );
}
You do not need to build your own login page or session management. Vybe handles all of that for you. Just read the user identity from the request headers.

Two-factor request authentication

When your app makes API calls to Vybe services (for example, to access integration data or run data queries), the request is authenticated with two credentials:
CredentialPurposeHow it is provided
VYBE_SERVER_SECRETIdentifies the appInjected as an environment variable at deployment
x-vybe-user-token (VUT)Identifies the userInjected as a request header by the Vybe middleware
  • App-level resources (like shared integration connections) require only the server secret.
  • User-level resources (like a user’s personal integration account) require both the server secret and the VUT.
This two-factor approach ensures that API calls are both app-authorized and user-authorized.

How this differs from traditional auth

In a traditional web app, you would build a login page, manage sessions, store user credentials, and handle password resets. In Vybe, all of this is handled by the platform:
ConcernTraditional AppVybe App
Login pageYou build itVybe provides it
Session managementYou implement itVybe handles it
User identityYou query your databaseYou read request headers
Access controlYou implement middlewareVybe enforces it before your app receives the request
Token managementYou generate and validate tokensVybe mints and validates the VUT automatically
Apps cannot be accessed publicly. All users must be authenticated members of your organization with appropriate access rights. There is no way to make a Vybe app publicly accessible.

Common patterns

Personal dashboard

Build an app where each user sees only their own data:
export async function GET(request: Request) {
  const userEmail = request.headers.get('x-vybe-user-email');

  const myMetrics = await sql`
    SELECT * FROM metrics WHERE user_email = ${userEmail}
  `;

  return Response.json(myMetrics);
}

Role-based content

Combine user identity with your own role data to show different content:
export async function GET(request: Request) {
  const userEmail = request.headers.get('x-vybe-user-email');

  const user = await sql`
    SELECT role FROM app_users WHERE email = ${userEmail}
  `;

  if (user[0]?.role === 'manager') {
    const teamData = await sql`SELECT * FROM team_metrics`;
    return Response.json(teamData);
  }

  const personalData = await sql`
    SELECT * FROM metrics WHERE user_email = ${userEmail}
  `;
  return Response.json(personalData);
}

What is next