Suporte a CWT para o CloudFront Functions
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.
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
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
( // CWT Tag (Tag value: 61) --- optional ( // COSE MAC0 Structure Tag (Tag value: 17) --- required [ protectedHeaders, unprotectedHeaders, payload, tag, ] ) )
exemplo : 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 ] ) )
nota
A tag CWT é opcional ao gerar tokens. No entanto, a tag da estrutura COSE é necessária.
Método validateToken()
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
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
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
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()
Essa função gera um novo CWT usando a carga útil e as configurações de contexto fornecidas.
Solicitação
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 quecwtTagdeve 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
Bufferem JavaScript.
- payload (obrigatório)
-
Carga útil do token para codificação. A carga útil deve estar no seguinte formato
CWTObject.
Resposta
Exibe um buffer em JavaScript contendo o token codificado.
exemplo : 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' }; } }
exemplo : 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; }