Obtenção de tokens de acesso protegidos com Prova de Posse

Para aumentar a proteção dos tokens de acesso OAuth 2.0 armazenados no navegador contra "reprodução de token", o MSAL fornece um esquema de autenticação Access Token Proof-of-Posession. Access Token Proof-of-Possession, ou AT PoP, é um esquema de autenticação que vincula criptograficamente os tokens de acesso ao navegador e ao aplicativo cliente a partir dos quais são solicitados, o que significa que eles não podem ser usados em um aplicativo ou dispositivo diferente.

É importante entender que, para AT PoP trabalhar de ponta a ponta e fornecer a atualização de segurança pretendida, o serviço de autorização que emite os tokens de acesso e o servidor de recursos ao qual eles estão fornecendo acesso devem dar suporte AT PoP.

Token de Acesso Portador vs. Token de Acesso Vinculado (PoP)

Token de acesso do portador

O padrão Authentication Result retornado pelas APIs do MSAL v2 inclui a propriedade accessToken. Quando usado com o esquema de autenticação padrão Bearer , o valor na accessToken propriedade é o segredo do token de acesso fornecido pelo servidor de autorização. Esse artefato é armazenado em cache pela MSAL e deve ser adicionado a solicitações de recurso como um token de portador no cabeçalho da Authorization solicitação.

Exemplo de uso do token de acesso do portador:

// Using the Bearer scheme (default), acquireTokenRedirect returns an AuthenticationResult object containing the Bearer access token secret
const { accessToken } = await myMSALObj.acquireTokenRedirect(popTokenRequest);

// The bearer token secret is appended to the Authorization header
const headers = new Headers();
const authHeader = `Bearer ${accessToken}`; // The Bearer label is used in this header
headers.append("Authorization", authHeader);

Token de acesso vinculado

Também conhecido como PoP Token ou Signed HTTP Request. Quando o esquema de autorização POP está habilitado em uma solicitação de token do MSAL, o servidor de autorização ainda fornecerá um segredo de token de acesso JWT (JSON Web Token) que se parece com um token de acesso Bearer, que o MSAL também armazenará em cache. A principal diferença é que, ao usar o POP esquema, esse segredo de token de acesso será associado ao navegador do usuário por meio de um keypair criptográfico assimétrico.

O segredo do token de acesso é encapsulado em um novo JSON Web Token, que será assinado usando o algoritmo de hash HMAC (Código de Autenticação de Mensagem baseado em Hash) e a chave privada do par de chaves que o MSAL gera, armazena e gerencia. O JWT assinado é então adicionado ao objeto AuthorizationResult na propriedade accessToken e retornado pela chamada à API MSAL v2.

Depois que o aplicativo cliente recebe o resultado de autenticação retornado, ele pode extrair o accessToken valor do resultado da autenticação e adicioná-lo ao Authorization cabeçalho de uma solicitação de recurso protegida por PoP, usando o PoP rótulo em vez do Bearer rótulo.

Observação: o JWT assinado (chamado de solicitação HTTP assinada ou SHR) nunca é armazenado em cache pela MSAL. Sempre que uma API msal v2 for chamada, a MSAL recuperará um segredo de token de acesso bruto válido do cache ou solicitará um novo token de acesso do servidor de autorização. A MSAL assinará o token de acesso e o retornará no resultado da autenticação.

Exemplo de uso de token de acesso vinculado (PoP):

// Using the POP scheme (default), acquireTokenRedirect returns an AuthenticationResult object containing the Signed HTTP Request (PoP Token)
const { accessToken } = await myMSALObj.acquireTokenRedirect(popTokenRequest);

// The SHR is appended to the Authorization header
const headers = new Headers();
const authHeader = `PoP ${accessToken}`; // The PoP label is used in this header
headers.append("Authorization", authHeader);

Fazendo uma solicitação de token PoP

Depois de determinar se o serviço de autorização e o servidor de recursos suportam a vinculação de token de acesso, você pode configurar seus objetos de solicitação de autenticação e autorização do MSAL para adquirir tokens de acesso vinculados, criando um objeto de solicitação de token contendo os atributos específicos do PoP do Token de Acesso. Todos os atributos a seguir são opcionais no objeto de solicitação, no entanto, authorizationScheme deve ser definido manualmente como 'pop' para habilitar a prova de posse.

Parâmetros de solicitação do AT PoP

Nome Description Obrigatório
authenticationScheme Indica se a MSAL deve adquirir um Bearer ou PoP token. O padrão é Bearer. Required
resourceRequestMethod O nome em letras maiúsculas do método HTTP da solicitação que usará o token assinado (GET, POST, PUT, etc.) Required
resourceRequestUri A URL do recurso protegido para o qual o token de acesso está sendo emitido Required
shrClaims Um objeto JSON em formato de string contendo declarações personalizadas do cliente a serem adicionadas ao SignedHTTPRequest. Confira a documentação de Declarações SHR Personalizadas para obter mais informações. Opcional
shrNonce Um carimbo de data/hora assinado gerado pelo servidor que é codificado em Base64URL como uma cadeia de caracteres. Este nonce é usado para mitigar ataques de distorção de relógio e de viagem no tempo destinados a permitir a pré-geração de tokens PoP. Confira a documentação do SHR Server Nonce para obter mais informações. Opcional

Nota: embora este documento mostre como adicionar um shrNonce ao SignedHttpRequest, o padrão de aquisição de nonce do servidor está fora do escopo. Consulte a documentação do SHR Server Nonce para obter mais informações sobre como adquirir nonces gerados pelo servidor.

