

# Suporte a CWT para o CloudFront Functions
<a name="cwt-support-cloudfront-functions"></a>

Esta seção apresenta detalhes sobre o suporte a CBOR Web Tokens (CWT) no CloudFront Functions, o que permite autenticação e autorização seguras baseadas em tokens nos locais da borda do CloudFront. Esse suporte é fornecido como um módulo, acessível em sua função do CloudFront. 

Para usar esse módulo, crie uma função do CloudFront usando o Runtime 2.0 do JavaScript e inclua a seguinte instrução na primeira linha do código da função: 

```
import cf from 'cloudfront';
```

Os métodos associados a este módulo podem ser acessados por meio de cf.cwt.\* (em que \* é um curinga representando as diferentes funções presentes no módulo):

```
cf.cwt.*
```

Para ter mais informações, consulte [Recursos de runtime 2.0 do JavaScript para CloudFront Functions](functions-javascript-runtime-20.md).

No momento, o módulo aceita apenas a estrutura MAC0 com o algoritmo HS256 (HMAC-SHA256), com um limite de 1 KB para o tamanho máximo do token.

## Estrutura do tokens
<a name="token-structure"></a>

Esta seção aborda a estrutura de tokens que é esperada pelo módulo CWT. O módulo espera que o token seja corretamente marcado e identificável (p. ex., COSE MAC0). Além disso, para a estrutura de tokens, o módulo segue os padrões definidos pela [CBOR Object Signing and Encryption (COSE) [RFC 8152](https://datatracker.ietf.org/doc/html/rfc8152)].

```
( // CWT Tag (Tag value: 61) --- optional    
    ( // COSE MAC0 Structure Tag (Tag value: 17) --- required        
        [            
            protectedHeaders,            
            unprotectedHeaders,            
            payload,            
            tag,        
        ]    
    )
)
```

**Example : CWT usando a estrutura COSE MAC0**  

```
61( // CWT tag     
    17( // COSE_MAC0 tag       
        [         
            { // Protected Headers           
                1: 4  // algorithm : HMAC-256-64         
            },         
            { // Unprotected Headers           
                4: h'53796d6d6574726963323536' // kid : Symmetric key id          
            },         
            { // Payload           
                1: "https://iss.example.com", // iss           
                2: "exampleUser", // sub           
                3: "https://aud.example.com", // aud           
                4: 1444064944, // exp           
                5: 1443944944, // nbf           
                6: 1443944944, // iat         
            },         
            h'093101ef6d789200' // tag       
        ]     
    )   
)
```
A tag CWT é opcional ao gerar tokens. No entanto, a tag da estrutura COSE é necessária.

## Método validateToken()
<a name="validatetoken-method"></a>

A função decodifica e valida um CWT usando a chave especificada. Se o comando tiver êxito, ela exibirá um CWT decodificado. Do contrário, gerará um erro. Observe que essa função não valida o conjunto de instruções.

### Solicitação
<a name="validatetoken-request"></a>

```
cf.cwt.validateToken(token, handlerContext{key})
```Parâmetros

**token (obrigatório)**  
Token codificado para validação. Deve ser um buffer em JavaScript.

**handlerContext (obrigatório)**  
Um objeto JavaScript que armazena o contexto para a chamada validateToken. No momento, somente a propriedade key é permitida.

**key (obrigatório)**  
Chave secreta para computação de resumo de mensagens. Pode ser fornecido como uma string ou como um buffer em JavaScript.

### Resposta
<a name="validatetoken-response"></a>

Quando o método `validateToken()` exibe um token validado com êxito, a resposta da função é um `CWTObject` no formato a seguir. Depois de decodificadas, todas as chaves de solicitação são representadas como strings.

```
CWTObject {    
    protectedHeaders,    
    unprotectedHeaders,    
    payload
}
```

### Exemplo: validar o token com kid enviado como parte do token
<a name="validatetoken-example"></a>

Este exemplo demonstra a validação de um CWT, em que kid (key ID) é extraído do cabeçalho. Em seguida, o kid é encaminhado ao KeyValueStore do CloudFront Functions para buscar a chave secreta usada para validar o token.

```
import cf from 'cloudfront'

const CwtClaims = {
   iss: 1,
   aud: 3,
   exp: 4
}

async function handler(event) {
    try {
        let request = event.request;
        let encodedToken = request.headers['x-cwt-token'].value;
        let kid = request.headers['x-cwt-kid'].value;
                
        // Retrieve the secret key from the kvs
        let secretKey = await cf.kvs().get(kid);
                 
        // Now you can use the secretKey to decode & validate the token.
        let tokenBuffer = Buffer.from(encodedToken, 'base64url');
                
        let handlerContext = {
           key: secretKey,
        }
                
        try {
            let cwtObj = cf.cwt.validateToken(tokenBuffer, handlerContext);
                        
            // Check if token is expired
            const currentTime = Math.floor(Date.now() / 1000); // Current time in seconds
            if (cwtObj[CwtClaims.exp] && cwtObj[CwtClaims.exp] < currentTime) {
                return {
                    statusCode: 401,
                    statusDescription: 'Token expired'
                };
            }
        } catch (error) {
            return {
               statusCode: 401,
               statusDescription: 'Invalid token'
            };
         }
    } catch (error) {
        return {
            statusCode: 402,
            statusDescription: 'Token processing failed'
        };
     }
    return request;
}
```

## Método generateToken()
<a name="generatetoken-method"></a>

Essa função gera um novo CWT usando a carga útil e as configurações de contexto fornecidas.

### Solicitação
<a name="generatetoken-request"></a>

```
cf.cwt.generateToken(generatorContext, payload)
```Parâmetros

**generatorContext (obrigatório)**  
Esse é um objeto JavaScript usado como contexto para gerar o token e contém os seguintes pares de chave-valor:    
**cwtTag (opcional)**  
Esse valor é um booliano que, se for `true`, especifica que `cwtTag` deve ser adicionado.  
**coseTag (obrigatório)**  
Especifica o tipo de tag COSE. No momento, oferece suporte apenas a `MAC0`.  
**key (obrigatório)**  
Chave secreta para computar resumo de mensagens. Esse valor pode ser uma string ou `Buffer` em JavaScript.

**payload (obrigatório)**  
Carga útil do token para codificação. A carga útil deve estar no seguinte formato `CWTObject`.

### Resposta
<a name="generatetoken-response"></a>

Exibe um buffer em JavaScript contendo o token codificado.

**Example : gerar um CWT**  

```
import cf from 'cloudfront';

const CwtClaims = {
    iss: 1,
    sub: 2,
    exp: 4
};

const CatClaims = {
    catu: 401,
    catnip: 402,
    catm: 403,
    catr: 404
};

const Catu = {
    host: 1,
    path: 2,
    ext: 3
};

const CatuMatchTypes = {
    prefix_match: 1,
    suffix_match: 2,
    exact_match: 3
};

const Catr = {
    renewal_method: 1,
    next_renewal_time: 2,
    max_uses: 3
};

async function handler(event) {
    try {
        const response = {
            statusCode: 200,
            statusDescription: 'OK',
            headers: {}
        };
        
        const commonAccessToken = {
            protected: {
                1: "5",
            },
            unprotected: {},
            payload: {
                [CwtClaims.iss]: "cloudfront-documentation",
                [CwtClaims.sub]: "cwt-support-on-cloudfront-functions",
                [CwtClaims.exp]: 1740000000,
                [CatClaims.catu]: {
                    [Catu.host]: {
                        [CatuMatchTypes.suffix_match]: ".cloudfront.net"
                    },
                    [Catu.path]: {
                        [CatuMatchTypes.prefix_match]: "/media/live-stream/cf-4k/"
                    },
                    [Catu.ext]: {
                        [CatuMatchTypes.exact_match]: [
                            ".m3u8",
                            ".ts",
                            ".mpd"
                        ]
                    }
                },
                [CatClaims.catnip]: [
                    "[IP_ADDRESS]",
                    "[IP_ADDRESS]"
                ],
                [CatClaims.catm]: [
                    "GET",
                    "HEAD"
                ],
                [CatClaims.catr]: {
                    [Catr.renewal_method]: "header_renewal",
                    [Catr.next_renewal_time]: 1750000000,
                    [Catr.max_uses]: 5
                }
            }
        };
        
        if (!request.headers['x-cwt-kid']) {
            throw new Error('Missing x-cwt-kid header');
        }
        
        const kid = request.headers['x-cwt-kid'].value;
        const secretKey = await cf.kvs().get(kid);
        
        if (!secretKey) {
            throw new Error('Secret key not found for provided kid');
        }
        
        try {
            const genContext = {
                cwtTag: true,
                coseTag: "MAC0",
                key: secretKey
            };
            
            const tokenBuffer = cf.cwt.generateToken(commonAccessToken, genContext);
            response.headers['x-generated-cwt-token'] = { value: tokenBuffer.toString('base64url') };
                        
            return response;
        } catch (tokenError) {
            return {
                statusCode: 401,
                statusDescription: 'Could not generate the token'
            };
        }
    } catch (error) {
        return {
            statusCode: 402,
            statusDescription: 'Token processing failed'
        };
    }
}
```

**Example : atualizar o token com base em alguma lógica**  

```
import cf from 'cloudfront'

const CwtClaims = {
   iss: 1,
   aud: 3,
   exp: 4
}

async function handler(event) {
    try {
        let request = event.request;
        let encodedToken = request.headers['x-cwt-token'].value;
        let kid = request.headers['x-cwt-kid'].value;
        let secretKey = await cf.kvs().get(kid); // Retrieve the secret key from the kvs
                
        // Now you can use the secretKey to decode & validate the token.
        let tokenBuffer = Buffer.from(encodedToken, 'base64url');
                
        let handlerContext = {
           key: secretKey,
        }
                
        try {
            let cwtJSON = cf.cwt.validateToken(tokenBuffer, handlerContext);
                        
            // Check if token is expired
            const currentTime = Math.floor(Date.now() / 1000); // Current time in seconds
            if (cwtJSON[CwtClaims.exp] && cwtJSON[CwtClaims.exp] < currentTime) {
                // We can regnerate the token and add 8 hours to the expiry time
                cwtJSON[CwtClaims.exp] = Math.floor(Date.now() / 1000) + (8 * 60 * 60);
                                
                let genContext = {
                  coseTag: "MAC0",
                  key: secretKey
                }
                                
                let newTokenBuffer = cf.cwt.generateToken(cwtJSON, genContext);
                 request.headers['x-cwt-regenerated-token'] = newTokenBuffer.toString('base64url');
            }
        } catch (error) {
            return {
               statusCode: 401,
               statusDescription: 'Invalid token'
            };
         }
    }
    catch (error) {
        return {
            statusCode: 402,
            statusDescription: 'Token processing failed'
        };
     }
    return request;
}
```