# Signing in and out (https://session-kit.pages.dev/docs/client/signing-in-and-out)

`auth.signIn({ ...tokens, user })` validates and saves a new session,
replacing any current one, even a locked one. With
[`fromAccessToken`](https://session-kit.pages.dev/docs/client/users-from-tokens), leave out `user`. The
latest call wins, and invalid input keeps the previous session.
[Expiry](https://session-kit.pages.dev/docs/configuration/expiry) covers how the token's lifetime is
found.

`auth.signOut()` ends the session and clears storage. Other tabs sign out too
when the storage reports changes, as `webStorage()` does, and `locking` is
off.

If your backend can revoke tokens, give the client a `revoke` callback. It
receives the ended tokens after the user is signed out:

```ts title="src/revoke.ts"
import type { RevokeFn } from "@monarcode/session-kit";

/** Pass as `createAuth`'s `revoke` option. */
export const revoke: RevokeFn = async ({ refreshToken, signal }) => {
  if (!refreshToken) return;
  const response = await fetch("https://api.example.com/auth/revoke", {
    method: "POST",
    signal,
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ refreshToken }),
  });
  if (!response.ok) throw new Error(`Revoke failed (${response.status})`);
};
```

`signOut()` resolves once `revoke` settles, so await it before a full-page
redirect, which would cancel the request.

A failed revocation shows in `state.error` as `REVOKE_FAILED`, and the
sign-out stands. The user asked to leave, and has. The client doesn't revoke
a session the backend already rejected.