{"id":16827,"library":"haaremy-auth","title":"Haaremy SSO Auth SDK","description":"The official Haaremy SSO Authentication SDK provides a comprehensive solution for integrating Haaremy's Single Sign-On system into JavaScript applications. It encapsulates token handling, login/logout flows, BroadcastChannel-based tab synchronization, and offers specific integrations for React and Next.js. Currently at version 2.0.0, this SDK is actively maintained with a focus on security and developer experience. Key differentiators include its 'zero localStorage' approach (tokens are memory-only), proactive token refresh, server-side replay detection for token families, and efficient offline JWT validation using JWKS caching with Ed25519 signatures. It offers distinct entrypoints for vanilla JS/framework-agnostic core logic, React hooks and components, and Next.js middleware/server-side helpers, making it adaptable to various application architectures.","status":"active","version":"2.0.0","language":"javascript","source_language":"en","source_url":"https://github.com/haaremy/hmyAuth","tags":["javascript","haaremy","sso","auth","jwt","ed25519","typescript"],"install":[{"cmd":"npm install haaremy-auth","lang":"bash","label":"npm"},{"cmd":"yarn add haaremy-auth","lang":"bash","label":"yarn"},{"cmd":"pnpm add haaremy-auth","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Required for the `@haaremy/auth/next` entrypoint for middleware and server-side helpers.","package":"next","optional":true},{"reason":"Required for the `@haaremy/auth/react` entrypoint for React hooks and components.","package":"react","optional":true}],"imports":[{"note":"The core library is primarily designed for ESM usage. CommonJS `require` is not officially supported and may lead to issues, especially in environments like Next.js Edge Runtime.","wrong":"const { init } = require('@haaremy/auth')","symbol":"init","correct":"import { init } from '@haaremy/auth'"},{"note":"`useAuth` is a React Hook and must be imported from the `/react` subpath. Importing from the main entrypoint will result in `undefined` or a module not found error.","wrong":"import { useAuth } from '@haaremy/auth'","symbol":"useAuth","correct":"import { useAuth } from '@haaremy/auth/react'"},{"note":"The React context provider `HmyAuthProvider` is specific to React applications and must be imported from the `/react` subpath.","symbol":"HmyAuthProvider","correct":"import { HmyAuthProvider } from '@haaremy/auth/react'"},{"note":"`createHmyMiddleware` is a named export from the `/next` subpath, intended for Next.js `middleware.ts` files. It is not a default export.","wrong":"import createHmyMiddleware from '@haaremy/auth/next'","symbol":"createHmyMiddleware","correct":"import { createHmyMiddleware } from '@haaremy/auth/next'"},{"note":"The `login` function is part of the core vanilla JS API. It's an async function and should be awaited.","symbol":"login","correct":"import { login } from '@haaremy/auth'"}],"quickstart":{"code":"import { HmyAuthProvider, useAuth, HmyLoginForm } from '@haaremy/auth/react';\n\nconst ssoUrl = process.env.NEXT_PUBLIC_SSO_URL ?? 'https://sso.haaremy.de'; // Ensure SSO URL is configured\n\n// This component would typically be in your _app.tsx or layout.tsx\nfunction AppWrapper({ children }) {\n  return (\n    <HmyAuthProvider config={{ ssoUrl: ssoUrl }}>\n      {children}\n    </HmyAuthProvider>\n  );\n}\n\n// This component demonstrates how to use the auth state within your application\nfunction MyAuthenticatedPage() {\n  const { state, user, login, logout, getAccessToken } = useAuth();\n\n  if (state === 'loading') {\n    return <div>Authentifizierungsstatus wird geladen...</div>;\n  }\n\n  if (state === 'unauthenticated') {\n    return (\n      <div>\n        <p>Sie sind nicht angemeldet.</p>\n        <HmyLoginForm\n          onSuccess={(loggedInUser) => {\n            console.log('Login erfolgreich:', loggedInUser.display_name);\n          }}\n          onError={(error) => {\n            console.error('Login fehlgeschlagen:', error.message);\n          }}\n        />\n      </div>\n    );\n  }\n\n  // State is 'authenticated'\n  return (\n    <div>\n      <h1>Hallo, {user?.display_name}!</h1>\n      <p>Ihre E-Mail: {user?.email}</p>\n      <button onClick={logout}>Abmelden</button>\n      <button onClick={async () => {\n        const token = await getAccessToken();\n        console.log('Aktueller Access Token:', token ? token.substring(0, 20) + '...' : 'Kein Token');\n      }}>Token anzeigen</button>\n    </div>\n  );\n}\n\n// Example usage within a React component tree:\n// function Root() {\n//   return (\n//     <AppWrapper>\n//       <MyAuthenticatedPage />\n//     </AppWrapper>\n//   )\n// }\n// export default Root;\n","lang":"typescript","description":"This quickstart demonstrates how to set up the `HmyAuthProvider` at your application root and use the `useAuth` hook in a child component to manage authentication state, display user information, handle login via `HmyLoginForm`, and perform logout. It showcases both authenticated and unauthenticated states."},"warnings":[{"fix":"Review all import statements. For React components/hooks, change `import { X } from '@haaremy/auth'` to `import { X } from '@haaremy/auth/react'`. For Next.js middleware, ensure `import { createHmyMiddleware } from '@haaremy/auth/next'` is used.","message":"Version 2.0.0 introduces a refactor of the SDK's internal architecture, particularly how subpath imports are organized. Ensure all React-specific components (`HmyAuthProvider`, `useAuth`, `HmyLoginForm`) are imported from `@haaremy/auth/react` and Next.js-specific utilities (`createHmyMiddleware`) from `@haaremy/auth/next`.","severity":"breaking","affected_versions":">=2.0.0"},{"fix":"Design your application's user experience with this in mind. Ensure your login flow can gracefully handle token expiry or loss on browser close. Leverage the refresh token mechanism for persistent sessions via SSO cookies.","message":"The SDK strictly adheres to a 'zero localStorage' policy for Access Tokens, storing them only in JavaScript memory. This means that if a user closes all tabs or the browser, the Access Token is lost, requiring a re-login (which might be handled transparently by the refresh token in the cookie on next visit).","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Carefully define `publicPaths` in your `createHmyMiddleware` configuration. Include `/login`, `/register`, API routes that should be public (e.g., `/api/public*`), and any static assets or `_next` paths as needed. Ensure `loginPath` points to your actual login route.","message":"The Next.js Middleware (`createHmyMiddleware`) relies on `publicPaths` to define routes that do not require authentication. Failing to correctly configure this array can lead to all routes being protected, including login/registration pages, resulting in redirect loops or inaccessible routes.","severity":"gotcha","affected_versions":">=2.0.0"},{"fix":"Always call and `await init()` at your application's startup. When using `authFetch`, ensure the authentication state indicates `authenticated` to prevent unauthorized requests. Consider wrapping `authFetch` calls in conditional logic based on the `state` from `useAuth` or `subscribe`.","message":"The `authFetch` utility, which automatically injects the Access Token into requests, expects an initialized SDK with a valid session. Using `authFetch` before `await init()` has completed or when the user is `unauthenticated` can lead to failed requests.","severity":"breaking","affected_versions":">=2.0.0"},{"fix":"Verify that your SSO provider is configured to use Ed25519 for JWT signatures. Ensure the `jwks.json` endpoint is publicly accessible and contains the correct public keys matching the SSO's private key.","message":"The SDK uses Ed25519 for JWT signing. While highly secure, ensure your backend SSO system correctly issues Ed25519-signed JWTs and exposes a compatible JWKS endpoint (`/.well-known/jwks.json`). Incompatibilities can lead to token validation failures.","severity":"gotcha","affected_versions":">=1.0.0"}],"env_vars":null,"last_verified":"2026-04-22T00:00:00.000Z","next_check":"2026-07-21T00:00:00.000Z","problems":[{"fix":"Change `import { HmyAuthProvider } from '@haaremy/auth'` to `import { HmyAuthProvider } from '@haaremy/auth/react'` (and similarly for other React components/hooks).","cause":"Attempting to use a React component like `HmyAuthProvider` or `HmyLoginForm` imported from the main `@haaremy/auth` entrypoint instead of the `@haaremy/auth/react` subpath.","error":"Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object."},{"fix":"Ensure you are importing `createHmyMiddleware` from the correct subpath: `import { createHmyMiddleware } from '@haaremy/auth/next'`.","cause":"This error typically occurs if `createHmyMiddleware` is imported incorrectly from the main package or if the Next.js subpath is not correctly resolved.","error":"TypeError: Cannot destructure property 'createHmyMiddleware' of 'undefined' as it is undefined."},{"fix":"Add `import { init } from '@haaremy/auth'` to the top of your file. If using CommonJS, consider migrating to ESM or ensuring your build process correctly transpiles.","cause":"The `init` function was called without being imported, or imported incorrectly from a CommonJS `require` statement that doesn't align with the ESM-first design.","error":"ReferenceError: init is not defined"},{"fix":"Before making requests with `authFetch`, ensure your application has completed initialization (`await init()`) and the user state is `authenticated`. You can use `subscribe` or `useAuth` to monitor the authentication state.","cause":"An `authFetch` request was attempted when the SDK's internal state indicated the user was 'unauthenticated' or 'loading', meaning no valid access token was available.","error":"ERR_INVALID_AUTH_STATE: Cannot perform authenticated request. User is not authenticated."}],"ecosystem":"npm","meta_description":null}