Skip to main content

Authentication

Overview

ForgeX uses SuperTokens with Google OAuth for authentication. Users cannot self-register - all accounts must be invited by an admin.

Authentication Flow

1
Admin Invites User

Admin creates invitation via /api/admin/users/invite. User receives email with invitation link.

2
User Accepts Invitation

User clicks invitation link and signs in with Google OAuth.

3
Session Created

Backend validates Google token, updates user status to ACTIVE, and creates session.

4
Access Protected Resources

User makes API requests with session cookie (HTTP-only).

Google OAuth Login

Step 1: Initiate Login

GET /api/auth/authorisationurl?thirdPartyId=google

Response:

{
"urlWithQueryParams": "https://accounts.google.com/o/oauth2/v2/auth?..."
}

Step 2: Google Callback

After user authenticates with Google:

GET /api/auth/callback/google?code=AUTHORIZATION_CODE

Success Response:

  • Sets HTTP-only session cookies
  • Redirects to dashboard

Error Responses:

{
"error": "No account found. Contact admin for invitation."
}

Session Management

ForgeX uses SuperTokens for session management with HTTP-only cookies. This provides enterprise-grade security without the complexity of JWT token management.

How SuperTokens Sessions Work

When a user logs in via Google OAuth:

  1. Google validates the user's identity
  2. Backend verifies the user exists and is ACTIVE
  3. SuperTokens creates a new session with:
    • Access token (short-lived, ~1 hour)
    • Refresh token (long-lived, ~100 days)
    • Anti-CSRF token (for write operations)
  4. Cookies are set with these tokens (HTTP-only, secure)

The session contains:

{
userId: "user-uuid",
userDataInJWT: {
email: "user@example.com",
role: "ESTIMATOR",
name: "John Smith"
}
}

Session Cookies

Sessions are stored in HTTP-only cookies with the following configuration:

{
httpOnly: true, // Not accessible via JavaScript (XSS protection)
secure: true, // HTTPS only (production)
sameSite: 'lax', // CSRF protection
domain: '.precisionsiteservices.com' // All subdomains share auth
}

Cookies set by SuperTokens:

  • sAccessToken - Short-lived access token (~1 hour)
  • sRefreshToken - Long-lived refresh token (~100 days)
  • sFrontToken - Frontend metadata (user info, not sensitive)
  • sIdRefreshToken - Anti-CSRF token (for state changes)
note

No JWT in localStorage: SuperTokens uses HTTP-only cookies exclusively. This prevents XSS attacks - malicious JavaScript cannot steal session tokens.

Session Validation

All protected endpoints automatically validate session cookies. No manual token handling required.

# Session cookie automatically included
GET /api/bids
Cookie: sAccessToken=...; sRefreshToken=...

Logout

POST /api/auth/signout

Clears session cookies and invalidates session.

Invitation System

Admin Invites User

POST /api/admin/users/invite
Content-Type: application/json
Cookie: sAccessToken=...; sRefreshToken=...

{
"email": "user@example.com",
"name": "John Smith",
"role": "ESTIMATOR",
"services": [
{ "service": "BIDS", "role": null },
{ "service": "PROJECTS", "role": "PM" }
]
}
info

An invitation email is automatically sent via Gmail API. If delivery fails, the invitation URL is still returned for manual sharing.

Get Invitation Info

GET /api/auth/invitation/:token

Response:

{
"email": "user@example.com",
"name": "John Smith",
"role": "ESTIMATOR",
"services": ["BIDS", "PROJECTS"],
"invitedBy": {
"name": "Admin User",
"email": "admin@example.com"
},
"expiresAt": "2026-01-20T10:00:00.000Z",
"isExpired": false
}

Accept Invitation

POST /api/auth/accept-invitation
Content-Type: application/json

{
"token": "abc123...",
"googleToken": "google-oauth-token"
}

Response:

{
"user": {
"id": "uuid",
"email": "user@example.com",
"name": "John Smith",
"role": "ESTIMATOR"
}
}

Session cookies (sAccessToken, sRefreshToken) are set automatically in the response headers.

User Status States

StatusCan LoginDescription
PENDING_INVITATIONInvited but hasn't accepted
ACTIVECan log in normally
DISABLEDAccount disabled by admin

Environment Variables

Backend (Required)

SUPERTOKENS_CONNECTION_URI=https://supertokens.example.com
API_DOMAIN=https://api.precisionsiteservices.com
WEBSITE_DOMAIN=https://portal.precisionsiteservices.com
GOOGLE_CLIENT_ID=your-client-id
GOOGLE_CLIENT_SECRET=your-client-secret

Frontend (Required)

VITE_API_URL=https://api.precisionsiteservices.com
VITE_GOOGLE_CLIENT_ID=your-client-id

Security Features

🛡️

HTTP-Only Cookies

Session tokens not accessible via JavaScript (XSS protection)

🔒

Secure Cookies

HTTPS only in production

🛡️

SameSite Protection

Prevents CSRF attacks

✉️

Invitation-Based

No self-registration - admin must invite

Troubleshooting

Session expired error

Sessions expire after inactivity. User must log in again via Google OAuth.

Wrong Google account

User must sign in with the same Google account that received the invitation.

Invitation expired

Admin must resend invitation via /api/admin/users/:id/resend-invite.

No account found

User must receive invitation from admin before logging in.