Paillasse/portail/resources/views/jetons-api.blade.php
Adam Belkacemi ecf3dfb21d ajoute l'API publique /api/v1 (bloc B, premier chantier)
Catalogue en lecture seule (labs, banque de quiz officielle, cours) -
choix d'Adam pour la première version, zéro donnée d'élève. Laravel
Sanctum, un jeton Bearer par développeur créé depuis /jetons-api (un
prof), portée catalogue:lire seulement. Quota par jeton (pas par
compte ni par IP) dans Redis via un limiteur nommé, 60 requêtes/minute.
Documentation : spécification OpenAPI 3.0 et page publique /api/docs.

Désactive /sanctum/csrf-cookie (config/sanctum.php) : l'API est en
jeton Bearer seulement, jamais en cookie de SPA.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-10-14 01:23:23 +02:00

48 lines
3.6 KiB
PHP

@extends('layouts.app')
@section('titre', 'Jetons de l\'API')
@section('contenu')
<div class="mx-auto max-w-2xl px-5 py-10">
<p class="font-mono text-sm font-semibold"><a href="{{ route('profil') }}" class="underline" style="color:var(--sy-muted)">← Mon profil</a></p>
<h1 class="mt-2 text-3xl font-extrabold" style="color:var(--sy-ink)">Jetons de l'API publique</h1>
<p class="mt-2 font-semibold" style="color:var(--sy-muted)">Un jeton donne accès en lecture au catalogue (labs, banque de quiz officielle, cours) via <code class="font-mono">/api/v1</code>. 60 requêtes par minute et par jeton.</p>
@if (session('jeton_cree'))
<div class="mt-6 rounded-2xl border p-5" style="border-color:#A63D2A;background:#fce8e6">
<p class="font-extrabold" style="color:var(--sy-ink)">Ton jeton (copie-le maintenant, il ne sera plus jamais affiché) :</p>
<p class="mt-2 break-all rounded-xl p-3 font-mono text-sm font-bold" style="background:var(--sy-surface);color:var(--sy-ink)">{{ session('jeton_cree') }}</p>
<p class="mt-2 text-sm font-semibold" style="color:var(--sy-muted)">À utiliser dans l'en-tête <code class="font-mono">Authorization: Bearer &lt;jeton&gt;</code>.</p>
</div>
@endif
<form action="{{ route('jetons-api.store') }}" method="post" class="mt-6 flex flex-wrap items-end gap-3 rounded-2xl border p-5" style="border-color:var(--sy-line);background:var(--sy-surface)">
@csrf
<label class="grid gap-1 font-bold" style="color:var(--sy-ink)">Nom du jeton<input name="nom" required maxlength="80" placeholder="Ex. : script de révision" class="rounded-xl border px-3 py-2 font-semibold" style="border-color:var(--sy-line);background:var(--sy-bg);color:var(--sy-ink)"></label>
<button type="submit" class="inline-flex h-11 items-center rounded-full px-5 font-bold text-white" style="background:var(--sy-blue)">Créer un jeton</button>
</form>
<section class="mt-8">
<h2 class="text-xl font-extrabold" style="color:var(--sy-ink)">Jetons actifs</h2>
@if ($jetons->isEmpty())
<p class="mt-3 font-semibold" style="color:var(--sy-muted)">Aucun jeton pour l'instant.</p>
@else
<ul class="mt-3 grid gap-2">
@foreach ($jetons as $jeton)
<li class="flex flex-wrap items-center justify-between gap-3 rounded-xl border p-3" style="border-color:var(--sy-line);background:var(--sy-surface)">
<span class="font-bold" style="color:var(--sy-ink)">{{ $jeton->name }}
<span class="font-mono text-xs font-semibold" style="color:var(--sy-muted)">· créé le {{ $jeton->created_at->translatedFormat('d/m/Y') }}@if($jeton->last_used_at) · utilisé le {{ $jeton->last_used_at->translatedFormat('d/m/Y') }}@endif</span>
</span>
<form action="{{ route('jetons-api.destroy', $jeton) }}" method="post" onsubmit="return confirm('Révoquer ce jeton ? Il arrêtera de fonctionner immédiatement.')">
@csrf
<button type="submit" class="font-bold underline" style="color:#A63D2A">Révoquer</button>
</form>
</li>
@endforeach
</ul>
@endif
</section>
<p class="mt-8 text-sm font-semibold" style="color:var(--sy-muted)">Documentation : <a href="{{ route('api.docs') }}" class="underline" style="color:var(--sy-blue)">/api/docs</a>.</p>
</div>
@endsection