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.