@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 +173 -0
- package/dist/guard.d.ts +6 -0
- package/dist/guard.js +24 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/provider.d.ts +20 -0
- package/dist/provider.js +114 -0
- package/package.json +58 -0
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
|
package/dist/guard.d.ts
ADDED
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 };
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -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, };
|
package/dist/provider.js
ADDED
|
@@ -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
|
+
}
|