@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 CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@arcote.tech/arc-auth",
3
3
  "type": "module",
4
- "version": "0.7.24",
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.24",
14
- "@arcote.tech/platform": "^0.7.24",
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
  },
@@ -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
+ }