# Sign users in

Canonical page: https://docs.ovok.com/web-sdk/core/guides/sign-in

This guide uses the `ovok` client from [Get started](/web-sdk/core/getting-started). Pass a persistent `storage` when users should stay signed in across app restarts.

## Sign in and out [#sign-in-and-out]

```ts
const result = await ovok.auth.login({
  profileType: 'Practitioner',
  email: 'ada@example.com',
  password,
});

if (result.status === 'mfa-required') {
  await ovok.auth.verifyMfa(result.challenge, codeFromAuthenticatorApp);
}

await ovok.auth.logout();
```

- **Login flow:** `login` runs the tenant login with PKCE and signs in to the configured `tenantCode`. `profileType` is `Patient`, `Practitioner` or `RelatedPerson`.
- **Session storage:** the session is saved in `storage` under `ovok:<tenantCode>:session`. The client never clears other keys.
- **Refresh:** access tokens refresh a minute before they expire.
  - A refused refresh token signs the user out and calls `onUnauthenticated`.
  - An outage keeps the session, so a later call can retry.
- **Logout:** `logout` always clears the local session, even when the server cannot be reached.

## Saved accounts and session changes [#saved-accounts-and-session-changes]

The client keeps a private saved session for each signed-in profile in the configured storage.
`ovok.session.savedAccounts.list()` returns profile and project metadata without tokens. Switch or
remove an account by its profile reference. Removing the active account switches to the next
available saved account, when one exists:

```ts
const accounts = await ovok.session.savedAccounts.list();
await ovok.session.savedAccounts.switch('Patient/123');
await ovok.session.savedAccounts.remove('Patient/123');
```

Listen for sign-in, sign-out, account switches and rejected refresh tokens with
`ovok.session.onChange(listener)`. The listener receives the active `Session` or `null`; call the
returned function to unsubscribe. `ovok.session.current()` reads the restored session snapshot.
`ovok.invites.accept(body)` sends a record-share invite to the practitioner route or a care invite
to the patient route based on the active profile.

## Sign in a server as a machine client [#sign-in-a-server-as-a-machine-client]

On a server, pass `clientId` and `clientSecret` from a client application. The client fetches its own token from `/oauth2/token` and renews it before it expires. A machine client cannot call `ovok.auth.login`.

```ts
const ovok = new Ovok({
  baseUrl: process.env.OVOK_BASE_URL,
  tenantCode: process.env.OVOK_TENANT_CODE,
  clientId: process.env.OVOK_CLIENT_ID,
  clientSecret: process.env.OVOK_CLIENT_SECRET,
});
```

## Related [#related]

- [ovok.auth](/web-sdk/core/namespaces/auth) and [ovok.session](/web-sdk/core/namespaces/session) guides.
- [Errors and retries](/web-sdk/core/errors-and-retries) for refused sign-ins and expired sessions.
