diff --git a/passkey-api/js-sdk.mdx b/passkey-api/js-sdk.mdx
index ab2f1cf..f6015b8 100644
--- a/passkey-api/js-sdk.mdx
+++ b/passkey-api/js-sdk.mdx
@@ -70,273 +70,102 @@ const creationOptions = await tenant.registration.initialize({
{/* TODO complete node.js tutorial just like "/passkey-api/example-implementation"? */}
-## Example Implementation
+## Methods
-
-
+### Initializing the API
-
-
-```bash npm
-npm i @teamhanko/passkeys-sdk
+```typescript
+const passkeys = tenant({ baseUrl?: string, apiKey: string, tenantId: string })
```
-```bash yarn
-yarn add @teamhanko/passkeys-sdk
-```
+### Registration
-```bash bun
-bun add @teamhanko/passkeys-sdk
-```
+#### Initialize Registration
-```bash pnpm
-pnpm add @teamhanko/passkeys-sdk
+```typescript
+passkeys.registration.initialize({ userId: string, username: string, icon?: string, displayName?: string })
```
-
-
-
+Initialize the registration process for a new user.
-Get your tenant ID and API key from [Hanko Cloud](https://cloud.hanko.io/) and add them to your `.env` file.
+#### Finalize Registration
-```bash .env
-PASSKEYS_API_KEY=your-api-key
-PASSKEYS_TENANT_ID=your-tenant-id
+```typescript
+passkeys.registration.finalize(credential)
```
-
-
-On your backend, you’ll have to call `tenant({ ... }).registration.initialize()` and `registration.finalize()` to create and store a passkey.
-```js services.js
-import { tenant } from "@teamhanko/passkeys-sdk";
-import dotenv from "dotenv";
-import db from "../db.js";
+Finalize the registration process. The `credential` should be the credential returned by the user's browser (from `navigator.credentials.create()`).
-dotenv.config();
+### Login
-const passkeyApi = tenant({
- apiKey: process.env.PASSKEYS_API_KEY,
- tenantId: process.env.PASSKEYS_TENANT_ID,
-});
+#### Initialize Login
-async function startServerPasskeyRegistration(userID) {
- const user = db.users.find((user) => user.id === userID);
+```typescript
+passkeys.login.initialize()
+```
- const createOptions = await passkeyApi.registration.initialize({
- userId: user.id,
- username: user.email || "",
- });
+Initialize the login process.
- return createOptions;
-}
+#### Finalize Login
-async function finishServerPasskeyRegistration(credential) {
- await passkeyApi.registration.finalize(credential);
-}
+```typescript
+passkeys.login.finalize(credential)
```
-```js controllers.js
-async function handlePasskeyRegister(req, res) {
- const { user } = req;
- const userID = user.id;
-
- if (!userID) {
- return res.status(401).json({ message: "Unauthorized" });
- }
- console.log("userId", userID);
-
- const { start, finish, credential } = req.body;
-
- try {
- if (start) {
- const createOptions = await startServerPasskeyRegistration(userID);
- console.log("registration start");
- return res.json({ createOptions });
- }
- if (finish) {
- await finishServerPasskeyRegistration(credential);
- return res.json({ message: "Registered Passkey" });
- }
- } catch (error) {
- return res.status(500).json(error);
- }
-}
+Finalize the login process. The `credential` should be the credential returned by the user's browser (from `navigator.credentials.get()`).
+
+### Multi-Factor Authentication (MFA)
+
+#### MFA Registration
+
+```typescript
+passkeys.user(userId).mfa.registration.initialize({ username: string, icon?: string, displayName?: string })
+passkeys.user(userId).mfa.registration.finalize(credential)
```
-**Frontend**
-
-On your frontend, the `registerPasskey()` function handles the passkey registration process. It first sends a request to the server to initiate the registration process and receives the response for creating a new passkey.
-
-It then uses the `@github/webauthn-json` library to create a new passkey credential based on the received options from the response. Finally, it sends another request to the server with the newly created credential to complete the registration process.
-
-```tsx
- async function registerPasskey() {
- const createOptionsResponse = await fetch("http://localhost:5001/api/passkeys/register", {
- method: "POST",
- headers: { "Content-Type": "application/json" },
- credentials: 'include',
- body: JSON.stringify({ start: true, finish: false, credential: null }),
- });
-
- const { createOptions } = await createOptionsResponse.json();
- console.log("createOptions", createOptions)
-
- const credential = await create(
- createOptions as CredentialCreationOptionsJSON,
- );
- console.log(credential)
-
- const response = await fetch("http://localhost:5001/api/passkeys/register", {
- method: "POST",
- headers: { "Content-Type": "application/json" },
- credentials: "include",
- body: JSON.stringify({ start: false, finish: true, credential }),
- });
- console.log(response)
-
- if (response.ok) {
- toast.success("Registered passkey successfully!");
- return;
- }
- }
+Initialize and finalize MFA registration for a specific user.
+
+#### MFA Login
+
+```typescript
+passkeys.user(userId).mfa.login.initialize()
+passkeys.user(userId).mfa.login.finalize(credential)
```
-
-
-
-```js services.js
-async function startServerPasskeyLogin() {
- const options = await passkeyApi.login.initialize();
- return options;
-}
-
-async function finishServerPasskeyLogin(options) {
- const response = await passkeyApi.login.finalize(options);
- return response;
-}
+
+Initialize and finalize MFA login for a specific user.
+
+### User-specific Operations
+
+These methods all operate on a user. You'll need to pass their user ID using `.user(userId)`
+
+#### Get User Credentials
+
+```typescript
+passkeys.user(userId).credentials()
```
-```js controllers.js
-async function handlePasskeyLogin(req, res) {
- const { start, finish, options } = req.body;
-
- try {
- if (start) {
- const loginOptions = await startServerPasskeyLogin();
- return res.json({ loginOptions });
- }
- if (finish) {
- const jwtToken = await finishServerPasskeyLogin(options);
- const userID = await getUserID(jwtToken?.token ?? "");
- console.log("userID from hanko", userID);
- const user = db.users.find((user) => user.id === userID);
- if (!user) {
- return res.status(401).json({ message: "Invalid user" });
- }
- console.log("user", user);
- const sessionId = uuidv4();
- setUser(sessionId, user);
- res.cookie("sessionId", sessionId);
- return res.json({ message: " Passkey Login successful" });
- }
- } catch (error) {
- console.error(error);
- return res
- .status(500)
- .json({ message: "An error occurred during the passke login process." });
- }
-}
+Retrieve a list of WebAuthn credentials for a specific user.
+
+### Credential Operations
+
+#### Remove Credential
+
+```typescript
+passkeys.credential(credentialId).remove()
```
-**Frontend**
-```tsx
- async function signInWithPasskey() {
- const createOptionsResponse = await fetch("http://localhost:5001/api/passkeys/login", {
- method: "POST",
- headers: { "Content-Type": "application/json" },
- credentials: 'include',
- body: JSON.stringify({ start: true, finish: false, credential: null }),
- });
-
- const { loginOptions } = await createOptionsResponse.json();
-
- // Open "register passkey" dialog
- const options = await get(
- loginOptions as any,
- );
-
- const response = await fetch("http://localhost:5001/api/passkeys/login", {
- method: "POST",
- headers: { "Content-Type": "application/json" },
- credentials: 'include',
- body: JSON.stringify({ start: false, finish: true, options }),
- });
-
- if (response.ok) {
- console.log("user logged in with passkey")
- navigate("/dashboard")
- return;
- }
- }
+Remove a specific credential.
+
+### Other Operations
+
+#### Get JWKS
+
+```typescript
+passkeys.jwks()
```
-
-
-
-## Try it yourself
-
-Check out sample apps made using the SDK:
-
-
-
-
-
-
-
-
-
-
-
-
- }
- >
- Full source code available on our GitHub.
-
-
-
-
-
- }
- >
- Full source code available on our GitHub.
-
-
+Retrieve the JSON Web Key Set (JWKS) for the tenant.
+
+## Error Handling
+
+The API uses a custom `PasskeyError` class for error handling. Errors will include a message and potentially the original error that caused the issue.