Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/vruizz22/innova-backend-serverless/llms.txt

Use this file to discover all available pages before exploring further.

Innova uses Supabase Auth with asymmetric JWT tokens (ES256 or RS256) validated on every request against the Supabase JWKS endpoint. Every request to a protected endpoint must include a valid, unexpired JWT in the Authorization: Bearer <token> header. The only public surfaces are GET / and all /auth/* endpoints — every other route runs through SupabaseAuthGuard and, where applicable, RolesGuard.

Roles

Four roles are defined in roles.enum.ts. A user’s role is resolved from app_metadata.role (set by admin provisioning) or user_metadata.role (set by the frontend at signup), with student as the default fallback.
RoleValueDescription
STUDENT"student"Can submit attempts, view own mastery, access assigned guides and practice
TEACHER"teacher"Can manage guides, view class mastery and alerts, create assignments
PARENT"parent"Can view children’s mastery summaries via parent-link
ADMIN"admin"Can manage the error-tag catalog and platform configuration
Role values are lowercase strings in the JWT payload and in all API responses (e.g. "teacher", not "TEACHER"). Use the exact lowercase values when setting role in registration or seed scripts.

Register

POST /auth/register — Creates a new user and a corresponding role profile (Student, Teacher, or Parent record) in one transaction. If the email already exists the password and role are updated (upsert). Returns a full session with accessToken, refreshToken, and the user object.
email
string
required
Valid email address. Normalized to lowercase and trimmed on the server.
password
string
required
Minimum 8 characters. Stored as a salted scrypt hash — never in plaintext.
role
string
required
One of "student", "teacher", "parent", "admin". Determines which role profile is auto-created.
curl -X POST https://api.superprofes.app/auth/register \
  -H 'Content-Type: application/json' \
  -d '{"email":"teacher@school.cl","password":"secure123","role":"teacher"}'
accessToken
string
Short-lived JWT for authenticating API requests. Include as Authorization: Bearer <accessToken>.
refreshToken
string
Long-lived token used to obtain a new accessToken without re-entering credentials.
user.id
string
The Prisma User.id (UUID). Use this as the subject for user-management operations.
user.email
string
Normalized email of the registered user.
user.role
string
The role assigned at registration (e.g. "teacher").
user.profileId
string | null
The role-specific record ID (Student.id, Teacher.id, or Parent.id). Pass this to domain endpoints such as GET /mastery/:studentId.

Login

POST /auth/login — Authenticates an existing user with email and password. Returns the same session shape as /auth/register.
email
string
required
Registered email address.
password
string
required
Minimum 8 characters. Verified with timing-safe comparison against the stored scrypt hash.
curl -X POST https://api.superprofes.app/auth/login \
  -H 'Content-Type: application/json' \
  -d '{"email":"teacher@school.cl","password":"secure123"}'
{
  "statusCode": 200,
  "data": {
    "accessToken": "eyJhbG...",
    "refreshToken": "eyJhbG...",
    "user": {
      "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "email": "teacher@school.cl",
      "role": "teacher",
      "profileId": "f1e2d3c4-b5a6-7890-abcd-ef0987654321",
      "supabaseUid": null,
      "tokenVersion": 0
    }
  },
  "timestamp": "2024-01-15T10:30:00.000Z",
  "path": "/auth/login",
  "traceId": "abc-123-def-456"
}

Using the Token

Include the accessToken in the Authorization header of every authenticated request:
curl https://api.superprofes.app/mastery/f1e2d3c4-b5a6-7890-abcd-ef0987654321 \
  -H 'Authorization: Bearer eyJhbG...'
Access tokens are short-lived. When a request returns 401 Unauthorized, use POST /auth/refresh with your refreshToken to obtain a new accessToken without requiring the user to log in again.

Refresh Tokens

POST /auth/refresh — Exchanges a valid refreshToken for a new session. The refresh token is verified against the stored tokenVersion; if the user has revoked their sessions (e.g. via a password reset), old refresh tokens are rejected.
refreshToken
string
required
The refreshToken value returned by /auth/register or /auth/login.
curl -X POST https://api.superprofes.app/auth/refresh \
  -H 'Content-Type: application/json' \
  -d '{"refreshToken":"eyJhbG..."}'
{
  "statusCode": 200,
  "data": {
    "accessToken": "eyJhbG...",
    "refreshToken": "eyJhbG...",
    "user": {
      "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "email": "teacher@school.cl",
      "role": "teacher",
      "profileId": "f1e2d3c4-b5a6-7890-abcd-ef0987654321",
      "supabaseUid": null,
      "tokenVersion": 0
    }
  },
  "timestamp": "2024-01-15T10:30:00.000Z",
  "path": "/auth/refresh",
  "traceId": "abc-123-def-456"
}

Password Reset

Password reset is a two-step flow: first request a reset code, then confirm with that code and a new password.
1

Request a reset code

POST /auth/forgot-password — Sends a password reset email via Resend. The email contains a link to your app’s /auth/reset page, with a token query parameter encoding the reset code. The code expires in 15 minutes.
email
string
required
The registered email address of the account to reset.
curl -X POST https://api.superprofes.app/auth/forgot-password \
  -H 'Content-Type: application/json' \
  -d '{"email":"teacher@school.cl"}'
{
  "statusCode": 200,
  "data": {
    "message": "A password reset link has been sent to your email. Check your inbox and spam folder."
  },
  "timestamp": "2024-01-15T10:30:00.000Z",
  "path": "/auth/forgot-password",
  "traceId": "abc-123-def-456"
}
2

Confirm the reset

POST /auth/confirm-forgot-password — Verifies the reset code and sets the new password. On success, the user’s tokenVersion is incremented, invalidating all existing refresh tokens.
email
string
required
The same email address used in step 1.
code
string
required
The 6-digit reset code extracted from the email link’s token parameter.
newPassword
string
required
The new password. Minimum 8 characters.
curl -X POST https://api.superprofes.app/auth/confirm-forgot-password \
  -H 'Content-Type: application/json' \
  -d '{"email":"teacher@school.cl","code":"123456","newPassword":"NewSecure456!"}'
{
  "statusCode": 200,
  "data": {
    "message": "Password updated successfully"
  },
  "timestamp": "2024-01-15T10:30:00.000Z",
  "path": "/auth/confirm-forgot-password",
  "traceId": "abc-123-def-456"
}

Current User

GET /auth/me — Returns the authenticated user’s profile, including their role-specific profileId. Requires a valid JWT in the Authorization header.
curl https://api.superprofes.app/auth/me \
  -H 'Authorization: Bearer eyJhbG...'
{
  "statusCode": 200,
  "data": {
    "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "email": "teacher@school.cl",
    "name": "teacher",
    "role": "teacher",
    "profileId": "f1e2d3c4-b5a6-7890-abcd-ef0987654321"
  },
  "timestamp": "2024-01-15T10:30:00.000Z",
  "path": "/auth/me",
  "traceId": "abc-123-def-456"
}
id
string
The Prisma User.id (UUID). This is the identity anchor for all user-management operations.
email
string
The user’s email address.
name
string
Display name from user_metadata.full_name (or name, or display_name). Falls back to the email local-part if no name metadata is present.
role
string
The user’s resolved role string.
profileId
string | null
The role-specific record ID. Use this value for domain endpoints that accept a student, teacher, or parent ID.

Logout

POST /auth/logout — Revokes the current session on the server side. Requires a valid JWT. After logout, the token remains cryptographically valid until its exp claim, so clients should also discard stored tokens immediately.
curl -X POST https://api.superprofes.app/auth/logout \
  -H 'Authorization: Bearer eyJhbG...'
{
  "statusCode": 200,
  "data": {
    "message": "Session revoked successfully"
  },
  "timestamp": "2024-01-15T10:30:00.000Z",
  "path": "/auth/logout",
  "traceId": "abc-123-def-456"
}

JWT Validation Details

For developers building integrations or debugging token issues:
  • Algorithm: Supabase signs JWTs with either ES256 (EC P-256, new projects) or RS256 (RSA, older projects). The backend accepts both via passport-jwt + jwks-rsa, so key rotation and algorithm changes are transparent.
  • Audience: Tokens must have aud: "authenticated".
  • Issuer: Tokens must be issued by https://<your-project>.supabase.co/auth/v1.
  • JWKS endpoint: Public keys are fetched (with caching and rate limiting) from https://<your-project>.supabase.co/auth/v1/.well-known/jwks.json.
  • Role claims: The role is read from app_metadata.role first (admin-provisioned), then falls back to user_metadata.role (set at signup), then defaults to "student".
  • User linking: On each validated request, UserLinkerService.ensureUser() creates or updates the corresponding User row in Postgres, keeping Supabase Auth and the application database in sync automatically.
// Role resolution order in SupabaseJwtStrategy.validate()
const role = toRole(
  payload.app_metadata?.role,      // 1st: admin-provisioned role
  typeof roleMeta === 'string'
    ? roleMeta                     // 2nd: user self-reported role at signup
    : undefined,
);
// Falls back to Role.STUDENT if neither is set
The SUPABASE_SERVICE_ROLE_KEY bypasses Supabase Row Level Security (RLS) entirely. It is used only server-side for admin provisioning and seeding. Never expose it to clients, embed it in frontend code, or include it in API responses.
Routes decorated with @Public() — currently GET /, POST /auth/register, POST /auth/login, POST /auth/refresh, POST /auth/forgot-password, and POST /auth/confirm-forgot-password — skip JWT validation completely. The SupabaseAuthGuard checks for this decorator before invoking Passport, so unauthenticated clients can reach these endpoints without a token.

Build docs developers (and LLMs) love