Pyxaura Pyxaura

Guide — Appairage d'un appareil mobile (OAuth 2.1 PKCE)

Flux nominal (Universal Links)

App mobile → Navigateur système → Page web Pyxaura → App mobile → API token

1. Générer PKCE + paramètres

// Swift
import CryptoKit, Foundation

let codeVerifier  = Data(UUID().uuidString.utf8 + UUID().uuidString.utf8)
  .base64EncodedString()
  .replacingOccurrences(of: "+", with: "-")
  .replacingOccurrences(of: "/", with: "_")
  .replacingOccurrences(of: "=", with: "")
let codeChallenge = Data(SHA256.hash(data: Data(codeVerifier.utf8)))
  .base64EncodedString()
  .replacingOccurrences(of: "+", with: "-")
  .replacingOccurrences(of: "/", with: "_")
  .replacingOccurrences(of: "=", with: "")
let state         = UUID().uuidString
let deviceId      = UIDevice.current.identifierForVendor?.uuidString ?? UUID().uuidString
// Kotlin
import java.security.MessageDigest
import java.util.Base64, UUID

val codeVerifier  = Base64.getUrlEncoder().withoutPadding()
  .encodeToString(UUID.randomUUID().toString().toByteArray())
val digest        = MessageDigest.getInstance("SHA-256").digest(codeVerifier.toByteArray())
val codeChallenge = Base64.getUrlEncoder().withoutPadding().encodeToString(digest)
val state         = UUID.randomUUID().toString()
val deviceId      = /* Settings.Secure.ANDROID_ID ou identifiant persisté */

2. Ouvrir le navigateur système

GET https://pyxaura.com/oauth/authorize?
  client_id=mobile_ios
  &redirect_uri=https://votre-app.com/app/callback
  &response_type=code
  &code_challenge=<codeChallenge>
  &code_challenge_method=S256
  &state=<state>
  &device_id=<deviceId>
  &device_name=iPhone+de+Tony
  &device_platform=ios
  &scope=user:profile+user:spaces+user:query+user:chat

iOS : ASWebAuthenticationSession
Android : Chrome Custom Tabs

3. Recevoir le callback

L'app reçoit https://votre-app.com/app/callback?code=ac_...&state=<state>.

Vérifier que state correspond à celui envoyé (anti-CSRF).

4. Échanger le code contre des tokens

curl -X POST https://pyxaura.com/api/v1/auth/token \
  -H "Content-Type: application/json" \
  -d '{
    "grant_type": "authorization_code",
    "client_id": "mobile_ios",
    "code": "ac_...",
    "code_verifier": "<codeVerifier>",
    "redirect_uri": "https://votre-app.com/app/callback",
    "device_id": "<deviceId>"
  }'
{
  "token_type": "Bearer",
  "access_token": "eyJhbGciOiJFUzI1NiIsImtpZCI6...",
  "expires_in": 900,
  "refresh_token": "rt_...",
  "refresh_token_expires_in": 5184000,
  "device": { "id": "dev_31", "name": "iPhone de Tony", "platform": "ios" },
  "user": { "id": "usr_17", "name": "Tony", "email": "tony@example.com", "plan": "pro" },
  "spaces": [{ "id": "spc_9f2", "name": "Projet Alpha" }]
}

Stocker : access_token en mémoire, refresh_token dans Keychain (iOS) / EncryptedSharedPreferences + Keystore (Android). Jamais en localStorage.

5. Rafraîchir le token

L'access token expire après 15 minutes. Rafraîchir avant chaque appel ou à la réception d'un 401 :

curl -X POST https://pyxaura.com/api/v1/auth/token \
  -H "Content-Type: application/json" \
  -d '{
    "grant_type": "refresh_token",
    "client_id": "mobile_ios",
    "refresh_token": "rt_...",
    "device_id": "<deviceId>"
  }'

⚠️ Rotation systématique : chaque rafraîchissement invalide le précédent refresh_token. Un rejeu révoque immédiatement l'appareil.

6. Appeler l'API avec le JWT

curl https://pyxaura.com/api/v1/spaces/spc_9f2/query \
  -H "Authorization: Bearer <access_token>" \
  -H "Content-Type: application/json" \
  -d '{"question": "Quel est le délai de retour ?"}'

7. Révoquer l'appareil

# Depuis l'app
curl -X DELETE https://pyxaura.com/api/v1/devices/dev_31 \
  -H "Authorization: Bearer <access_token>"

# Tous les appareils (déconnexion complète)
curl -X POST "https://pyxaura.com/api/v1/auth/logout?all=true" \
  -H "Authorization: Bearer <access_token>"

Variante device_code (TV, CLI, borne, QR code)

# 1. Initier
curl -X POST https://pyxaura.com/api/v1/auth/device_authorization \
  -d '{"client_id":"mobile_ios","device_id":"<uuid>"}'
# → {"user_code":"PYX-4F7Q","verification_uri":"https://pyxaura.com/appareil","expires_in":600}

# 2. Afficher le QR code vers verification_uri_complete et le user_code
# 3. Poll toutes les 5 s
curl -X POST https://pyxaura.com/api/v1/auth/token \
  -d '{"grant_type":"urn:ietf:params:oauth:grant-type:device_code","client_id":"mobile_ios","device_code":"dc_..."}'
# → 400 {"error":"authorization_pending"} ou 200 avec tokens

Sécurité

  • PKCE S256 obligatoire — plain refusé.
  • Universal Links prioritaires sur le schéma privé pyxia:// (empêche l'interception).
  • WebViews embarquées refusées côté serveur.
  • Email d'alerte envoyé à chaque nouvel appairage approuvé avec lien de révocation.
  • Révocation immédiate via session_version : l'access token est invalidé en < 1 min après révocation de l'appareil.