@auditauth/react 0.2.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,173 @@
1
+ # @auditauth/react
2
+
3
+ `@auditauth/react` is the AuditAuth SDK integration for React applications. It
4
+ provides a provider, a hook, and a route guard to handle redirect callbacks,
5
+ session state, login and logout actions, and authenticated HTTP calls.
6
+
7
+ ## Install
8
+
9
+ Install the package in your React application.
10
+
11
+ ```bash
12
+ npm install @auditauth/react
13
+ ```
14
+
15
+ `@auditauth/react` has peer dependencies on `react` and `react-dom` version 18
16
+ or higher.
17
+
18
+ ## Wrap your app with the provider
19
+
20
+ Create one top-level `AuditAuthProvider` and pass your AuditAuth config.
21
+
22
+ ```tsx
23
+ import { AuditAuthProvider } from '@auditauth/react'
24
+
25
+ export function AppRoot() {
26
+ return (
27
+ <AuditAuthProvider
28
+ config={{
29
+ apiKey: import.meta.env.VITE_AUDITAUTH_API_KEY,
30
+ appId: import.meta.env.VITE_AUDITAUTH_APP_ID,
31
+ baseUrl: 'http://localhost:5173',
32
+ redirectUrl: 'http://localhost:5173/private',
33
+ }}
34
+ >
35
+ <App />
36
+ </AuditAuthProvider>
37
+ )
38
+ }
39
+ ```
40
+
41
+ The provider runs `handleRedirect()` on startup and exposes the current user
42
+ and session actions through `useAuditAuth()`.
43
+
44
+ ## Protect private UI with `RequireAuth`
45
+
46
+ Wrap private content with `RequireAuth` to trigger login when the user is not
47
+ authenticated.
48
+
49
+ ```tsx
50
+ import { RequireAuth } from '@auditauth/react'
51
+
52
+ export function PrivatePage() {
53
+ return (
54
+ <RequireAuth>
55
+ <h1>Private area</h1>
56
+ </RequireAuth>
57
+ )
58
+ }
59
+ ```
60
+
61
+ `RequireAuth` renders children only after the SDK is ready and the user has a
62
+ valid session.
63
+
64
+ ## Use auth state and actions in components
65
+
66
+ Use `useAuditAuth()` inside components that are children of
67
+ `AuditAuthProvider`.
68
+
69
+ ```tsx
70
+ import { useAuditAuth } from '@auditauth/react'
71
+
72
+ export function AccountMenu() {
73
+ const { user, ready, login, logout, goToPortal } = useAuditAuth()
74
+
75
+ if (!ready) return null
76
+
77
+ if (!user) {
78
+ return <button onClick={() => login()}>Login</button>
79
+ }
80
+
81
+ return (
82
+ <div>
83
+ <span>{user.email}</span>
84
+ <button onClick={() => goToPortal()}>Portal</button>
85
+ <button onClick={() => logout()}>Logout</button>
86
+ </div>
87
+ )
88
+ }
89
+ ```
90
+
91
+ ## Make authenticated API calls
92
+
93
+ Use `fetch` from `useAuditAuth()` instead of `window.fetch()` for authenticated
94
+ requests. The SDK attaches the session token and handles refresh behavior when
95
+ needed.
96
+
97
+ ```tsx
98
+ import { useAuditAuth } from '@auditauth/react'
99
+
100
+ export function ProfileButton() {
101
+ const { fetch } = useAuditAuth()
102
+
103
+ const loadProfile = async () => {
104
+ const response = await fetch('https://api.example.com/private/profile')
105
+ const data = await response.json()
106
+ console.log(data)
107
+ }
108
+
109
+ return <button onClick={loadProfile}>Load profile</button>
110
+ }
111
+ ```
112
+
113
+ ## Track navigation metrics
114
+
115
+ If you use a client router such as React Router, call `trackNavigationPath()`
116
+ when the path changes.
117
+
118
+ ```tsx
119
+ import { useEffect } from 'react'
120
+ import { useLocation } from 'react-router-dom'
121
+ import { useAuditAuth } from '@auditauth/react'
122
+
123
+ export function NavigationTracker() {
124
+ const { pathname } = useLocation()
125
+ const { trackNavigationPath } = useAuditAuth()
126
+
127
+ useEffect(() => {
128
+ trackNavigationPath(pathname)
129
+ }, [pathname, trackNavigationPath])
130
+
131
+ return null
132
+ }
133
+ ```
134
+
135
+ ## API reference
136
+
137
+ `useAuditAuth()` returns:
138
+
139
+ - `ready: boolean`
140
+ - `user: SessionUser | null`
141
+ - `fetch(input, init?): Promise<Response>`
142
+ - `login(): Promise<void>`
143
+ - `logout(): Promise<void>`
144
+ - `goToPortal(): Promise<void>`
145
+ - `isAuthenticated(): boolean`
146
+ - `trackNavigationPath(path: string): void`
147
+
148
+ Exports from `@auditauth/react`:
149
+
150
+ - `AuditAuthProvider`
151
+ - `useAuditAuth`
152
+ - `RequireAuth`
153
+
154
+ ## Compatibility
155
+
156
+ This package requires:
157
+
158
+ - Node.js `>=18.18.0` for tooling and build environments
159
+ - React `>=18`
160
+ - React DOM `>=18`
161
+
162
+ ## Resources
163
+
164
+ - Repository: https://github.com/nimibyte/auditauth-sdk
165
+ - Documentation: https://docs.auditauth.com
166
+
167
+ ## Example
168
+
169
+ See `examples/react` for a complete Vite + React Router integration.
170
+
171
+ ## License
172
+
173
+ MIT
@@ -0,0 +1,6 @@
1
+ import type { ReactNode } from 'react';
2
+ type RequireAuthProps = {
3
+ children: ReactNode;
4
+ };
5
+ declare const RequireAuth: ({ children }: RequireAuthProps) => import("react/jsx-runtime").JSX.Element | null;
6
+ export { RequireAuth };
package/dist/guard.js ADDED
@@ -0,0 +1,24 @@
1
+ import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
2
+ import { useEffect, useRef } from 'react';
3
+ import { useAuditAuth } from './provider';
4
+ const RequireAuth = ({ children }) => {
5
+ const { ready, isAuthenticated, login } = useAuditAuth();
6
+ const startedRef = useRef(false);
7
+ const authed = isAuthenticated();
8
+ useEffect(() => {
9
+ if (!ready)
10
+ return;
11
+ if (authed)
12
+ return;
13
+ if (startedRef.current)
14
+ return;
15
+ startedRef.current = true;
16
+ login();
17
+ }, [ready, authed, login]);
18
+ if (!ready)
19
+ return null;
20
+ if (!authed)
21
+ return null;
22
+ return _jsx(_Fragment, { children: children });
23
+ };
24
+ export { RequireAuth };
@@ -0,0 +1,2 @@
1
+ export * from './provider';
2
+ export * from './guard';
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export * from './provider';
2
+ export * from './guard';
@@ -0,0 +1,20 @@
1
+ import type { ReactNode } from 'react';
2
+ import type { AuditAuthConfig, SessionUser } from '@auditauth/core';
3
+ import { AuditAuthWeb } from '@auditauth/web';
4
+ type AuditAuthContextValue = {
5
+ ready: boolean;
6
+ user: SessionUser | null;
7
+ fetch: AuditAuthWeb['fetch'];
8
+ login: () => Promise<void>;
9
+ logout: () => Promise<void>;
10
+ goToPortal: () => Promise<void>;
11
+ isAuthenticated: () => boolean;
12
+ trackNavigationPath: (path: string) => void;
13
+ };
14
+ type AuditAuthProviderProps = {
15
+ config: AuditAuthConfig;
16
+ children: ReactNode;
17
+ };
18
+ declare const AuditAuthProvider: ({ config, children }: AuditAuthProviderProps) => import("react/jsx-runtime").JSX.Element;
19
+ declare const useAuditAuth: () => AuditAuthContextValue;
20
+ export { AuditAuthProvider, useAuditAuth, };
@@ -0,0 +1,114 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { createContext, useContext, useEffect, useMemo, useRef, useState } from 'react';
4
+ import { AuditAuthWeb } from '@auditauth/web';
5
+ const AuditAuthContext = createContext(null);
6
+ const createSdk = (config) => {
7
+ const safeStorage = {
8
+ get: (name) => {
9
+ if (typeof window === 'undefined')
10
+ return null;
11
+ return localStorage.getItem(name);
12
+ },
13
+ set: (name, value) => {
14
+ if (typeof window === 'undefined')
15
+ return;
16
+ localStorage.setItem(name, value);
17
+ },
18
+ remove: (name) => {
19
+ if (typeof window === 'undefined')
20
+ return;
21
+ localStorage.removeItem(name);
22
+ },
23
+ };
24
+ return new AuditAuthWeb(config, safeStorage);
25
+ };
26
+ const AuditAuthProvider = ({ config, children }) => {
27
+ const sdkRef = useRef(null);
28
+ const [ready, setReady] = useState(false);
29
+ const [user, setUser] = useState(null);
30
+ if (!sdkRef.current) {
31
+ sdkRef.current = createSdk(config);
32
+ }
33
+ const sdk = sdkRef.current;
34
+ useEffect(() => {
35
+ let mounted = true;
36
+ const init = async () => {
37
+ try {
38
+ await sdk.handleRedirect();
39
+ const sessionUser = sdk.getSessionUser();
40
+ if (!mounted)
41
+ return;
42
+ setUser(sessionUser);
43
+ }
44
+ catch {
45
+ if (!mounted)
46
+ return;
47
+ setUser(null);
48
+ }
49
+ finally {
50
+ if (!mounted)
51
+ return;
52
+ setReady(true);
53
+ }
54
+ };
55
+ init();
56
+ return () => {
57
+ mounted = false;
58
+ };
59
+ }, [sdk]);
60
+ useEffect(() => {
61
+ if (typeof window === 'undefined')
62
+ return;
63
+ const handler = (event) => {
64
+ if (event.key !== '__auditauth_sync__')
65
+ return;
66
+ const sessionUser = sdk.getSessionUser();
67
+ setUser(sessionUser);
68
+ };
69
+ window.addEventListener('storage', handler);
70
+ return () => {
71
+ window.removeEventListener('storage', handler);
72
+ };
73
+ }, [sdk]);
74
+ const logout = useMemo(() => {
75
+ return async () => {
76
+ await sdk.logout();
77
+ setUser(null);
78
+ localStorage.setItem('__auditauth_sync__', Date.now().toString());
79
+ };
80
+ }, [sdk]);
81
+ const fetchWrapper = useMemo(() => {
82
+ return async (...args) => {
83
+ try {
84
+ const res = await sdk.fetch(...args);
85
+ return res;
86
+ }
87
+ catch (err) {
88
+ setUser(null);
89
+ throw err;
90
+ }
91
+ };
92
+ }, [sdk]);
93
+ const value = useMemo(() => {
94
+ return {
95
+ ready,
96
+ user,
97
+ fetch: fetchWrapper,
98
+ login: sdk.login.bind(sdk),
99
+ logout,
100
+ goToPortal: sdk.goToPortal.bind(sdk),
101
+ isAuthenticated: () => !!user,
102
+ trackNavigationPath: sdk.trackNavigationPath.bind(sdk),
103
+ };
104
+ }, [ready, user, sdk, logout, fetchWrapper]);
105
+ return (_jsx(AuditAuthContext.Provider, { value: value, children: children }));
106
+ };
107
+ const useAuditAuth = () => {
108
+ const ctx = useContext(AuditAuthContext);
109
+ if (!ctx) {
110
+ throw new Error('useAuditAuth must be used inside AuditAuthProvider');
111
+ }
112
+ return ctx;
113
+ };
114
+ export { AuditAuthProvider, useAuditAuth, };
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "@auditauth/react",
3
+ "version": "0.2.0-beta.1",
4
+ "description": "AuditAuth React SDK",
5
+ "license": "MIT",
6
+ "author": "Nimibyte",
7
+ "engines": {
8
+ "node": ">=18.18.0"
9
+ },
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "https://github.com/nimibyte/auditauth-sdk.git"
13
+ },
14
+ "homepage": "https://docs.auditauth.com",
15
+ "bugs": {
16
+ "url": "https://github.com/nimibyte/auditauth-sdk/issues"
17
+ },
18
+ "keywords": [
19
+ "authentication",
20
+ "auth",
21
+ "oauth",
22
+ "identity",
23
+ "jwt",
24
+ "security",
25
+ "auditauth"
26
+ ],
27
+ "module": "dist/index.js",
28
+ "type": "module",
29
+ "main": "dist/index.js",
30
+ "types": "dist/index.d.ts",
31
+ "files": [
32
+ "dist"
33
+ ],
34
+ "sideEffects": false,
35
+ "exports": {
36
+ ".": {
37
+ "types": "./dist/index.d.ts",
38
+ "default": "./dist/index.js"
39
+ },
40
+ "./package.json": "./package.json"
41
+ },
42
+ "scripts": {
43
+ "build": "tsc -p tsconfig.build.json",
44
+ "dev": "tsc -p tsconfig.build.json --watch",
45
+ "clean": "rm -rf dist"
46
+ },
47
+ "peerDependencies": {
48
+ "react": ">=18",
49
+ "react-dom": ">=18"
50
+ },
51
+ "dependencies": {
52
+ "@auditauth/web": "^0.2.0-beta.1"
53
+ },
54
+ "devDependencies": {
55
+ "@types/react": "^18.2.0",
56
+ "@types/react-dom": "^18.2.0"
57
+ }
58
+ }