Palamond Docs
Building Patient-Facing Apps

Authentication

Sign patients in, keep sessions fresh, and register new patients.

Patient-facing apps authenticate a real person and then act as them. The client manages the OAuth session: it stores tokens, attaches them to every request, and refreshes them when they expire.

Email and password sign-in

Request an offline scope so you receive a refresh token and the session survives page reloads.

import { palamond } from './client';

async function signIn(email: string, password: string): Promise<void> {
  const login = await palamond.startLogin({ email, password, scope: 'openid offline' });
  await palamond.processCode(login.code!);
}

After processCode resolves, the session is active:

const patient = palamond.getProfile(); // the signed-in Patient

startLogin can return a next step instead of a final code (for example a project selection). Check the returned object and follow the step it indicates before calling processCode.

Sessions and tokens

The client stores tokens and adds the Authorization header to each request. You rarely touch them, but the accessors exist:

palamond.isAuthenticated(); // boolean
palamond.getAccessToken();  // current access token, or undefined

Tokens persist in storage, so a returning user is still signed in. Check isAuthenticated() on load and redirect to sign-in when it is false; the onUnauthenticated option handles a request failing mid-session.

Refreshing

Access tokens are short lived; with an offline scope the client renews them automatically. To refresh proactively on app start:

await palamond.refreshIfExpired(); // no-op while the token is valid

Signing out

await palamond.signOut();

Federated sign-in

For social or enterprise identity providers, use the redirect flow. Called with no code in the URL it navigates the user to the provider; called on your redirect route it exchanges the returned code for a session.

// 1. Begin the flow (navigates away).
await palamond.signInWithRedirect();

// 2. On your redirect route, the same call completes the sign-in.
const profile = await palamond.signInWithRedirect();

Register a new patient

patient.register is the whole sign-up flow in one call: it creates the account, signs it in, and assigns the patient to your clinic. When it resolves, the session is active exactly as after a sign-in, and the return value is the signed-in Patient.

const patient = await palamond.patient.register({
  firstName: 'Ada',
  lastName: 'Voss',
  email: '[email protected]',
  password,
});

That is the whole call. Everything beyond the person's details is derived from the client id you configured the client with: the clinic from the client's organization binding, and the project from the environment. You never pass a project id or a clinic identifier.

A registration with an email that already has an account fails with the platform's message; send the user to sign-in instead. The names go on the account and the new Patient; the patient maintains the rest of their demographics themselves via the record plane.

After registration, the signed-in profile is a Patient scoped to your clinic's organization. See Organization Scoping for how that shapes every read.

Registering into a specific clinic

Most apps serve a single clinic and the section above is all you need. If your app serves several clinics under one account (one client id, many clinics), select the clinic before registering:

palamond.organization.select(organizationId); // the clinic's Organization ID
await palamond.patient.register({ firstName, lastName, email, password });

The patient is then homed into that clinic instead of the client's default. You can set it once when you create the client (organizationId) or switch it per registration with organization.select(...); organization.current() reads it back.

The organization id is the clinic's, and you find it in the console on the clinic's details page or the applications page. It must be a clinic your client is allowed to register into (the organization it is bound to, or a clinic within that account) — anything else is refused. Unlike a registration link, this works whether or not the clinic runs a patient portal.

On this page