# JWT

O pacote `@aziontech/jwt` é a biblioteca da Azion Lib para JSON Web Tokens (JWTs). As três funções dele assinam um payload em um token, verificam um token e retornam o payload dele, e decodificam um token sem conferir a assinatura. Elas não fazem chamadas de API e não precisam de token. Cada função retorna o resultado diretamente ou lança um erro.

Instale o pacote:

```bash
npm install @aziontech/jwt
```

Os exemplos desta página são módulos ES em TypeScript que usam `await` no nível superior, e eles rodam no Node.js. Eles importam tipos com `import type`, o que mantém os exemplos carregáveis quando as anotações de tipo são removidas.

---

## Chaves e algoritmos

O parâmetro `alg` de [sign](#sign) e [verify](#verify) indica o algoritmo de assinatura. O padrão dele é `HS256`. As declarações de tipo listam 13 valores: `HS256`, `HS384`, `HS512`, `RS256`, `RS384`, `RS512`, `PS256`, `PS384`, `PS512`, `ES256`, `ES384`, `ES512` e `EdDSA`.

Uma chave é uma [SignatureKey](#signaturekey): uma `string`, uma `JsonWebKey` ou uma `CryptoKey`. A chave que você passa depende do algoritmo:

- Com o padrão `HS256`, a chave é um segredo compartilhado. Assine e verifique com a mesma string.
- Um algoritmo assimétrico, como `RS256`, recebe uma `CryptoKey` ou uma `JsonWebKey`. Assine com a chave privada e verifique com a chave pública.

Este exemplo gera um par de chaves RSA com `crypto.subtle`, assina um token com `RS256`, exibe o cabeçalho do token e verifica o token com a chave pública:

```typescript
import { sign, verify } from '@aziontech/jwt';

// Asymmetric algorithms take a CryptoKey (or JsonWebKey): sign with the private key, verify with the public key
const { privateKey, publicKey } = (await crypto.subtle.generateKey(
  { name: 'RSASSA-PKCS1-v1_5', modulusLength: 2048, publicExponent: new Uint8Array([1, 0, 1]), hash: 'SHA-256' },
  true,
  ['sign', 'verify'],
)) as CryptoKeyPair;

const token = await sign({ userId: 123 }, privateKey, 'RS256');
console.log('header:', JSON.parse(atob(token.split('.')[0])));
console.log('verified payload:', await verify(token, publicKey, 'RS256'));
```

Saída:

```text
header: { alg: 'RS256', typ: 'JWT' }
verified payload: { userId: 123 }
```

---

## sign

Assina um payload e retorna o token.

```typescript
function sign(payload: JWTPayload, privateKey: SignatureKey, alg?: SignatureAlgorithm): Promise<string>;
```

| Parâmetro    | Tipo                                        | Obrigatório | Descrição                                                                                                         |
| ------------ | ------------------------------------------- | ----------- | ----------------------------------------------------------------------------------------------------------------- |
| `payload`    | [`JWTPayload`](#jwtpayload)                 | Sim         | Os claims a assinar.                                                                                              |
| `privateKey` | [`SignatureKey`](#signaturekey)             | Sim         | A chave que assina o token: o segredo compartilhado com `HS256`, ou a chave privada com um algoritmo assimétrico. |
| `alg`        | [`SignatureAlgorithm`](#signaturealgorithm) | Não         | O algoritmo de assinatura. Padrão: `HS256`.                                                                       |

Retorna uma promise que resolve para o token assinado. Um valor de `alg` fora da lista em [Chaves e algoritmos](#chaves-e-algoritmos) rejeita com `JwtAlgorithmNotImplemented`.

Este exemplo assina, com o padrão `HS256`, um payload que expira em uma hora:

```typescript
import { sign } from '@aziontech/jwt';
import type { JWTPayload } from '@aziontech/jwt';

const secret: string = 'your-secret-key'; // HS256 (the default) signs with a shared secret
const payload: JWTPayload = { userId: 123, exp: Math.floor(Date.now() / 1000) + 3600 }; // 1 hour expiration
sign(payload, secret).then((token: string) => console.log(token)); // Outputs the signed JWT
```

Saída:

```text
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjEyMywiZXhwIjoxNzkxMTI1NjA0fQ.mmn-otq04QJJHbUQvm_e7b0SvNUQI98CtypKEz58kDQ
```

---

## verify

Confere a assinatura e os claims de tempo de um token e retorna o payload dele.

```typescript
function verify(token: string, publicKey: SignatureKey, alg?: SignatureAlgorithm): Promise<JWTPayload>;
```

| Parâmetro   | Tipo                                        | Obrigatório | Descrição                                                                                                               |
| ----------- | ------------------------------------------- | ----------- | ----------------------------------------------------------------------------------------------------------------------- |
| `token`     | `string`                                    | Sim         | O token a verificar.                                                                                                    |
| `publicKey` | [`SignatureKey`](#signaturekey)             | Sim         | A chave que confere a assinatura: o segredo compartilhado com `HS256`, ou a chave pública com um algoritmo assimétrico. |
| `alg`       | [`SignatureAlgorithm`](#signaturealgorithm) | Não         | O algoritmo com que o token foi assinado. Padrão: `HS256`.                                                              |

Retorna uma promise que resolve para o [JWTPayload](#jwtpayload) de um token válido. A promise rejeita quando a assinatura não corresponde à chave, quando `exp` está no passado, quando `nbf` ou `iat` está no futuro, ou quando o token ou o cabeçalho dele não é válido. Cada caso tem o próprio nome de erro, listado em [Erros](#erros).

Este exemplo assina um token, verifica o token com o mesmo segredo e depois verifica o token com um segredo diferente:

```typescript
import { sign, verify } from '@aziontech/jwt';
import type { JWTPayload } from '@aziontech/jwt';

const secret: string = 'your-secret-key';
const token: string = await sign({ userId: 123, exp: Math.floor(Date.now() / 1000) + 3600 }, secret);

try {
  const payload: JWTPayload = await verify(token, secret);
  console.log(payload); // Outputs the payload if verification is successful
} catch (err) {
  console.error((err as Error).name, (err as Error).message);
}

try {
  await verify(token, 'another-secret');
} catch (err) {
  console.error((err as Error).name, (err as Error).message); // A wrong key rejects with JwtTokenSignatureMismatched
}
```

Saída:

```text
{ userId: 123, exp: 1791127003 }
JwtTokenSignatureMismatched token(eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjEyMywiZXhwIjoxNzkxMTI3MDAzfQ.myf2vixa4QI6GQCxHu6h5t3UpZwMya3J1UIr2W3d8pU) signature mismatched
```

---

## decode

Lê o cabeçalho e o payload de um token sem verificar a assinatura dele.

```typescript
function decode(token: string): { header: TokenHeader; payload: JWTPayload };
```

| Parâmetro | Tipo     | Obrigatório | Descrição              |
| --------- | -------- | ----------- | ---------------------- |
| `token`   | `string` | Sim         | O token a decodificar. |

Retorna um objeto com o [TokenHeader](#tokenheader) em `header` e o [JWTPayload](#jwtpayload) em `payload`. A função é síncrona. Uma string que não é um JWT lança `JwtTokenInvalid`. Como `decode` não confere a assinatura, use [verify](#verify) antes de confiar em um claim.

O pacote não exporta `TokenHeader`, então o exemplo deixa o TypeScript inferir o tipo do resultado:

```typescript
import { sign, decode } from '@aziontech/jwt';

const token: string = await sign({ userId: 123 }, 'your-secret-key');
const { header, payload } = decode(token); // decode does not verify the signature
console.log(header, payload); // Outputs the decoded header and payload
```

Saída:

```text
{ alg: 'HS256', typ: 'JWT' } { userId: 123 }
```

---

## Erros

Uma chamada que falha lança, ou rejeita com, um erro cujo `name` é um dos sete abaixo. As declarações de tipo listam essas classes de erro como exports, mas o pacote não as exporta em tempo de execução: um arquivo que importa uma delas para no carregamento. Diferencie os erros por `err.name`, como faz o exemplo de [verify](#verify). Para o erro de carregamento, consulte [Solucionar problemas da Azion Lib](/pt-br/documentacao/devtools/azion-lib/solucao-de-problemas/#uma-importacao-de-classe-de-erro-jwt-falha-com-does-not-provide-an-export-named).

Nas mensagens abaixo, `<token>` representa o token que a chamada recebeu.

| Nome                          | Mensagem                                                                     | Causa                                                                | O que fazer                                                                       |
| ----------------------------- | ---------------------------------------------------------------------------- | -------------------------------------------------------------------- | --------------------------------------------------------------------------------- |
| `JwtAlgorithmNotImplemented`  | `none is not an implemented algorithm`                                       | O valor de `alg` não é um dos algoritmos que o pacote implementa.    | Passe um valor de [Chaves e algoritmos](#chaves-e-algoritmos).                    |
| `JwtTokenInvalid`             | `invalid JWT token: abc`                                                     | A string passada para `decode` ou `verify` não é um JWT.             | Passe um token completo, como `sign` o retorna.                                   |
| `JwtTokenNotBefore`           | `token (<token>) is being used before it's valid`                            | O claim `nbf` está no futuro.                                        | Verifique o token depois do horário em `nbf`.                                     |
| `JwtTokenExpired`             | `token (<token>) expired`                                                    | O claim `exp` está no passado.                                       | Assine um token novo com um `exp` posterior.                                      |
| `JwtTokenIssuedAt`            | `Incorrect "iat" claim must be a older than "<current-time>" (iat: "<iat>")` | O claim `iat` é posterior ao horário atual.                          | Assine o token com um `iat` que não esteja no futuro.                             |
| `JwtHeaderInvalid`            | `jwt header is invalid: {"alg":"HS256","typ":"XYZ"}`                         | O cabeçalho do token não é válido, como um `typ` diferente de `JWT`. | Assine o token com `sign`, que escreve `typ: 'JWT'`.                              |
| `JwtTokenSignatureMismatched` | `token(<token>) signature mismatched`                                        | A chave não corresponde à chave que assinou o token.                 | Verifique com o mesmo segredo, ou com a chave pública do par que assinou o token. |

---

## Tipos

O pacote exporta um tipo, `JWTPayload`. Importe-o com `import type`. Os outros três tipos abaixo são declarados pelo pacote, mas não são exportados, então você não pode importá-los.

### JWTPayload

Os claims de um token. Os horários são timestamps Unix, em segundos.

```typescript
type JWTPayload = {
  [key: string]: unknown;
  exp?: number;
  nbf?: number;
  iat?: number;
};
```

| Propriedade     | Tipo      | Obrigatório | Descrição                                                                                              |
| --------------- | --------- | ----------- | ------------------------------------------------------------------------------------------------------ |
| `[key: string]` | `unknown` | Não         | Um claim personalizado, como `userId`.                                                                 |
| `exp`           | `number`  | Não         | O horário de expiração do token. Depois dele, [verify](#verify) rejeita com `JwtTokenExpired`.         |
| `nbf`           | `number`  | Não         | O horário antes do qual o token não é válido. Antes dele, `verify` rejeita com `JwtTokenNotBefore`.    |
| `iat`           | `number`  | Não         | O horário em que o token foi emitido. Um valor no futuro faz `verify` rejeitar com `JwtTokenIssuedAt`. |

### TokenHeader

O cabeçalho que [decode](#decode) retorna.

```typescript
interface TokenHeader {
  alg: SignatureAlgorithm;
  typ?: 'JWT';
}
```

| Propriedade | Tipo                                        | Obrigatório | Descrição                        |
| ----------- | ------------------------------------------- | ----------- | -------------------------------- |
| `alg`       | [`SignatureAlgorithm`](#signaturealgorithm) | Sim         | O algoritmo que assinou o token. |
| `typ`       | `'JWT'`                                     | Não         | O tipo do token.                 |

### SignatureAlgorithm

Os nomes de algoritmo que `sign` e `verify` recebem em `alg`. Para os 13 valores, consulte [Chaves e algoritmos](#chaves-e-algoritmos).

```typescript
type SignatureAlgorithm = 'HS256' | 'HS384' | 'HS512' | 'RS256' | 'RS384' | 'RS512' | 'PS256' | 'PS384' | 'PS512' | 'ES256' | 'ES384' | 'ES512' | 'EdDSA';
```

### SignatureKey

A chave que `sign` e `verify` recebem.

```typescript
type SignatureKey = string | JsonWebKey | CryptoKey;
```

---

## Recursos relacionados

- [Azion Lib](/pt-br/documentacao/devtools/azion-lib.md): As bibliotecas que a Azion Lib oferece e o pacote que contém cada uma.
- [Como a Azion Lib funciona](/pt-br/documentacao/devtools/azion-lib/como-funciona.md): Quais módulos chamam uma API, quais lançam erros e onde cada um roda.
- [Solucionar problemas da Azion Lib](/pt-br/documentacao/devtools/azion-lib/solucao-de-problemas.md): Correções para os erros de carregamento e de execução que os pacotes da Azion Lib retornam.
- [SubtleCrypto](/pt-br/documentacao/devtools/runtime/api-reference/subtle-crypto.md): Os métodos de crypto.subtle que geram e importam chaves.
