Authentification

Cliqer s'authentifie au moyen d'un cookie de session httpOnly (session_token), émis par POST /api/auth/login. Les navigateurs l'envoient automatiquement à chaque requête ; les outils de serveur à serveur le conservent dans un cookie jar. Les équipes Studio 8K et Enterprise peuvent en outre créer des clés API pour l'accès de serveur à serveur, envoyées sous la forme Authorization: Bearer cliqer_<key> ; voir Authentification par clé API ci-dessous.
Modèle de session
| Identifiant | Emplacement | Mode d'obtention |
|---|---|---|
Cookie de session (session_token) | Cookie httpOnly et Secure sur votre hôte Cliqer | Défini par POST /api/auth/login, renouvelé automatiquement par le serveur |
Le cookie est HttpOnly : il n'est donc pas lisible depuis JavaScript. Sa durée de vie suit le TTL de la session côté serveur et il est renouvelé de façon transparente chaque fois que vous appelez GET /api/auth/me. Il n'existe pas d'endpoint de rafraîchissement distinct à appeler : pour qu'un client de longue durée reste correctement connecté, il suffit d'appeler GET /api/auth/me périodiquement.
Cycle de vie de la session
Utiliser la session
Les navigateurs joignent le cookie automatiquement. Pour les clients de serveur à serveur, conservez le cookie défini par la réponse de connexion et envoyez-le avec les requêtes suivantes :
# 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?;
Authentification par clé API
Les équipes Studio 8K et Enterprise peuvent créer des clés API de longue durée pour l'accès de serveur à serveur, une alternative à la conservation des identifiants de connexion d'un utilisateur. Créez-les et révoquez-les dans le tableau de bord, sous Équipe → Clés API (/dash/team/api-keys) ; leur création est réservée au propriétaire de l'équipe (ou à un rôle personnalisé disposant de l'autorisation sur les clés API). La gestion des clés est disponible uniquement avec les formules Studio 8K et Enterprise.


Une clé n'est affichée qu'une seule fois, à sa création, au format cliqer_<prefix>_<secret>. Conservez-la en lieu sûr : elle ne peut pas être récupérée, donc en cas de perte, révoquez-la et créez-en une nouvelle. Envoyez-la en tant que jeton Bearer sur tout endpoint REST qui accepte une session :
curl -X GET "$BASE_URL/api/licenses/status?license_key=YOUR_LICENSE_KEY" \
-H "Authorization: Bearer cliqer_ab12cd34_your_secret_here"
Les clés API fonctionnent uniquement sur les endpoints REST. Le WebSocket, y compris le contrôle des diapositives, nécessite un jeton de session.
La clé s'authentifie en tant que l'utilisateur qui l'a créée, dans le périmètre de l'équipe et de la formule de cet utilisateur. Une clé révoquée ou inconnue renvoie 401, exactement comme une session absente. Les endpoints réservés aux administrateurs rejettent toujours les clés API avec 403. Les clés sont soumises aux mêmes limites de débit que les requêtes de session.
Connexion
Échangez les identifiants d'un utilisateur contre une session. En cas de succès, la réponse définit le cookie session_token.
Endpoint : POST /api/auth/login
| Paramètre | Type | Obligatoire | Description |
|---|---|---|---|
email | string | Oui | E-mail de l'utilisateur (un nom d'utilisateur WordPress est également accepté) |
password | string | Oui | Mot de passe de l'utilisateur |
otp | string | Non | Code TOTP, lorsque le compte utilise une application d'authentification |
email_otp | string | Non | Code PIN reçu par e-mail, lorsque le compte utilise la 2FA par 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?;
Réponse (succès) : définit le cookie session_token et renvoie les métadonnées de la session.
{
"data": {
"expires": 604800000
}
}
Réponse (2FA requise) : un signal de contrôle de flux 200, et non une erreur. Renvoyez POST /api/auth/login avec les mêmes identifiants, accompagnés de otp (application d'authentification) ou de email_otp (code PIN reçu par e-mail).
{
"requires_otp": true,
"method": "totp",
"email_sent": false
}
method vaut totp, email ou both. Pour email, le serveur envoie un code PIN par e-mail et email_sent indique si cet e-mail a bien été envoyé. Un compte both se connecte avec son code d'authentification (otp) ; le code PIN reçu par e-mail ne constitue pas un facteur de connexion pour ce compte.
401, tout comme un code TOTP erroné ou expiré. Un code PIN reçu par e-mail erroné ou expiré renvoie également 401, avec le même message qu'un mot de passe erroné. Un membre d'une organisation qui impose l'authentification unique reçoit 403 et doit se connecter via SSO (voir la FAQ SSO).Renouvellement de la session
Il n'existe pas d'endpoint de rafraîchissement distinct. Le serveur renouvelle le cookie session_token pour vous : lorsqu'une session est suffisamment proche de son expiration, GET /api/auth/me répond avec un nouveau Set-Cookie en plus du profil. Un client qui conserve un cookie jar et appelle GET /api/auth/me périodiquement reste connecté indéfiniment, sans aucun travail supplémentaire.
Utilisateur actuel
Renvoie le profil de l'utilisateur authentifié, ou { "data": null } en l'absence de session valide (compatible avec les accès anonymes, jamais de 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?;
Réponse :
{
"data": {
"id": "uuid",
"email": "user@example.com",
"first_name": "Jane",
"last_name": "Doe",
"role": "uuid",
"tfa_method": "none",
"is_admin": false
}
}
Déconnexion
Met fin à la session associée au cookie actuel et efface ce dernier du navigateur.
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?;
Réponse :
{
"success": true
}
Bonnes pratiques de sécurité
- Utilisez uniquement HTTPS : le cookie de session est
Secure; toutes les requêtes doivent utiliser TLS 1.2+. - Ne lisez jamais le cookie depuis JavaScript : il est
HttpOnlypar conception ; conservez ce fonctionnement. - Renouvelez de manière proactive : appelez
GET /api/auth/meavant l'expiration de la session sur les onglets ouverts longtemps ; le serveur renouvelle le cookie pour vous. - Déconnectez-vous pour révoquer :
POST /api/auth/logoutmet immédiatement fin à la session côté serveur. - Stockez des identifiants, pas des sessions : les intégrations de serveur à serveur doivent conserver les identifiants de connexion dans un gestionnaire de secrets et rétablir une session, sans jamais stocker le cookie dans le code source.