Przejdź do treści

Zwykła przeglądarka

Jedna instancja klienta, jedna trasa powrotna i token dostępu do każdego żądania, które wysyła Twoja aplikacja.

Dla aplikacji jednostronicowej bez naszego modułu: Vite i czysty TypeScript, React, Svelte, Solid albo framework, o którym nigdy nie słyszeliśmy. @kleora-io/browser to klient authorization code z PKCE i nie wie nic o Twoim frameworku.

npm install @kleora-io/browser

Bez zależności w czasie działania, wyłącznie moduły ES.

1. Utwórz klienta raz

Jedna instancja na całą aplikację, we własnym module. Druga instancja to najprostszy sposób, by dwie połowy tej samej strony miały dwa różne zdania o tym, kto jest zalogowany.

// src/kleora.ts
import { createKleora } from '@kleora-io/browser'

export const kleora = createKleora({
  issuer: import.meta.env.VITE_KLEORA_ISSUER,
  clientId: import.meta.env.VITE_KLEORA_CLIENT_ID,
  redirectUri: location.origin + '/callback',
  storage: 'session',
})

issuer, clientId i redirectUri są wymagane; reszta ma wartości domyślne. scope to domyślnie openid profile email offline_access — zostaw w nim offline_access, bo inaczej nie zostanie wydany token odświeżania i nic nie odnowi się po cichu.

2. Obsłuż powrót

Issuer odsyła przeglądarkę na /callback z kodem autoryzacyjnym. Wymień go tam i odstaw człowieka tam, skąd wyszedł:

import { kleora } from './kleora'

if (location.pathname === '/callback') {
  const { appState } = await kleora.handleRedirectCallback()
  const returnTo = (appState as { returnTo?: string })?.returnTo ?? '/'
  history.replaceState(null, '', returnTo)
}

handleRedirectCallback() sprawdza state i iss, wymienia kod z użyciem weryfikatora PKCE, weryfikuje ID token względem zestawu kluczy issuera, zapisuje tokeny i usuwa dane logowania z paska adresu.

Twój serwer deweloperski musi oddawać HTML aplikacji także pod /callback, nie tylko pod /. Serwer deweloperski Vite robi to dla nieznanych ścieżek sam; zwykły serwer plików statycznych nie robi i odpowiada 404 na jedyną nawigację, która ma tu znaczenie.

3. Zaloguj i wiedz, kiedy jesteś zalogowany

if (!(await kleora.checkSession())) {
  await kleora.loginWithRedirect({ returnTo: location.pathname })
}

const user = kleora.getUser() // sub, email, name, tenant, tenant_slug…

checkSession() próbuje po kolei: świeżego tokenu z pamięci, zapisanego tokenu odświeżania, a dopiero na końcu cichego prompt=none w ukrytej ramce. returnTo przechodzi przez przekierowanie i wraca jako appState.returnTo — czyli dokładnie to, co czyta krok 2.

Zamiast odpytywać stan, można na niego reagować:

const unsubscribe = kleora.onAuthChange(({ user, isAuthenticated }) => {
  render(isAuthenticated ? user : null)
})

Jest jeszcze kleora.hasLikelySession(), które mówi, czy ta przeglądarka dokończyła kiedyś logowanie, po którym nie było wylogowania. To podpowiedź do renderowania — pozwala pokazać szkielet interfejsu zamiast mignięcia ekranem logowania, kiedy weryfikacja jeszcze trwa. Nigdy nie jest decyzją autoryzacyjną ani dowodem żywej sesji; dowodem jest tylko checkSession() albo udane wywołanie API.

4. Wołaj własne API

const token = await kleora.getAccessToken()

await fetch('/api/invoices', {
  headers: { Authorization: `Bearer ${token}` },
})

getAccessToken() oddaje token z pamięci, dopóki do wygaśnięcia zostało więcej niż 30 sekund, a potem odświeża; równoległe wywołania dzielą jedno odświeżenie. Tokeny odświeżania rotują przy każdym użyciu. Jeśli Twoje API odpowie 401 na token, w który ten klient wciąż wierzy, ponów raz z getAccessToken({ force: true }) — to wyrzuca token z pamięci, zamiast wysyłać po raz drugi ten sam odrzucony.

Sprawdzanie tego tokenu opisuje strona o Express — albo verify_access_token, jeśli Twoje API jest w Pythonie.

5. Wyloguj

await kleora.logout({ returnTo: location.origin + '/' })

returnTo jest wymagane i musi być jednym z zarejestrowanych adresów po wylogowaniu, porównywanym dokładnie. Stan lokalny czyszczony jest przed jakimkolwiek pobraniem, więc wylogowanie kończy się lokalnie nawet wtedy, gdy issuer jest nieosiągalny.