@arcote.tech/arc-auth 0.7.24 → 0.7.25
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/package.json +3 -3
- package/src/auth-builder.ts +4 -1
- package/src/react/auth-provider.tsx +14 -2
- package/src/routes/logout-route.ts +28 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arcote.tech/arc-auth",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.7.
|
|
4
|
+
"version": "0.7.25",
|
|
5
5
|
"private": false,
|
|
6
6
|
"description": "Reusable authentication module for Arc framework — aggregate-based auth with factory pattern",
|
|
7
7
|
"main": "./src/index.ts",
|
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
"type-check": "tsc --noEmit"
|
|
11
11
|
},
|
|
12
12
|
"peerDependencies": {
|
|
13
|
-
"@arcote.tech/arc": "^0.7.
|
|
14
|
-
"@arcote.tech/platform": "^0.7.
|
|
13
|
+
"@arcote.tech/arc": "^0.7.25",
|
|
14
|
+
"@arcote.tech/platform": "^0.7.25",
|
|
15
15
|
"react": "^18.0.0 || ^19.0.0",
|
|
16
16
|
"typescript": "^5.0.0"
|
|
17
17
|
},
|
package/src/auth-builder.ts
CHANGED
|
@@ -12,6 +12,7 @@ import { createAccountId } from "./ids/account";
|
|
|
12
12
|
import { createOAuthIdentityId } from "./ids/oauth-identity";
|
|
13
13
|
import { createToken } from "./tokens/token";
|
|
14
14
|
import { createOAuthRoutes } from "./routes/oauth-routes";
|
|
15
|
+
import { createLogoutRoute } from "./routes/logout-route";
|
|
15
16
|
import type { AccountId } from "./ids/account";
|
|
16
17
|
import type { OAuthProvidersConfig } from "./providers/types";
|
|
17
18
|
import type { Token } from "./tokens/token";
|
|
@@ -86,8 +87,10 @@ export class AuthBuilder<
|
|
|
86
87
|
}
|
|
87
88
|
|
|
88
89
|
build() {
|
|
90
|
+
// Logout route zawsze obecny (niezależnie od OAuth) — czyści cookie sesji.
|
|
91
|
+
const logout = createLogoutRoute();
|
|
89
92
|
return {
|
|
90
|
-
context: context(this.elements),
|
|
93
|
+
context: context([...this.elements, logout]),
|
|
91
94
|
accountId: this.accountId,
|
|
92
95
|
token: this.token,
|
|
93
96
|
Account: this.Account,
|
|
@@ -13,7 +13,7 @@ export interface AuthContextType {
|
|
|
13
13
|
/** Resolves when the module loader has synced chunks for the new token —
|
|
14
14
|
* await before navigating to a token-gated route. */
|
|
15
15
|
setAccessToken: (token: string) => Promise<void>;
|
|
16
|
-
logout: () => void
|
|
16
|
+
logout: () => Promise<void>;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
const AuthContext = createContext<AuthContextType | null>(null);
|
|
@@ -60,7 +60,19 @@ export function AuthProvider({ children, onTokenChange, initialToken }: AuthProv
|
|
|
60
60
|
await onTokenChange?.(newToken);
|
|
61
61
|
};
|
|
62
62
|
|
|
63
|
-
const logout = () => {
|
|
63
|
+
const logout = async (): Promise<void> => {
|
|
64
|
+
// Najpierw serwerowo wygaś cookie `arc_token` (HttpOnly — JS go nie ruszy);
|
|
65
|
+
// bez tego serwer używałby go jako fallback (m.in. upgrade /ws) i sesja
|
|
66
|
+
// trwałaby po wylogowaniu. Best-effort: błąd sieci nie blokuje czyszczenia
|
|
67
|
+
// stanu klienta, żeby UI był wylogowany.
|
|
68
|
+
try {
|
|
69
|
+
await fetch("/route/auth/logout", {
|
|
70
|
+
method: "POST",
|
|
71
|
+
credentials: "include",
|
|
72
|
+
});
|
|
73
|
+
} catch {
|
|
74
|
+
/* offline / serwer niedostępny — i tak czyścimy stan lokalny */
|
|
75
|
+
}
|
|
64
76
|
setToken(null);
|
|
65
77
|
onTokenChange?.(null); // scope.setToken(null) → adapter clears this scope
|
|
66
78
|
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { route } from "@arcote.tech/arc";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Publiczny route wylogowania — wygasza serwerowe cookie sesji `arc_token`
|
|
5
|
+
* (ustawiane przez OAuth callback, Max-Age 7 dni). Symetryczny do logowania:
|
|
6
|
+
* skoro OAuth ustawia cookie, logout musi je czyścić serwerowo — JS nie ruszy
|
|
7
|
+
* HttpOnly cookie, a serwer używa go jako fallback dla każdego requestu (w tym
|
|
8
|
+
* upgrade'u `/ws`), więc bez tego po wylogowaniu sesja trwała dalej.
|
|
9
|
+
*
|
|
10
|
+
* Publiczny (logout nie może wymagać auth). Czyszczenie nieistniejącego cookie
|
|
11
|
+
* (login hasłem) jest no-opem. Atrybuty muszą pokrywać się z ustawieniem
|
|
12
|
+
* (Path=/) żeby przeglądarka dopasowała cookie do usunięcia.
|
|
13
|
+
*/
|
|
14
|
+
export function createLogoutRoute() {
|
|
15
|
+
return route("authLogout")
|
|
16
|
+
.path("/auth/logout")
|
|
17
|
+
.public()
|
|
18
|
+
.handle({
|
|
19
|
+
POST: async () => {
|
|
20
|
+
const headers = new Headers();
|
|
21
|
+
headers.append(
|
|
22
|
+
"Set-Cookie",
|
|
23
|
+
"arc_token=; HttpOnly; SameSite=Lax; Path=/; Max-Age=0",
|
|
24
|
+
);
|
|
25
|
+
return new Response(null, { status: 204, headers });
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
}
|