Skip to main content

Client Login

The One Portal supports three login paths for client users: direct email/password login, Hub SSO (for PSA-provisioned users), and Portal SSO.


Direct Login

The default login method. A client user navigates to the portal URL, enters their email and password, and receives a session cookie.

Login URL: https://app.theoneportal.app/portal/login?tenant=YOUR_SLUG

Session behavior:

  • Session cookie name: portal_session
  • Expiry: 24 hours
  • Cookie is HttpOnly and Secure; set on the portal domain
  • Each login increments login_count and updates last_login_at

First-time login after invite:

  1. The MSP admin creates a client user account in Admin → Clients
  2. The client receives an invitation email with a tokenized link
  3. The link opens the portal's /portal/register?invite=TOKEN page
  4. The client sets their password and is immediately logged in

Hub SSO Login

Clients provisioned through PSA's portal-access feature can log in without a password using a signed JWT generated by Hub.

How it works:

  1. MSP enables "portal access" for a contact in The One PSA
  2. The client receives a login link containing a short-lived JWT (70-second expiry)
  3. The client clicks the link, which hits /api/auth/client-hub-sso?token=TOKEN
  4. The Portal API validates the JWT:
    • Verifies the signature using PORTAL_CLIENT_SSO_SECRET
    • Confirms context === 'client_portal'
    • Checks the JTI (JWT ID) against a replay-prevention store — each token can only be used once
  5. The API auto-provisions a client user record if one does not already exist, linking hub_user_id, psa_contact_id, and psa_company_id
  6. A Portal session cookie is set and the client is redirected to /portal/tickets

JWT claims carried through:

ClaimDescription
subHub user ID (becomes the Portal user ID)
emailUser email address
tenant_idMSP tenant ID
tenant_slugMSP tenant slug
client_idPSA company ID (maps to Portal client ID)
access_levelown / company / company_admin
psa_contact_idPSA contact record ID
psa_company_idPSA company record ID
⚠️

Hub SSO tokens expire after 70 seconds. If the client clicks the link after it has expired, they will see an "Invalid or expired SSO token" error. Have them request a new link from the MSP.


Access Levels

Client users have one of two roles, set during provisioning:

RolePermissions
userView own tickets, invoices, documents, announcements, team, profile
company_adminAll of the above, plus view all company tickets, manage team members

The access_level from PSA (own / company / company_admin) maps to the Portal role:

  • company_admincompany_admin role
  • own or companyuser role

Session Management

  • Duration: 24 hours from login
  • Logout: Click the logout icon in the top-right header. The session cookie is cleared.
  • Expired sessions: If the session cookie expires mid-session, the next API call returns 401 and the user is redirected to the login page.
  • Multiple sessions: Not limited — a user can have multiple active sessions on different browsers/devices.

Password Reset

  1. Navigate to the login page
  2. Click Forgot password?
  3. Enter your email address and submit
  4. Receive a reset email with a time-limited link
  5. Click the link → /portal/reset-password?token=TOKEN
  6. Enter and confirm your new password
  7. Log in with the new password
ℹ️

Password reset is only applicable for direct-login accounts. Hub SSO users do not have a portal password — they always authenticate through Hub.


Troubleshooting Login Issues

ErrorCauseResolution
"Invalid credentials"Wrong email or passwordReset password or contact MSP to verify account exists
"Invalid or expired SSO token"Hub SSO link clicked after 70-second windowRequest a new login link from the MSP
"Token already used"SSO link clicked twiceRequest a new login link — JTI replay prevention blocked the second attempt
"Client SSO not configured"Missing PORTAL_CLIENT_SSO_SECRET env varMSP admin must configure the env var on the Portal API function app
Login succeeds but portal is blankWrong tenant slug in URLVerify the URL includes ?tenant=YOUR_SLUG