Intégration provider
Générer vos clés, les enregistrer, vérifier les jetons utilisateurs.
Comment un fournisseur branche son backend sur Yeria, de bout en bout : clés, authentification, profils utilisateurs. Deux esquisses de langage ; un seul protocole.
Le SDK fournit des helpers, pas du middleware. Vous les câblez dans votre propre couche d'authentification (middleware Express, dépendance FastAPI, handler Total.js…). Il n'existe pas de YeriaApp.authMiddleware() et il n'en existera jamais : l'intégration au framework reste votre choix.
Où se situe votre backend
Yeria est un registre et un fournisseur d'identité, pas un proxy. Une fois que l'application mobile a résolu votre service, elle parle directement à votre URL. Yeria ne voit jamais ce trafic.
1[Mobile] ── discovers service ──> [Yeria] (catalog, review, signing keys)
2[Mobile] ── mints service JWT ──> [Yeria] (POST /user/service-token)
3[Mobile] ── Bearer <serviceJWT> ─> [Your backend] ← all real trafficVotre backend doit donc être joignable en HTTPS depuis les appareils des utilisateurs, et vérifier lui-même chaque jeton entrant. C'est l'objet de cette page.
Les deux systèmes de clés
| Clé | Algorithme | Détenteur | Rôle |
|---|---|---|---|
| Clé de plateforme Yeria | RSA (RS256) | Yeria | Signe les jetons utilisateurs que vous recevez. Vous ne faites que vérifier avec elle ; le SDK la récupère et la met en cache par son kid. |
| Clé de votre service | Ed25519 | Vous | Signe les enveloppes de vue que vous renvoyez et vos appels vers Yeria. La moitié publique est enregistrée sur votre service Yeria ; la privée ne quitte jamais votre backend. |
Générer une paire RSA pour votre service est une erreur : le registre refuse tout ce qui n'est pas Ed25519.
1. Générer la paire de clés du service
1# Private key — PKCS#8 PEM. Keep it out of git.
2openssl genpkey -algorithm ed25519 -out service_private.pem
3
4# Public key — SPKI PEM. This is what you paste into Yeria.
5openssl pkey -in service_private.pem -pubout -out service_public.pemEn Node, si vous préférez :
1import { generateKeyPairSync } from 'node:crypto';
2
3const { privateKey, publicKey } = generateKeyPairSync('ed25519');
4const privatePem = privateKey.export({ type: 'pkcs8', format: 'pem' });
5const publicPem = publicKey.export({ type: 'spki', format: 'pem' });La clé publique ressemble à ceci — une courte ligne base64, parce qu'une clé Ed25519 fait 32 octets :
1-----BEGIN PUBLIC KEY-----
2MCowBQYDK2VwAyEA14UIHuc98YQOnlD+EB8BIT2zbEzPJipRvXtcQifZ+jE=
3-----END PUBLIC KEY-----La clé privée est l'identité de votre service. Ne la committez jamais, ne l'envoyez jamais à Yeria, ne la placez jamais dans un build mobile. Quiconque la détient peut signer des vues et des appels en votre nom. En cas de fuite, effectuez une rotation immédiate.
2. Enregistrer la clé publique
Collez le PEM public dans le champ clé publique du fournisseur de votre service, depuis l'espace fournisseur Yeria (Services → votre service → Modifier). Yeria le stocke dans son registre de clés et s'en sert pour vérifier tout ce que vous signez.
Sur un service déjà validé par une revue Yeria, changer la clé est une modification du registre : elle est mise en brouillon et appliquée à la validation de la revue. La rotation d'urgence suit un chemin distinct — voir Rotation de clés plus bas.
3. Configurer votre backend
| Variable d'environnement | Rôle |
|---|---|
YERIA_BASE_URL | Par exemple https://yeria.app. La barre oblique finale est facultative. |
YERIA_APP_ID | Identifiant de votre application ; transporté dans chaque charge utile signée. |
YERIA_SERVICE_ID | Identifiant de votre service dans Yeria. Sert à épingler l'audience du jeton. |
SERVICE_ED25519_PRIVATE_KEY | PEM de la clé privée générée à l'étape 1. |
Cycle de vie d'une requête
1[Mobile] -- Bearer <serviceJWT> --> [Provider backend]
2 |
3 | 1. app.verifyUserToken(bearer, SERVICE_ID)
4 | (signature math; key cached after first hit)
5 |
6 | 2. cache miss? app.fetchUserDetails(...)
7 | (signs an envelope, POSTs to Yeria)
8 |
9 | 3. your handler logic
10 v
11 [YeriaUI builds a view → app.serve(view)]L'étape 1 est le chemin chaud : aucun appel réseau une fois la clé de signature en cache. L'étape 2 ne se déclenche qu'au premier appel par utilisateur, puis plus jamais — persistez le profil par sub et servez-le localement ensuite.
JavaScript / TypeScript
1import express from 'express';
2import {
3 YeriaUI,
4 YeriaApp,
5 SignatureVerificationError,
6 ViewExpiredError,
7 YeriaPlatformUnreachableError,
8} from '@numerum-tech/yeriasdk';
9
10const SERVICE_ID = process.env.YERIA_SERVICE_ID!;
11
12// One instance: it signs views, verifies inbound tokens, and talks to Yeria.
13// The public key is derived from the private key — no need to pass it.
14const app = new YeriaApp({
15 appId: process.env.YERIA_APP_ID!,
16 baseUrl: process.env.YERIA_BASE_URL!,
17 privateKey: process.env.SERVICE_ED25519_PRIVATE_KEY!,
18});
19
20// Your own middleware — NOT shipped by the SDK.
21async function requireYeriaUser(
22 req: express.Request,
23 res: express.Response,
24 next: express.NextFunction,
25) {
26 const auth = req.headers.authorization ?? '';
27 const bearer = auth.toLowerCase().startsWith('bearer ') ? auth.slice(7).trim() : '';
28 if (!bearer) return res.status(401).json({ error: 'missing token' });
29
30 try {
31 // Resolves the token's `kid` against Yeria through an internal cached
32 // key store, enforces iss='yeria', exp > now, and aud = our service.
33 (req as any).yeriaUser = await app.verifyUserToken(bearer, SERVICE_ID);
34 (req as any).yeriaToken = bearer;
35 next();
36 } catch (err) {
37 if (err instanceof ViewExpiredError) return res.status(401).json({ error: 'token expired' });
38 if (err instanceof SignatureVerificationError) return res.status(401).json({ error: 'invalid token' });
39 // Yeria unreachable — the token may well be fine. Do not 401.
40 if (err instanceof YeriaPlatformUnreachableError) return res.status(503).json({ error: 'yeria unreachable' });
41 return res.status(500).json({ error: 'auth error' });
42 }
43}
44
45const server = express();
46server.use('/secure', requireYeriaUser);
47
48server.get('/secure/home', async (req, res) => {
49 const claims = (req as any).yeriaUser;
50
51 // Cache miss → fetch from Yeria once, persist locally.
52 let user = await db.users.findByYeriaSub(claims.sub);
53 if (!user) {
54 const details = await app.fetchUserDetails({
55 userServiceToken: (req as any).yeriaToken,
56 });
57 user = await db.users.insert({ yeria_sub: claims.sub, ...details });
58 }
59
60 const view = YeriaUI.createReaderView('home', `Bonjour ${user.first_name}`)
61 .addParagraph('Votre espace personnel.');
62
63 res.json(app.serve(view));
64});Python
1import os
2from yeriasdk import YeriaApp, YeriaAppConfig, YeriaUI
3from yeriasdk.errors.exceptions import SignatureVerificationError, ViewExpiredError
4
5SERVICE_ID = os.environ["YERIA_SERVICE_ID"]
6
7app = YeriaApp(YeriaAppConfig(
8 app_id=os.environ["YERIA_APP_ID"],
9 base_url=os.environ["YERIA_BASE_URL"],
10 private_key=os.environ["SERVICE_ED25519_PRIVATE_KEY"],
11))
12
13# FastAPI dependency — written by you, NOT shipped by the SDK.
14from fastapi import Depends, Header, HTTPException
15
16async def require_yeria_user(authorization: str = Header(default="")):
17 if not authorization.lower().startswith("bearer "):
18 raise HTTPException(401, "missing token")
19 bearer = authorization[7:].strip()
20 try:
21 claims = app.verify_user_token(bearer, SERVICE_ID)
22 return claims, bearer
23 except ViewExpiredError:
24 raise HTTPException(401, "token expired")
25 except SignatureVerificationError:
26 raise HTTPException(401, "invalid token")
27
28@app.get("/secure/home")
29async def home(auth = Depends(require_yeria_user)):
30 claims, bearer = auth
31
32 user = db.users.find_by_yeria_sub(claims.sub)
33 if user is None:
34 details = app.fetch_user_details(user_service_token=bearer)
35 user = db.users.insert(yeria_sub=claims.sub, **dataclasses.asdict(details))
36
37 view = (YeriaUI.create_reader_view("home", f"Bonjour {user.first_name}")
38 .add_paragraph("Votre espace personnel."))
39 return app.serve(view)Persistence model
Répliquez le sub de Yeria dans votre propre table d'utilisateurs. Il est stable pendant toute la vie du compte Yeria de l'utilisateur, et c'est le seul champ garanti présent dans chaque jeton de service.
1CREATE TABLE users (
2 id BIGSERIAL PRIMARY KEY,
3 yeria_sub TEXT UNIQUE NOT NULL,
4 first_name TEXT,
5 last_name TEXT,
6 country_code CHAR(2),
7 email TEXT,
8 fetched_at TIMESTAMPTZ NOT NULL DEFAULT now(),
9 -- your own provider-specific fields below
10 ...
11);
12CREATE INDEX users_yeria_sub_idx ON users (yeria_sub);La politique de rafraîchissement vous appartient : une durée de validité sur fetched_at, ou une action explicite « actualiser depuis Yeria » dans votre écran de réglages.
Rotation de clés
La clé de Yeria tourne selon son propre calendrier. L'ancienne reste valide pendant une courte période de grâce, puis cesse d'être résolue. Le magasin de clés interne du SDK suit le kid présent dans l'en-tête de chaque jeton : vous n'avez rien à faire.
Votre clé tourne lorsque vous appelez app.rotateKey(...), ou depuis le formulaire d'édition du service. La clé précédente continue de vérifier pendant une période de grâce de 5 minutes, afin que les requêtes en cours survivent au basculement.
Ce qui n'est PAS dans le corps
Les appels signés par le fournisseur (fetchUserDetails, rotation de clé) ne transportent jamais de jeton porteur dans le corps. Le justificatif est la signature Ed25519 de l'enveloppe, produite avec votre clé enregistrée.
Erreurs — aide-mémoire
| Erreur du SDK | Cause probable | Réponse HTTP adaptée |
|---|---|---|
SignatureVerificationError | Mauvaise clé, jeton falsifié, ou clé à laquelle Yeria ne fait plus confiance | 401 |
ViewExpiredError | exp est dans le passé | 401 |
YeriaPlatformUnreachableError | Yeria est hors service ou injoignable — le jeton lui-même est peut-être valide | 503 |
| Échec de récupération du profil | Identifiant de service mal configuré, enveloppe rejouée, ou clé refusée par Yeria | 502 / 503 |
| Forme de réponse inattendue | Yeria a fait évoluer le format de transport et votre SDK est plus ancien | Mettez le SDK à jour |
Renvoyez vos erreurs au mobile via app.serveError({ code, message, status }) pour qu'elles arrivent signées — voir YeriaUI & YeriaApp.
Voir aussi
- YeriaUI & YeriaApp — toute la surface d'API
- Spécifications des composants — tous les types de vue
- Notifications — règles d'abonnement et erreurs de distribution