1 line
11 KiB
JSON
1 line
11 KiB
JSON
{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"\ud83d\udd10 react-auth \u2014 Authentication UI and State","text":"<p><code>react-auth</code> is the front-end half of the Aetos auth story: a JWT-backed <code>AuthProvider</code>, a pluggable login/register screen, profile screens, and an axios factory that carries bearer tokens and reacts to <code>401</code> responses. The server side lives in the Auth Server service; this package never defines an endpoint contract of its own.</p> <p>Doc model: this wiki is written for humans \u2014 guides and wiring recipes. The authoritative API contracts live in the code (RDFC JSDoc) and the machine-readable bundle under <code>docs/mcp/</code>. Browse the TypeDoc site for the full symbol reference.</p>"},{"location":"#key-features","title":"\ud83d\ude80 Key Features","text":"<ul> <li>\u269b\ufe0f <code>AuthProvider</code> + <code>useAuth</code> \u2014 current user, token, loading and error state with <code>login</code> / <code>register</code> / <code>logout</code></li> <li>\ud83e\uddfe <code>createApiClient</code> \u2014 axios with <code>Authorization: Bearer <token></code> on every request and <code>auth:unauthorized</code> dispatch on <code>401</code></li> <li>\ud83c\udfad <code>AuthPage</code> \u2014 a ready-made split-screen login/register form</li> <li>\ud83d\udc64 <code>ProfileCreate</code> / <code>ProfileEdit</code> / <code>ProfileView</code> \u2014 presentational profile screens that delegate persistence to your callbacks</li> <li>\ud83d\uddc3\ufe0f <code>tokenStore</code> \u2014 the single <code>localStorage</code> accessor keeping the UI and the network layer in sync</li> </ul>"},{"location":"#documentation-structure","title":"\ud83d\udce6 Documentation Structure","text":"Section Description Overview What the library is, and the token/session lifecycle Wiring Guide Drop-in recipes for provider, gate and profile flows"},{"location":"#quick-start","title":"\ud83d\ude80 Quick Start","text":"<pre><code>import { AuthProvider, useAuth, AuthPage } from \"react-auth\";\n\nexport default function Root() {\n return (\n <AuthProvider\n authConfig={{\n serverUrl: \"https://api.example.com\",\n loginPath: \"/auth/login\",\n registerPath: \"/auth/register\",\n logoutPath: \"/auth/logout\",\n mePath: \"/auth/me\",\n introspectPath: \"/auth/introspect\",\n }}\n >\n <LoginGate />\n </AuthProvider>\n );\n}\n</code></pre>"},{"location":"#related-resources","title":"\ud83d\udd17 Related Resources","text":"<ul> <li>Source Code: the <code>react-auth</code> repository</li> <li>TypeDoc site: the generated <code>lib</code> HTML for the full API reference</li> <li>MCP Bundle: <code>docs/mcp/</code> (<code>docs://modules/react-auth</code>)</li> <li>Library Registry: registered in the standards hub as <code>react-auth</code> (MCP <code>:8011</code>)</li> <li>Auth Server: the service behind <code>authConfig</code> \u2014 read <code>docs://spec</code> on the <code>standards</code> MCP for the pinned contract</li> </ul> <p>\u00a9 Aetoskia Internal \u2014 <code>react-auth</code> 0.0.1</p>"},{"location":"01_overview/","title":"Library Overview","text":"<p><code>react-auth</code> owns three concerns and nothing else: session state, the authenticated HTTP client, and the screens that produce a session. It talks to an auth server over HTTP \u2014 it never issues, validates or decodes tokens itself.</p>"},{"location":"01_overview/#what-lives-where","title":"\ud83e\udded What lives where","text":"Concern Module Notes Session state <code>contexts.tsx</code> <code>AuthProvider</code>, <code>useAuth</code>, <code>AuthServerConfig</code> Authenticated HTTP client <code>axios.ts</code> <code>createApiClient</code>, <code>attachAuthInterceptors</code> Token persistence <code>token.ts</code> <code>tokenStore</code> (<code>localStorage</code>, key <code>\"token\"</code>) Login / register screen <code>AuthPage.tsx</code> <code>AuthPage</code>, <code>AuthMode</code> Profile screens <code>Profile*.tsx</code> controlled presentational components User model <code>models.ts</code> <code>AuthUser</code> <p>The package entry (<code>index.ts</code>) re-exports the public surface; nothing else in the app should import the internals directly.</p>"},{"location":"01_overview/#session-lifecycle","title":"\ud83d\udd04 Session lifecycle","text":"<ol> <li>Bootstrap \u2014 <code>AuthProvider</code> seeds its token from <code>tokenStore.get()</code>.</li> <li>Resolve the user \u2014 whenever the token changes, <code>mePath</code> is fetched and <code>currentUser</code> is set (or cleared).</li> <li>Login \u2014 <code>login(username, password)</code> posts to <code>loginPath</code>, stores <code>access_token</code> through <code>tokenStore</code>, and takes <code>currentUser</code> from the response <code>user</code>.</li> <li>Register \u2014 <code>register(...)</code> creates the account, then logs in.</li> <li>Request \u2014 every client built by <code>createApiClient</code> attaches <code>Authorization: Bearer <token></code> from <code>tokenStore</code>.</li> <li>Expiry \u2014 a <code>401</code> clears the token and dispatches an <code>auth:unauthorized</code> window event; <code>AuthProvider</code> listens, clears the session, and invokes the optional <code>onUnauthorized</code> callback.</li> <li>Logout \u2014 best-effort call to <code>logoutPath</code>, then local state is always cleared.</li> </ol> <p>One source of truth</p> <p><code>tokenStore</code> is the only place the token is written. Reading it from anywhere else will desynchronise the UI from the network layer.</p>"},{"location":"01_overview/#endpoint-contract","title":"\ud83c\udfd7\ufe0f Endpoint contract","text":"<p><code>AuthServerConfig</code> is the complete wiring surface; every path resolves relative to <code>serverUrl</code>:</p> Field Shape <code>loginPath</code> <code>POST { username, password }</code> \u2192 <code>{ access_token, user }</code> <code>registerPath</code> <code>POST { username, password }</code> to create an account <code>logoutPath</code> called on logout; failures are ignored <code>mePath</code> returns the current <code>AuthUser</code> for a valid bearer token <code>introspectPath</code> token introspection, available to callers that need it <p><code>AuthUser</code> is intentionally permissive so it can be spread into application state without loss.</p>"},{"location":"01_overview/#read-next","title":"\u27a1\ufe0f Read Next","text":"<ul> <li>02 \u2013 Wiring Guide</li> </ul>"},{"location":"02_wiring/","title":"Wiring Guide","text":"<p>Recipes for the three things every Khata front-end does: mount the provider, gate on the session, and edit the profile. All of these are presentational \u2014 swap in your own router or layout as needed.</p>"},{"location":"02_wiring/#1-mount-the-provider","title":"\ud83d\udce6 1. Mount the provider","text":"<pre><code>import { AuthProvider } from \"react-auth\";\nimport type { AuthServerConfig } from \"react-auth\";\n\nconst authConfig: AuthServerConfig = {\n serverUrl: \"https://api.example.com\",\n loginPath: \"/auth/login\",\n registerPath: \"/auth/register\",\n logoutPath: \"/auth/logout\",\n mePath: \"/auth/me\",\n introspectPath: \"/auth/introspect\",\n};\n\nexport default function Root() {\n return (\n <AuthProvider authConfig={authConfig} onUnauthorized={() => console.info(\"session expired\")}>\n <App />\n </AuthProvider>\n );\n}\n</code></pre> <p><code>AuthProvider</code> must wrap any component that calls <code>useAuth</code>.</p>"},{"location":"02_wiring/#2-gate-on-the-session","title":"\ud83d\udce6 2. Gate on the session","text":"<pre><code>import { useAuth, AuthPage } from \"react-auth\";\nimport { useState } from \"react\";\n\nfunction LoginGate({ children }: { children: React.ReactNode }) {\n const auth = useAuth();\n const [mode, setMode] = useState<\"login\" | \"register\">(\"login\");\n\n if (auth.currentUser) return <>{children}</>;\n\n return (\n <AuthPage\n mode={mode}\n onBack={() => history.back()}\n onSwitchMode={() => setMode((m) => (m === \"login\" ? \"register\" : \"login\"))}\n login={auth.login}\n register={auth.register}\n loading={auth.loading}\n error={auth.error}\n currentUser={auth.currentUser}\n />\n );\n}\n</code></pre> <p>Automatic redirect</p> <p><code>AuthPage</code> calls <code>onBack</code> on its own once <code>currentUser</code> becomes truthy, so it works as a route guard without a <code>useEffect</code>. <code>mode</code> is fully controlled, so the login/register toggle never unmounts the form.</p>"},{"location":"02_wiring/#3-profile-screens","title":"\ud83d\udce6 3. Profile screens","text":"<p><code>ProfileCreate</code>, <code>ProfileEdit</code> and <code>ProfileView</code> render the profile UI and delegate persistence to callbacks you supply \u2014 the library does not know how your backend stores profiles.</p> <p>The three screens take flat props, not a user object:</p> Component Props <code>ProfileView</code> <code>name</code>, <code>username</code>, <code>email</code>, <code>onEdit?</code>, <code>loading?</code> <code>ProfileEdit</code> <code>name</code>, <code>username</code>, <code>email</code>, <code>onSubmit</code>, <code>onBack?</code>, <code>loading?</code>, <code>error?</code> <code>ProfileCreate</code> <code>onSubmit</code>, <code>defaultUsername?</code>, <code>defaultEmail?</code>, <code>onBack?</code>, <code>loading?</code>, <code>error?</code> <pre><code>import { ProfileView, ProfileEdit, useAuth } from \"react-auth\";\nimport { useState } from \"react\";\n\nfunction ProfileRoute() {\n const { currentUser } = useAuth();\n const [editing, setEditing] = useState(false);\n\n if (!currentUser) return null;\n const { username, email } = currentUser;\n const props = { username, email, name: username };\n\n if (editing) {\n return <ProfileEdit {...props} onBack={() => setEditing(false)} onSubmit={saveProfile} />;\n }\n return <ProfileView {...props} onEdit={() => setEditing(true)} />;\n}\n</code></pre> <p><code>onSubmit</code> always receives <code>{ name, email }</code> \u2014 persistence is yours.</p> <p>Client-side validation only</p> <p><code>AuthPage</code> validates <code>username >= 3</code> and <code>password >= 6</code> before calling your callback. The auth server remains the authority \u2014 never skip its validation.</p>"},{"location":"02_wiring/#4-authenticated-api-calls","title":"\ud83d\udce6 4. Authenticated API calls","text":"<pre><code>import { createApiClient } from \"react-auth\";\n\nconst api = createApiClient(\"https://api.example.com\");\nconst { data } = await api.get(\"/expenses\"); // Authorization added automatically\n</code></pre> <p>Use <code>createApiClient</code> for any backend that shares the auth-server login. A plain axios instance is fine for unauthenticated endpoints.</p> <p>For an existing client, <code>attachAuthInterceptors(client)</code> decorates it in place with the same request/response behaviour.</p>"},{"location":"02_wiring/#related","title":"\ud83d\udd17 Related","text":"<ul> <li>01 \u2013 Overview</li> <li>Auth Server contract: <code>docs://spec</code> on the <code>standards</code> MCP</li> </ul>"}]} |