Uwierzytelnianie

Cliqer uwierzytelnia za pomocą ciasteczka sesji httpOnly (session_token), tworzonego przez POST /api/auth/login. Przeglądarki wysyłają je automatycznie przy każdym żądaniu, a narzędzia server-to-server przechowują je w magazynie ciasteczek (cookie jar). Zespoły Studio 8K i Enterprise mogą dodatkowo tworzyć klucze API do dostępu server-to-server, wysyłane jako Authorization: Bearer cliqer_<key>, zobacz Uwierzytelnianie kluczem API poniżej.
Model sesji
| Poświadczenie | Gdzie się znajduje | Jak je uzyskać |
|---|---|---|
Ciasteczko sesji (session_token) | Ciasteczko httpOnly i Secure na Twoim hoście Cliqer | Ustawiane przez POST /api/auth/login, automatycznie rotowane przez serwer |
Ciasteczko ma flagę HttpOnly, więc nie da się go odczytać z JavaScriptu. Jego czas życia odpowiada TTL sesji na serwerze i jest odnawiany w tle za każdym razem, gdy wywołujesz GET /api/auth/me. Nie ma osobnego endpointu odświeżania: aby długo działający klient zachowywał się poprawnie, wystarczy okresowo wywoływać GET /api/auth/me.
Cykl życia sesji
Korzystanie z sesji
Przeglądarki dołączają ciasteczko automatycznie. W klientach server-to-server zapisz ciasteczko ustawione przez odpowiedź na logowanie i wysyłaj je w kolejnych żądaniach:
# Save the session cookie on login, then reuse it
curl -X POST "$BASE_URL/api/auth/login" \
-H "Content-Type: application/json" \
-c cookies.txt \
-d '{"email":"user@example.com","password":"your_password"}'
curl -X GET "$BASE_URL/api/auth/me" -b cookies.txt
// Same-origin $fetch sends the httpOnly cookie automatically.
// Cross-origin fetch must opt in with credentials: 'include'.
const me = await $fetch('/api/auth/me')
import requests
session = requests.Session() # persists the session cookie
session.post('$BASE_URL/api/auth/login',
json={'email': 'user@example.com', 'password': 'your_password'})
me = session.get('$BASE_URL/api/auth/me').json()
jar, _ := cookiejar.New(nil)
client := &http.Client{Jar: jar}
// Login stores the session cookie in the jar; later requests reuse it.
client.Post("$BASE_URL/api/auth/login", "application/json", body)
resp, _ := client.Get("$BASE_URL/api/auth/me")
$ch = curl_init('$BASE_URL/api/auth/login');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_COOKIEJAR, 'cookies.txt');
curl_setopt($ch, CURLOPT_COOKIEFILE, 'cookies.txt');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
'email' => 'user@example.com', 'password' => 'your_password'
]));
curl_exec($ch);
// reqwest with cookie_store persists the session cookie across calls
let client = reqwest::Client::builder()
.cookie_store(true)
.build()?;
client.post("$BASE_URL/api/auth/login")
.json(&serde_json::json!({"email": "user@example.com", "password": "your_password"}))
.send().await?;
let me = client.get("$BASE_URL/api/auth/me").send().await?;
Uwierzytelnianie kluczem API
Zespoły Studio 8K i Enterprise mogą tworzyć długoterminowe klucze API do dostępu server-to-server, co pozwala nie przechowywać danych logowania użytkownika. Tworzysz je i unieważniasz w panelu, w sekcji Zespół → Klucze API (/dash/team/api-keys). Do utworzenia klucza potrzebny jest właściciel zespołu (lub rola niestandardowa z uprawnieniem do kluczy API). Zarządzanie kluczami jest dostępne wyłącznie w planach Studio 8K i Enterprise.


