{"id":50971990,"url":"https://github.com/faablecloud/auth-js","last_synced_at":"2026-06-19T03:02:09.986Z","repository":{"id":361275367,"uuid":"790267455","full_name":"faablecloud/auth-js","owner":"faablecloud","description":"🔐 An isomorphic JavaScript client for Faable Auth.","archived":false,"fork":false,"pushed_at":"2026-05-29T21:59:54.000Z","size":414,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-29T23:14:53.252Z","etag":null,"topics":["auth","faable","oauth"],"latest_commit_sha":null,"homepage":"https://faablecloud.github.io/auth-js/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/faablecloud.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-04-22T15:12:31.000Z","updated_at":"2026-05-29T21:59:59.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/faablecloud/auth-js","commit_stats":null,"previous_names":["faablecloud/auth-js"],"tags_count":54,"template":false,"template_full_name":null,"purl":"pkg:github/faablecloud/auth-js","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/faablecloud%2Fauth-js","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/faablecloud%2Fauth-js/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/faablecloud%2Fauth-js/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/faablecloud%2Fauth-js/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/faablecloud","download_url":"https://codeload.github.com/faablecloud/auth-js/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/faablecloud%2Fauth-js/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34515405,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-19T02:00:06.005Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["auth","faable","oauth"],"created_at":"2026-06-19T03:02:09.477Z","updated_at":"2026-06-19T03:02:09.980Z","avatar_url":"https://github.com/faablecloud.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://faable.com\"\u003e\n    \u003cimg src=\"https://www.faable.com/assets/logo/Emblem.png\" height=\"96\"\u003e\n    \u003ch3 align=\"center\"\u003eFaable\u003c/h3\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://faable.com\"\u003e\n    \u003ch1 align=\"center\"\u003eauth-js\u003c/h1\u003e\n  \u003c/a\u003e\n  \u003cp align=\"center\"\u003eAn isomorphic JavaScript client for Faable Auth.\u003c/p\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca aria-label=\"NPM version\" href=\"https://www.npmjs.com/package/@faable/auth-js\"\u003e\n    \u003cimg alt=\"\" src=\"https://img.shields.io/npm/v/@faable/auth-js.svg?style=for-the-badge\u0026labelColor=000000\"\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  📚 Full documentation at \u003ca href=\"https://faable.com/docs\"\u003efaable.com/docs\u003c/a\u003e\n\u003c/p\u003e\n\n## Features\n\n- OAuth social connections (Google, GitHub, …) with PKCE and implicit flows\n- Username + password login\n- Passwordless: email magic link and OTP code\n- Automatic token refresh with cross-tab synchronization via `BroadcastChannel`\n- Pluggable storage adapters (`localStorage`, cookies, or custom)\n- Server-side session helpers for Next.js\n\n## Install\n\n```bash\nnpm install @faable/auth-js\n```\n\nRequires Node.js `\u003e=22.8` for development. The published bundle runs in any\nmodern browser and in Node/SSR environments.\n\n## Quick start\n\n```ts\nimport { createClient } from '@faable/auth-js'\n\nexport const auth = createClient({\n  domain: '\u003cfaableauth_domain\u003e',\n  clientId: '\u003cclient_id\u003e',\n  redirectUri: window.location.origin\n})\n\n// Trigger a social login\nawait auth.signInWithOauthConnection({ connection: 'google' })\n```\n\n## Configuration\n\n`createClient(config)` accepts:\n\n| Option          | Type               | Description                                                           |\n| --------------- | ------------------ | --------------------------------------------------------------------- |\n| `domain`        | `string`           | **Required.** Your Faable Auth tenant domain.                         |\n| `clientId`      | `string`           | **Required.** Application client ID.                                  |\n| `redirectUri`   | `string`           | Default callback URL. Falls back to `window.location.origin`.         |\n| `scope`         | `string`           | Space-separated scopes. Defaults to `openid profile email`.           |\n| `storage`       | `SupportedStorage` | Custom storage adapter. Defaults to `localStorage`.                   |\n| `storageKey`    | `string`           | Prefix for the storage key. Final key is `${storageKey}-${clientId}`. |\n| `cookieOptions` | `CookieOptions`    | When set, switches storage to the cookie adapter.                     |\n| `lock`          | `LockFunc`         | Custom locking primitive for concurrent refreshes.                    |\n| `debug`         | `boolean`          | Enables verbose logging.                                              |\n\n## Authentication flows\n\n### OAuth / social connection\n\n```ts\n// Use the default connection configured on the tenant\nawait auth.signInWithOauthConnection({})\n\n// Or pick a specific provider (by name or connection_id)\nawait auth.signInWithOauthConnection({\n  connection_id: 'conn_01HX…', // preferred when known; falls back to `connection` for legacy tenants\n  redirectTo: 'https://app.example.com/callback',\n  scopes: 'openid profile email',\n  queryParams: { prompt: 'select_account' }\n})\n```\n\nIn browsers the SDK uses the PKCE flow by default and exchanges the `code` for a\nsession on the callback page. The first call to `createClient` automatically\nprocesses the URL when the user lands back on the redirect target.\n\n### Username + password\n\n```ts\nawait auth.signInWithUsernamePassword({\n  username: 'user@example.com',\n  password: '••••••••',\n  redirectTo: 'https://app.example.com/callback'\n})\n```\n\n### Passwordless (magic link or OTP)\n\n```ts\n// Step 1 — request a code or link\nawait auth.signInWithPasswordless({\n  email: 'user@example.com',\n  type: 'code' // or \"link\"\n})\n\n// Step 2 — complete the login with the OTP the user received\nconst { data, error } = await auth.signInWithOtp({\n  username: 'user@example.com',\n  otp: '123456'\n})\n```\n\n### Password reset\n\n```ts\nawait auth.changePassword({ email: 'user@example.com' })\n```\n\n### Sign out\n\n```ts\nawait auth.signOut() // global — all sessions for this user\nawait auth.signOut({ scope: 'local' }) // only this device\n```\n\n## Sessions and state changes\n\n```ts\n// Get the current session (refreshes if needed)\nconst {\n  data: { session }\n} = await auth.getSession()\n\n// Subscribe to auth events\nconst {\n  data: { subscription }\n} = auth.onAuthStateChange((event, session) =\u003e {\n  // event: INITIAL_SESSION | SIGNED_IN | SIGNED_OUT | TOKEN_REFRESHED | PASSWORD_RECOVERY | USER_UPDATED\n})\n\n// Stop listening\nsubscription.unsubscribe()\n\n// Force a refresh\nawait auth.refreshSession()\n```\n\nAuth events are broadcast across tabs using `BroadcastChannel`, so a sign-in or\nsign-out in one tab is reflected in every other tab using the same `storageKey`.\n\n## Storage adapters\n\n### Trade-offs\n\nRefresh tokens are sensitive: anyone who reads them can impersonate the user\nuntil the token is revoked. The storage you pick decides where they live:\n\n- **`localStorage` (default)** — simple and supports cross-tab sync via\n  `BroadcastChannel`, but any script running on the same origin can read it. **A\n  single XSS lets an attacker exfiltrate the refresh token.** Acceptable for\n  low-risk apps and prototypes; not recommended when the surface has third-party\n  scripts, user-generated HTML, or strict compliance requirements.\n- **Cookies** — required for SSR (server reads them on every request) and the\n  only adapter that lets you scope storage with `Secure`, `SameSite`, and\n  `Domain`. Note that this library writes cookies from JavaScript, so they\n  cannot be marked `HttpOnly`; an XSS can still read them, but cookies make CSRF\n  and same-site policies enforceable in a way `localStorage` does not.\n- **Custom adapter** — use for in-memory storage (tokens lost on reload, safest\n  against XSS), Web Workers, or platform-specific keychains.\n\nIf your app is exposed to untrusted content, prefer cookies with `Secure: true`\nand `SameSite: \"Lax\"` (or `\"Strict\"`), and treat XSS prevention (CSP, escaping,\nframework guarantees) as a hard requirement regardless of which adapter you\npick.\n\n### localStorage (default)\n\nUsed automatically in browsers. No configuration required.\n\n### Cookies\n\nUseful for SSR setups where the server must read the session from the request.\n\n```ts\nimport { createClient } from '@faable/auth-js'\n\nexport const auth = createClient({\n  domain: '\u003cfaableauth_domain\u003e',\n  clientId: '\u003cclient_id\u003e',\n  storage: 'cookie'\n})\n```\n\nThat's it. The adapter sets sensible defaults: `Path=/`, `SameSite=Lax`, auto\n`Secure` on HTTPS, and a 30-day `Max-Age` so users stay signed in across browser\nrestarts.\n\nUse `cookieOptions` only when you need to override something — e.g. share the\nsession across subdomains:\n\n```ts\ncreateClient({\n  domain: '\u003cfaableauth_domain\u003e',\n  clientId: '\u003cclient_id\u003e',\n  storage: 'cookie',\n  cookieOptions: { domain: '.example.com' }\n})\n```\n\n### Custom adapter\n\nProvide any object that implements `getItem`, `setItem`, and `removeItem` (sync\nor async). Set `isServer: true` if values may come from an untrusted source such\nas request cookies.\n\n```ts\nconst memoryStorage = {\n  store: new Map\u003cstring, string\u003e(),\n  getItem: (k: string) =\u003e memoryStorage.store.get(k) ?? null,\n  setItem: (k: string, v: string) =\u003e void memoryStorage.store.set(k, v),\n  removeItem: (k: string) =\u003e void memoryStorage.store.delete(k)\n}\n\ncreateClient({ domain, clientId, storage: memoryStorage })\n```\n\n## Next.js / server-side\n\nUse cookie storage on the client, then read the session from `next/headers` on\nthe server:\n\n```ts\n// app/page.tsx\nimport { cookies } from 'next/headers'\nimport { getSessionFromCookies } from '@faable/auth-js'\n\nexport default async function Page() {\n  const session = getSessionFromCookies(cookies(), { clientId: '\u003cclient_id\u003e' })\n  if (!session) return \u003cSignIn /\u003e\n  return \u003cDashboard user={session.user} /\u003e\n}\n```\n\nPass the same `clientId` you used in `createClient`. If you also passed a custom\n`storageKey` to `createClient`, mirror it here as `{ clientId, storageKey }` so\nthe helper looks at the same cookie.\n\n## Documentation\n\nFor the full guides, API reference, and dashboard setup walkthroughs visit\n[faable.com/docs](https://faable.com/docs).\n\n## License\n\nSee [LICENSE.md](LICENSE.md).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffaablecloud%2Fauth-js","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffaablecloud%2Fauth-js","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffaablecloud%2Fauth-js/lists"}