@djangocfg/api 2.1.547 → 2.1.548
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 +25 -0
- package/dist/auth.cjs +8 -0
- package/dist/auth.cjs.map +1 -1
- package/dist/auth.d.cts +17 -2
- package/dist/auth.d.ts +17 -2
- package/dist/auth.mjs +8 -0
- package/dist/auth.mjs.map +1 -1
- package/package.json +2 -2
- package/src/auth/__tests__/guard.test.ts +65 -0
- package/src/auth/utils/guard.ts +27 -1
- package/src/auth/utils/index.ts +1 -0
package/README.md
CHANGED
|
@@ -77,6 +77,31 @@ import {
|
|
|
77
77
|
} from '@djangocfg/api/auth';
|
|
78
78
|
```
|
|
79
79
|
|
|
80
|
+
### Guard resolvers
|
|
81
|
+
|
|
82
|
+
The "spinner vs redirect vs render" decision is pure and separately testable.
|
|
83
|
+
`useAuthGuard` (and `@djangocfg/layouts`' `PrivateLayout`) just wire React state
|
|
84
|
+
into these:
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
import {
|
|
88
|
+
resolveGuardIsLoading, // show the preloader?
|
|
89
|
+
shouldRedirectToAuth, // no session → send to the auth form
|
|
90
|
+
isForbidden, // signed in, but lacks the required privilege
|
|
91
|
+
resolveGuardIsAuthenticated,
|
|
92
|
+
type GuardInput,
|
|
93
|
+
} from '@djangocfg/api/auth';
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
`GuardInput` takes two optional fields for the role gate: `requireStaff` (the
|
|
97
|
+
route needs staff/admin) and `isAdminUser` (from `useAuth()` — the
|
|
98
|
+
`is_staff || is_superuser` fold, never one flag).
|
|
99
|
+
|
|
100
|
+
`isForbidden` is deliberately **not** a redirect condition: the session is
|
|
101
|
+
valid, so the auth form cannot fix it, and redirecting would loop on the saved
|
|
102
|
+
URL. Render a distinct "not authorised" state instead. `resolveGuardIsLoading`
|
|
103
|
+
returns `false` once forbidden, so the preloader never spins on it.
|
|
104
|
+
|
|
80
105
|
## Token storage & DPoP
|
|
81
106
|
|
|
82
107
|
The token lives in the shared `auth` store (localStorage by default, switchable
|
package/dist/auth.cjs
CHANGED
|
@@ -50,6 +50,7 @@ __export(auth_exports, {
|
|
|
50
50
|
getCachedProfile: () => getCachedProfile,
|
|
51
51
|
hasValidCache: () => hasValidCache,
|
|
52
52
|
isAllowedAuthPath: () => isAllowedAuthPath,
|
|
53
|
+
isForbidden: () => isForbidden,
|
|
53
54
|
logger: () => logger,
|
|
54
55
|
normalizePath: () => normalizePath,
|
|
55
56
|
peekSavedRedirect: () => peekSavedRedirect,
|
|
@@ -5210,9 +5211,16 @@ var formatAuthError = /* @__PURE__ */ __name((error) => {
|
|
|
5210
5211
|
}, "formatAuthError");
|
|
5211
5212
|
|
|
5212
5213
|
// src/auth/utils/guard.ts
|
|
5214
|
+
function isForbidden(s) {
|
|
5215
|
+
return Boolean(
|
|
5216
|
+
s.mounted && s.requireAuth && s.requireStaff && !s.authLoading && s.isAuthenticated && !s.isAdminUser
|
|
5217
|
+
);
|
|
5218
|
+
}
|
|
5219
|
+
__name(isForbidden, "isForbidden");
|
|
5213
5220
|
function resolveGuardIsLoading(s) {
|
|
5214
5221
|
if (!s.mounted) return true;
|
|
5215
5222
|
if (!s.requireAuth) return false;
|
|
5223
|
+
if (isForbidden(s)) return false;
|
|
5216
5224
|
return s.authLoading || s.isRedirecting || !s.isAuthenticated;
|
|
5217
5225
|
}
|
|
5218
5226
|
__name(resolveGuardIsLoading, "resolveGuardIsLoading");
|