Klucz jest wyświetlany tylko raz, podczas tworzenia, w formacie cliqer_<prefix>_<secret>. Przechowuj go w bezpiecznym miejscu: nie da się go odzyskać, więc jeśli go zgubisz, unieważnij go i utwórz nowy. Wysyłaj go jako token Bearer do dowolnego endpointu REST, który akceptuje sesję:
curl -X GET "$BASE_URL/api/licenses/status?license_key=YOUR_LICENSE_KEY" \
-H "Authorization: Bearer cliqer_ab12cd34_your_secret_here"
Klucze API działają tylko z endpointami REST. WebSocket, łącznie ze sterowaniem slajdami, wymaga tokenu sesji.
Klucz uwierzytelnia jako użytkownik, który go utworzył, w zakresie zespołu i planu tego użytkownika. Unieważniony lub nieznany klucz zwraca 401, dokładnie tak jak brak sesji. Endpointy dostępne tylko dla administratorów zawsze odrzucają klucze API z kodem 403. Klucze podlegają tym samym limitom żądań co żądania z sesją.
Logowanie
Wymień dane logowania użytkownika na sesję. Po udanym logowaniu odpowiedź ustawia ciasteczko session_token.
Endpoint: POST /api/auth/login
| Parametr | Typ | Wymagany | Opis |
|---|---|---|---|
email | string | Tak | Adres e-mail użytkownika (akceptowana jest też nazwa użytkownika WordPress) |
password | string | Tak | Hasło użytkownika |
otp | string | Nie | Kod TOTP, gdy konto korzysta z aplikacji uwierzytelniającej |
email_otp | string | Nie | PIN wysłany e-mailem, gdy konto korzysta z 2FA przez e-mail |
curl -X POST "$BASE_URL/api/auth/login" \
-H "Content-Type: application/json" \
-c cookies.txt \
-d '{"email":"user@example.com","password":"your_password"}'
interface LoginResponse {
data: {
expires: number | null // session lifetime in ms
}
}
const res: LoginResponse = await $fetch('/api/auth/login', {
method: 'POST',
body: { email: 'user@example.com', password: 'your_password' }
})
// The session_token cookie is set by the response; no token is in the body.
import requests
session = requests.Session()
data = {'email': 'user@example.com', 'password': 'your_password'}
res = session.post('$BASE_URL/api/auth/login', json=data)
# The session cookie now lives in `session`.
jar, _ := cookiejar.New(nil)
client := &http.Client{Jar: jar}
payload := map[string]string{"email": "user@example.com", "password": "your_password"}
body, _ := json.Marshal(payload)
client.Post("$BASE_URL/api/auth/login", "application/json", bytes.NewBuffer(body))
$ch = curl_init('$BASE_URL/api/auth/login');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_COOKIEJAR, 'cookies.txt');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
'email' => 'user@example.com',
'password' => 'your_password'
]));
$response = curl_exec($ch);
use serde::Serialize;
#[derive(Serialize)]
struct LoginRequest { email: String, password: String }
let client = reqwest::Client::builder().cookie_store(true).build()?;
let response = client
.post("$BASE_URL/api/auth/login")
.json(&LoginRequest { email: "user@example.com".into(), password: "your_password".into() })
.send()
.await?;
Odpowiedź (sukces): ustawia ciasteczko session_token i zwraca metadane sesji.
{
"data": {
"expires": 604800000
}
}
Odpowiedź (wymagane 2FA): sygnał sterujący przepływem z kodem 200, a nie błąd. Wyślij ponownie POST /api/auth/login z tymi samymi danymi logowania oraz polem otp (aplikacja uwierzytelniająca) lub email_otp (PIN z e-maila).
{
"requires_otp": true,
"method": "totp",
"email_sent": false
}
method przyjmuje jedną z wartości: totp, email lub both. W przypadku email serwer wysyła PIN e-mailem, a email_sent informuje, czy ta wiadomość została wysłana. Konto z metodą both loguje się kodem z aplikacji uwierzytelniającej (otp). PIN wysłany e-mailem nie jest dla niego składnikiem logowania.
401, podobnie jak błędny lub wygasły kod TOTP. Błędny lub wygasły PIN z e-maila również zwraca 401 z tym samym komunikatem co błędne hasło. Członek organizacji, która wymaga logowania jednokrotnego, otrzymuje 403 i musi zalogować się przez SSO (zobacz FAQ dotyczące SSO).Rotacja sesji
Nie ma osobnego endpointu odświeżania. Serwer rotuje ciasteczko session_token za Ciebie: gdy sesja zbliża się do wygaśnięcia, GET /api/auth/me zwraca razem z profilem nowy nagłówek Set-Cookie. Klient, który przechowuje ciasteczka i okresowo wywołuje GET /api/auth/me, pozostaje zalogowany bezterminowo, bez żadnej dodatkowej pracy.
Bieżący użytkownik
Zwraca profil uwierzytelnionego użytkownika lub { "data": null }, gdy nie ma ważnej sesji (obsługuje wywołania anonimowe i nigdy nie zwraca 401).
Endpoint: GET /api/auth/me
curl -X GET "$BASE_URL/api/auth/me" -b cookies.txt
const { data } = await $fetch('/api/auth/me')
if (data) console.log(data.email, data.is_admin)
me = session.get('$BASE_URL/api/auth/me').json()
resp, _ := client.Get("$BASE_URL/api/auth/me")
$ch = curl_init('$BASE_URL/api/auth/me');
curl_setopt($ch, CURLOPT_COOKIEFILE, 'cookies.txt');
$response = curl_exec($ch);
let me = client.get("$BASE_URL/api/auth/me").send().await?;
Odpowiedź:
{
"data": {
"id": "uuid",
"email": "user@example.com",
"first_name": "Jane",
"last_name": "Doe",
"role": "uuid",
"tfa_method": "none",
"is_admin": false
}
}
Wylogowanie
Kończy sesję powiązaną z bieżącym ciasteczkiem i usuwa je z przeglądarki.
Endpoint: POST /api/auth/logout
curl -X POST "$BASE_URL/api/auth/logout" -b cookies.txt -c cookies.txt
await $fetch('/api/auth/logout', { method: 'POST' })
session.post('$BASE_URL/api/auth/logout')
req, _ := http.NewRequest("POST", "$BASE_URL/api/auth/logout", nil)
client.Do(req)
$ch = curl_init('$BASE_URL/api/auth/logout');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_COOKIEFILE, 'cookies.txt');
curl_exec($ch);
client.post("$BASE_URL/api/auth/logout").send().await?;
Odpowiedź:
{
"success": true
}
Najlepsze praktyki bezpieczeństwa
- Używaj wyłącznie HTTPS: ciasteczko sesji ma flagę
Secure, a wszystkie żądania muszą korzystać z TLS 1.2+. - Nigdy nie odczytuj ciasteczka z JavaScriptu: ma flagę
HttpOnlycelowo i niech tak zostanie. - Odświeżaj z wyprzedzeniem: w długo otwartych kartach wywołuj
GET /api/auth/meprzed wygaśnięciem sesji, a serwer sam zrotuje ciasteczko. - Wyloguj się, aby unieważnić sesję:
POST /api/auth/logoutnatychmiast kończy sesję po stronie serwera. - Przechowuj dane logowania, nie sesje: integracje server-to-server powinny trzymać dane logowania w menedżerze sekretów i na nowo nawiązywać sesję. Nigdy nie zapisuj ciasteczka w kodzie źródłowym.