Przejdź do treści

Express

Sprawdzanie tokenu dostępu we własnym API — middleware, uprawnienia i trzy odpowiedzi, jakie może mieć odmowa.

Druga połowa każdej strony w tej sekcji: przeglądarka ma token, a Twoje API musi zdecydować, co on znaczy. Weryfikacja jest offline — token to podpisany JWT, Twoje API sprawdza go względem zestawu kluczy publikowanego przez Twój issuer i nie pyta nas o nic przy każdym żądaniu.

npm install @kleora-io/node

Jedna zależność w czasie działania, biblioteka JOSE. Express i Fastify są opcjonalnymi peerami, więc paczka instaluje się bez obu.

1. Najpierw uwierzytelnienie, potem autoryzacja

import express from 'express'
import { express as kleora, requirePermission } from '@kleora-io/node'

const app = express()

app.use(
  kleora({
    issuer: process.env.KLEORA_ISSUER!,
    audience: 'https://api.example.com',
  }),
)

app.get('/invoices', requirePermission('invoices:read'), (req, res) => {
  res.json({ tenant: req.kleora.tenant })
})

Middleware weryfikuje token i ustawia req.kleora na jego claimy. requirePermission czyta req.kleora.permissions — a te są już w tokenie, więc sprawdzenie kosztuje tyle, co przejrzenie listy, a nie zapytanie do nas.

2. Co podać jako audience

Claim aud tokenu dostępu to [client_id], a po ustawieniu na środowisku własnego api_audience — [client_id, api_audience]. Świeże środowisko nie ma go wcale, więc dopóki go nie ustawisz, podawaj identyfikator klienta, a potem własny identyfikator API.

3. Trzy odpowiedzi, jakie może mieć odmowa

SytuacjaOdpowiedź
Brak nagłówka Authorization albo token, który się nie zweryfikował401, dokument problemu unauthenticated
Token poprawny, ale brakuje uprawnienia403 insufficient-permission
Zestawu kluczy issuera w ogóle nie da się odczytać503 issuer-unavailable

Treść 401 mówi tylko tyle, że żądanie nie zostało uwierzytelnione. Powód — token wygasł, zły audience, zły podpis — idzie do opcji logger, czyli tam, gdzie przydaje się Tobie, a nie temu, kto próbuje zgadywać. 503 znaczy więcej, niż wygląda: bez niego nasza awaria mówiłaby każdemu z Twoich użytkowników, że jego token jest zły, i odsyłała go do issuera, który i tak już leży.

Wszystko inne to Twoja usługa skonfigurowana źle, i paczka nie wybiera za Ciebie statusu: w Express dostaje to next(error) i odpowiada Twój własny handler błędów.

requirePermission odpowiada 401, a nie 403, kiedy req.kleora w ogóle nie ma — trasa, na której zabrakło middleware uwierzytelniającego, to nie problem z uprawnieniami.

4. Co dokładnie sprawdza weryfikator

Nagłówek typ równy at+jwt, podpis ES256 względem zestawu kluczy issuera, iss dokładnie, aud zawierające Twój audience, exp i iat z tolerancją 60 sekund oraz to, że claim env tokenu zgadza się ze skonfigurowanym issuerem — więc token z sandboksa nie zadowoli po cichu produkcyjnego API.

Zestaw kluczy pobierany jest raz na issuer i trzymany tak długo, jak mówi jego Cache-Control. kid, którego cache nie zna, wywołuje jedno ponowne pobranie, nie częściej niż raz na minutę; nieudane pobranie serwuje zapamiętany zestaw do dwukrotności jego TTL, a potem odmawia. Klucze podpisujące są publikowane, zanim zaczną być używane, więc rotacja w locie trafia na kid, który już jest w cache'u.

Fastify i cała reszta

fastify({ issuer, audience }) to ta sama wtyczka: dekoruje request.kleora i daje te same trzy odpowiedzi. Rejestruje się bez enkapsulacji, bo zarejestrowanie wtyczki uwierzytelniającej w korzeniu nigdy nie znaczy „tylko trasy wewnątrz tej wtyczki”.

Dla API w Pythonie to samo sprawdzenie i te same reguły ma kleora — opisuje je Instalacja SDK.