Outils pour utilisateurs

Outils du site


web:javascript:jwt

Ceci est une ancienne révision du document !


JSON Web Token

Le JSON Web Token (JWT, prononcé jot) est un standard d'authentification.

http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html

Packages node

Outils

Spécifications

JWT

JWKS

Structure

Payload

iss Issuer
sub Subject
exp Expiration

JOSE

Clé privée

Générer la clé privée:

$ openssl genrsa -out rsa-2048.pem 2048

Une clé de longueur 2048 bits semble suffisante jusqu'en 2030. Sinon utiliser 3072 ou 4096.

Avec ssh-keygen:

ssh-keygen -t rsa -b 4096 -m PEM -f jwtRS256.key
# Don't add passphrase
openssl rsa -in jwtRS256.key -pubout -outform PEM -out jwtRS256.key.pub
cat jwtRS256.key
cat jwtRS256.key.pub

Créer un JWT

const privateKey = readFileSync('./path/to/rsa-2048.pem');

const rsaKey = JWK.asKey(privateKey);

const payload = {
  'urn:example:claim': 'foo'
};

const token = JWT.sign(payload, rsaKey, {
  algorithm: 'RS256',
  audience: ['urn:example:client'],
  issuer: 'https://op.example.com',
  expiresIn: '2 hours',
  header: {
    typ: 'JWT'
  }
});

Créer le endpoint JWKS

Quand on importe la clé privée RSA, on peut demander la clé publique:

const privateKey = readFileSync('./path/to/rsa-2048.pem');

const rsaKey = JWK.asKey(privateKey);

const publicKey = JSON.stringify(rsaKey.toJWK());

Ce qui donne quelque chose de ce genre:

{
  "e":"AQAB",
  "n":"5ColF8Lypyud9iKJjOeaTG7yP-KxdJ...9FMDEBQ",
  "kty":"RSA",
  "kid":"O06jlZQ_2JW0UXF6qvbMIFdaXFNnIoKHS9aVbv5-Mvc"
} 

Et comme on le veut dans un set (JWKS), on peut faire ceci:

{
  "keys": [
    {
      "e":"AQAB",
      "n":"5ColF8Lypyud9iKJjOeaTG7yP-KxdJ...9FMDEBQ",
      "kty":"RSA",
      "kid":"O06jlZQ_2JW0UXF6qvbMIFdaXFNnIoKHS9aVbv5-Mvc"
    }
  ]
}

On peut ajouter la propriété “alg”: “RS256”,, mais n'est pas nécessaire pour valider la signature plus tard.

Validation avec JWKS

Pour importer les fonctions nécessaires de jose:

import { JWK, JWT, JWKS } from 'jose';

On récupère les clés publiques via un endpoint JWKS, normalement sous une URL /.well-known/jwks.json.

const jwksEndpoint = 'https://c1058d53fc6f.ngrok.io/.well-known/jwks.json'; // Exemple d'URL de JWKS

const { data } = await axios.get<JWKSKeys>(
  jwksEndpoint,
);

const jwksKeys = data;

Interface de JWKSKeys:

export interface JWKSKeys {
  keys: [
    {
      kty: string;
      e: string;
      use?: string;
      kid: string;
      alg?: string;
      n: string;
    }
  ]
}

On transforme le data reçu en clés jose:

const rsaKeys = jwksKeys.keys.map((key) => JWK.asKey(key));
const keystore = new JWKS.KeyStore(rsaKeys);

Ensuite la validation en donnant le keystore.

let tokenVerification: TokenPayload;

try {
  tokenDecoded = JWT.verify(payload.jwt, keystore) as TokenPayload;
} catch (e) {
  console.error('Token Verification failed.', e);
}

console.log(tokenDecoded);

Le TokenPayload dépend de ce qu'on veut mettre dans le payload du JWT, ceci est un exemple:

export interface TokenPayload {
  name: string;
  nickname: string;
  picture: string;
  email: string;
  // eslint-disable-next-line camelcase
  email_verified: boolean;
}

jwks-rsa

Exemple d’utilisation de JWKS-RSA.

import * as jwksClient from 'jwks-rsa';
 
// *** skipped code ***
 
const client = jwksClient({
  strictSsl: true, // Default value
  jwksUri: 'https://7426c678d401.ngrok.io/.well-known/jwks.json',
});
 
const kid = 'id12345';
 
const agetSigningKey = promisify(client.getSigningKey).bind(client);
 
return agetSigningKey(kid);

Ressources

web/javascript/jwt.1594993712.txt.gz · Dernière modification : 2022/02/02 00:43 (modification externe)