Pornire rapidă
Bototeka funcționează cu orice bibliotecă OpenID Connect care acceptă Authorization Code și PKCE S256.
Creează o aplicație
Introdu numele serviciului, adresa de revenire și, opțional, sigla. Bototeka gestionează deja revenirile de la Google, Apple și Yandex.
Salvează datele de acces
Copiază Client ID și Client Secret. Secretul este afișat o singură dată.
Configurează OIDC
Furnizează bibliotecii issuer. Celelalte endpointuri sunt descoperite automat.
Testează autentificarea
Pornește autentificarea, verifică state și nonce, schimbă codul și creează o sesiune locală.
- Issuer
- https://bototeka.com/api
- Discovery URL
- https://bototeka.com/api/.well-known/openid-configuration
- Service API
- https://api.bototeka.com/api/identity/v1
- Exemplu de Redirect URI
- https://service.example/auth/callback
Verificarea conexiunii
Disponibil proprietarilor și administratorilor fără sold
Acest test verifică configurația Bototeka și disponibilitatea endpointului furnizorului. Autentificarea interactivă a utilizatorului se testează separat.
Deschide setările OAuthAutentificare și tokenuri
Serverul tău generează PKCE, state și nonce, trimite utilizatorul la Bototeka și primește doar un cod de autorizare cu durată scurtă.
import { createHash, randomBytes } from "node:crypto";
const clientId = process.env.BOTOTEKA_CLIENT_ID;
if (!clientId) throw new Error("BOTOTEKA_CLIENT_ID is required");
const verifier = randomBytes(32).toString("base64url");
const challenge = createHash("sha256").update(verifier).digest("base64url");
const state = randomBytes(24).toString("base64url");
const nonce = randomBytes(24).toString("base64url");
const authorize = new URL("https://bototeka.com/api/oauth/authorize");
authorize.search = new URLSearchParams({
client_id: clientId,
redirect_uri: "https://service.example/auth/callback",
response_type: "code",
scope: "openid email profile",
code_challenge: challenge,
code_challenge_method: "S256",
state,
nonce,
}).toString();
// Save verifier, state and nonce in the user's server-side session.
console.log(authorize.toString());curl --request POST 'https://bototeka.com/api/oauth/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=authorization_code' \
--data-urlencode 'client_id=YOUR_CLIENT_ID' \
--data-urlencode 'client_secret=YOUR_CLIENT_SECRET' \
--data-urlencode 'code=CODE_FROM_CALLBACK' \
--data-urlencode 'redirect_uri=https://service.example/auth/callback' \
--data-urlencode 'code_verifier=SAVED_PKCE_VERIFIER'curl 'https://bototeka.com/api/oauth/userinfo' \
--header 'Authorization: Bearer ACCESS_TOKEN'Date de înregistrare prin API
Creează o cheie API în setările companiei și solicită clienții sau evenimentele aplicațiilor companiei tale.
/applications/{applicationId}/customersReturnează sub, emailul verificat, numele și momentele activității.
/applications/{applicationId}/eventsReturnează înregistrarea sau autentificarea, suma, moneda, starea și momentul evenimentului.
curl 'https://api.bototeka.com/api/identity/v1/applications/APPLICATION_ID/customers?limit=50' \
--header 'Authorization: Bearer btk_v1_YOUR_API_KEY'curl 'https://api.bototeka.com/api/identity/v1/applications/APPLICATION_ID/events?limit=50' \
--header 'Authorization: Bearer btk_v1_YOUR_API_KEY'Citirea necesită identity:read. Trimite cheia ca token Bearer și păstreaz-o pe server.
Evenimente webhook
Abonează-te în setările companiei. Adresa trebuie să folosească HTTPS. Secretul de semnare este afișat o singură dată.
identity.registration.completed.v1Înregistrarea s-a încheiat și a fost inclusă în jurnalul de utilizare.
identity.login.completed.v1Autentificarea repetată s-a încheiat și a fost inclusă în jurnalul de utilizare.
Livrarea are loc cel puțin o dată. Elimină duplicatele după event ID, acceptă evenimente în orice ordine și returnează 2xx numai după salvare.
import { createHmac, timingSafeEqual } from "node:crypto";
export function verifyBototekaWebhook(rawBody, headers, secret) {
const timestamp = headers["x-bototeka-webhook-timestamp"];
const received = headers["x-bototeka-webhook-signature"];
if (!timestamp || !received) return false;
if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;
const expected = "v1=" + createHmac("sha256", secret)
.update(timestamp + "." + rawBody)
.digest("hex");
const left = Buffer.from(expected);
const right = Buffer.from(received);
return left.length === right.length && timingSafeEqual(left, right);
}Verificări înainte de lansare
- Folosește un HTTPS Redirect URI exact. Nu accepta reveniri la adrese arbitrare.
- Generează state, nonce și PKCE verifier noi la fiecare încercare și păstrează-le într-o sesiune pe server.
- Nu stoca Client Secret, chei API, access token sau refresh token în browser ori în analiza mobilă.
- Solicită offline_access numai când serverul are nevoie de o sesiune de lungă durată.
- Verifică semnăturile webhook pe corpul brut al cererii și tratează sigur livrările repetate.
Erori și recuperare
invalid_requestCe s-a întâmplat
Un parametru obligatoriu lipsește sau este incorect.
Ce trebuie făcut
Verifică Redirect URI, PKCE, state, nonce și Content-Type.
invalid_grantCe s-a întâmplat
Codul a expirat, a fost folosit sau nu corespunde cu verifier.
Ce trebuie făcut
Pornește o autentificare nouă. Nu repeta schimbul aceluiași cod.
temporarily_unavailableCe s-a întâmplat
Soldul aplicației este insuficient.
Ce trebuie făcut
Alimentează soldul OAuth și pornește o autentificare nouă.
429Ce s-a întâmplat
A fost depășită limita de cereri sau de încercări de verificare.
Ce trebuie făcut
Respectă Retry-After și reîncearcă după o întârziere cu variație aleatorie.
| Cod | Ce s-a întâmplat | Ce trebuie făcut |
|---|---|---|
| invalid_request | Un parametru obligatoriu lipsește sau este incorect. | Verifică Redirect URI, PKCE, state, nonce și Content-Type. |
| invalid_grant | Codul a expirat, a fost folosit sau nu corespunde cu verifier. | Pornește o autentificare nouă. Nu repeta schimbul aceluiași cod. |
| temporarily_unavailable | Soldul aplicației este insuficient. | Alimentează soldul OAuth și pornește o autentificare nouă. |
| 429 | A fost depășită limita de cereri sau de încercări de verificare. | Respectă Retry-After și reîncearcă după o întârziere cu variație aleatorie. |
Întrebări și răspunsuri
Când se percepe plata?
După emiterea cu succes a tokenului. Prima sesiune este o înregistrare, iar cele ulterioare sunt autentificări. Încercările eșuate sau anulate, refresh, UserInfo și logout sunt gratuite.
Pot folosi doar emailul?
Da. Bototeka acceptă înregistrare prin email, coduri de unică folosință, verificarea adresei și recuperarea parolei fără furnizori sociali.
Pot conecta o aplicație SPA?
Da, ca public client cu PKCE și access token de scurtă durată păstrat în memorie. Pentru utilizare reală, se preferă un server sau un BFF cu sesiune HttpOnly.
Ce păstrez ca ID al clientului?
Păstrează perechea issuer și sub. Emailul se poate schimba și nu este un identificator stabil.
Cum schimb un secret?
Creează sau rotește cheia API în setările companiei. Copiază imediat noul secret, actualizează configurația serverului și revocă accesul vechi.