Exemplo de solicitação de redirecionamento para aquisição de token

const popTokenRequest = {
    scopes: ["User.Read"],
    authenticationScheme: msal.AuthenticationScheme.POP,
    resourceRequestMethod: "POST",
    resourceRequestUri: "YOUR_RESOURCE_ENDPOINT",
    shrClaims: "{\"shrClaim1\": \"claimValue\"}",
    shrNonce: "NONCE_ACQUIRED_FROM_RESOURCE_SERVER"
}

Depois que a solicitação tiver sido configurada e POP for definida como a authenticationScheme, ela poderá ser enviada para a acquireTokenRedirect API msal v2.

const response = await myMSALObj.acquireTokenRedirect(popTokenRequest);

// Once a Pop Token has been acquired, it can be added on the authorization header of a resource request
const headers = new Headers();
const authHeader = `${response.tokenType} ${response.accessToken}`;

headers.append("Authorization", authHeader);

const options = {
    method: popTokenRequest.resourceRequestMethod,
    headers: headers
};

// After the request has been built and the POP access token has bee appended, the request can be executed using an API like "fetch"
fetch(endpoint, options)
    .then(response => response.json())
    .then(response => callback(response, endpoint))
    .catch(error => console.log(error));
});

Exemplo de solicitação silenciosa de aquisição de token

A aquisição silenciosa de tokens de acesso PoP exige as mesmas alterações na configuração da solicitação de token que nas APIs interativas acquireToken:

const silentPopTokenRequest = {
    scopes: ["User.Read"],
    authenticationScheme: msal.AuthenticationScheme.POP, // Default is "BEARER"
    resourceRequestMethod: "POST",
    resourceRequestUri: "YOUR_RESOURCE_ENDPOINT",
    shrClaims: "{\"shrClaim1\": \"claimValue\"}",
    shrNonce: "NONCE_ACQUIRED_FROM_RESOURCE_SERVER"
}

// Try to acquire token silently
const { accessToken } = await myMSALObj.acquireTokenSilent(silentPopTokenRequest).catch(async (error) => {
        console.log("Silent token acquisition failed.");
        if (error instanceof msal.InteractionRequiredAuthError) {
            // Fallback to interaction if silent call fails
            console.log("Acquiring token using redirect");
            myMSALObj.acquireTokenRedirect(silentPopTokenRequest);
        } else {
            console.error(error);
        }
    });

// Once a Pop Token has been acquired, it can be added on the authorization header of a resource request
const headers = new Headers();
const authHeader = `PoP ${accessToken}`;

headers.append("Authorization", authHeader);

const options = {
    method: popTokenRequest.resourceRequestMethod,
    headers: headers
};

// After the request has been built and the POP access token has bee appended, the request can be executed using an API like "fetch"
fetch(endpoint, options)
    .then(response => response.json())
    .then(response => callback(response, endpoint))
    .catch(error => console.log(error));
});

Gerenciamento de chaves PoP

O esquema de autenticação de prova de posse depende de um par de chaves criptográficas assimétricas para vincular o token de acesso ao navegador do usuário. O MSAL Browser gera esse keypair ao solicitar inicialmente um token de acesso do serviço de autorização e o armazena usando IndexedDB. Esse par de chaves criptográficas é então usado para assinar o SHR toda vez que o token de acesso vinculado é solicitado de forma silenciosa.

No caso de atualizar um token de acesso associado, a MSAL excluirá o keypair criptográfico gerado ao solicitar o token de acesso associado expirado, gerará um novo keypair criptográfico para o novo token de acesso e armazenará o novo keypair no repositório de chaves.

Recurso avançado: par de chaves criptográficas gerenciado pelo aplicativo

Warning

Não recomendamos usar esse recurso, a menos que você esteja familiarizado com o protocolo Prova de Posse e tenha um requisito específico para gerar seu próprio keypair criptográfico. Para a maioria dos casos, recomendamos o uso de PoP conforme descrito no restante deste documento.

Se você optar por gerar seu próprio keypair criptográfico, esse recurso permitirá que o aplicativo forneça o popKid parâmetro como uma solicitação. O MSAL JS garante que o emissor do token incorpore o cnf no token, mas retorna o token emitido não assinado. A responsabilidade por assinar o token de acesso antes que ele seja encaminhado ao recurso de destino será do aplicativo.

Observe também que, se você optar por aproveitar esse comportamento, deve garantir que os parâmetros PoP restantes, exceto o authenticationScheme, não sejam definidos.

Por que os tokens de acesso são salvos de forma assíncrona

A maioria das credenciais msal e itens de cache, como ID Tokens por exemplo, podem ser armazenados e removidos de forma síncrona. Isso ocorre porque esses itens de cache são armazenados em localStorage ou sessionStorage (que podem ser manipulados de forma síncrona) e não têm dependências de outros itens armazenados que têm restrições de acesso assíncrono.

Ao contrário de outros itens de cache, Access Tokens são salvos no cache de forma assíncrona. O motivo disso é que, no caso de um token de acesso ser associado a um keypair criptográfico, que é armazenado IndexedDB, substituir o token de acesso também envolve substituir o keypair criptográfico. Considerando que remover e gravar chaves IndexedDB são operações assíncronas, o processo para salvar um token de acesso inevitavelmente se torna assíncrono por extensão.

Exemplos de código