Extensões de Autenticação da Microsoft para Node.js

As Extensões de Autenticação da Microsoft para Node oferecem mecanismos seguros para que os aplicativos clientes realizem a serialização e a persistência multiplataforma do cache de token.

O MSAL Node exige que os desenvolvedores implementem sua própria lógica para a persistência do cache de tokens. As extensões do MSAL Node visam fornecer uma implementação robusta, segura e configurável de persistência de cache de tokens no Windows, Mac e Linux para aplicativos cliente públicos (clientes de desktop, aplicativos de CLI etc.). Ele fornece mecanismos para criptografar, bem como acessar o cache de token por vários processos simultaneamente.

As plataformas com suporte são Windows, Mac e Linux:

  • Windows – O DPAPI é usado para criptografia.
  • MAC – O Conjunto de Chaves MAC é usado por meio do keytar npm.
  • Linux – LibSecret é usado para armazenar no "Serviço Secreto" por meio do npm keytar.

Code

Criando a camada de persistência

A API para criar a camada de persistência varia de acordo com a plataforma para a qual você está desenvolvendo.

Como alternativa, você pode usar a createPersistence API de PersistenceCreator , pois ela é um wrapper genérico e seleciona o método de persistência apropriado com base na plataforma/sistema operacional.

const { PublicClientApplication } = require("@azure/msal-node");
const {
  DataProtectionScope,
  PersistenceCreator,
  PersistenceCachePlugin,
} = require("@azure/msal-node-extensions");

const persistence = await PersistenceCreator.createPersistence({
                cachePath: "path/to/cache/file.json",
                dataProtectionScope: DataProtectionScope.CurrentUser,
                serviceName: "test-msal-electron-service",
                accountName: "test-msal-electron-account",
                usePlaintextFileOnLinux: false,
          });
// Use the persistence object to initialize an MSAL PublicClientApplication with cachePlugin
const pca = new PublicClientApplication({
                auth: {
                        clientId: "CLIENT_ID_HERE",
                    },
                cache: {
                        cachePlugin: new PersistenceCachePlugin(persistence);
                    },
                });

Como alternativa, você pode usar as opções específicas da plataforma abaixo:


const { FilePersistenceWithDataProtection, DataProtectionScope } = require("@azure/msal-node-extensions");
const { PublicClientApplication } = require("@azure/msal-node");

const cachePath = "path/to/cache/file.json";
const dataProtectionScope = DataProtectionScope.CurrentUser;
const optionalEntropy = ""; //specifies password or other additional entropy used to encrypt the data.
const windowsPersistence = await FilePersistenceWithDataProtection.create(cachePath, dataProtectionScope, optionalEntropy);
// Use the persistence object to initialize an MSAL PublicClientApplication with cachePlugin
const pca = new PublicClientApplication({
                auth: {
                        clientId: "CLIENT_ID_HERE",
                    },
                cache: {
                        cachePlugin: new PersistenceCachePlugin(windowsPersistence);
                    },
                });

  • cachePath é o caminho no sistema de arquivos em que o arquivo de cache criptografado será armazenado.
  • dataProtectionScope especifica o escopo da proteção de dados, o usuário atual ou o computador local. Você não precisa de uma chave para proteger ou desproteger os dados. Se você definir o escopo como CurrentUser, somente os aplicativos em execução em suas credenciais poderão desproteger os dados; no entanto, isso significa que qualquer aplicativo em execução em suas credenciais pode acessar os dados protegidos. Se você definir o escopo como LocalMachine, qualquer aplicativo de confiança total no computador poderá desproteger, acessar e modificar os dados.
  • optionalEntropy especifica a senha ou outra entropia adicional usada para criptografar os dados.

O FilePersistenceWithDataProtection usa as APIs Win32 CryptProtectData e CryptUnprotectData. Para obter mais informações sobre dataProtectionScope ou optionalEntropy, faça referência à documentação dessas APIs.

Todas as plataformas

Uma persistência de arquivo não criptografada, que funciona em todas as plataformas, é fornecida para conveniência, embora não seja recomendável.

const { FilePersistence } = require("@azure/msal-node-extensions");

const filePath = "path/to/cache/file.json";
const filePersistence = await FilePersistence.create(filePath, loggerOptions);
// Pass the persistence to msal config's cachePlugin
const pca = new PublicClientApplication({
    auth: {
            clientId: "CLIENT_ID_HERE",
        },
    cache: {
            cachePlugin: new PersistenceCachePlugin(filePersistence);
        },
  });

Se o arquivo ou diretório não tiver sido criado, FilePersistence.create() criará o arquivo e quaisquer diretórios no caminho recursivamente. Isso pode ser visto em ação em FilePersistence.ts

Passar opções de bloqueio para o plug-in Cache para concorrência

Crie o PersistenceCachePlugin, passando o objeto de persistência criado na etapa anterior.

const { PersistenceCachePlugin } = require("@azure/msal-node-extensions");

const persistenceCachePlugin = new PersistenceCachePlugin(windowsPersistence); // or any of the other ones.

Para dar suporte ao acesso simultâneo por vários processos, as extensões usam um bloqueio baseado em arquivo. Você pode configurar o número de tentativas e o atraso entre tentativas para adquirir o bloqueio por meio de CrossPlatformLockOptions.

const {
  PersistenceCreator,
  PersistenceCachePlugin,
} = require("@azure/msal-node-extensions");

const lockOptions = {
    retryNumber: 100,
    retryDelay: 50
}

const persistence = await PersistenceCreator.createPersistence(persistenceConfiguration);
const persistenceCachePlugin = new PersistenceCachePlugin(persistence, lockOptions); // or any of the other ones
const pca = new PublicClientApplication({
    auth: {
            clientId: "CLIENT_ID_HERE",
        },
    cache: {
            cachePlugin: persistenceCachePlugin
        },
    });

Definindo o PersistenceCachePlugin na configuração do nó MSAL PublicClientApplication (com um exemplo)

Para resumir, depois de obter um PersistenceCachePlugin, você pode defini-lo no MSAL Node PublicClientApplication, definindo-o como parte do objeto configuration, conforme mostrado abaixo.

import { PublicClientApplication } from "@azure/msal-node";

const publicClientConfig = {
    auth: {
        clientId: "",
        authority: "",
    },
    cache: {
        cachePlugin: persistenceCachePlugin
    },
};

const pca = new PublicClientApplication(publicClientConfig);

Exemplo (para aplicativo de desktop em Electron/Node.js):-

authConfig.js:-

const AAD_ENDPOINT_HOST = "https://login.microsoftonline.com/"; // include the trailing slash
const REDIRECT_URI = "ENTER_REDIRECT_URI";

const cachePath = "path/to/cache/file.json";

/*define persistence config based on the appropriate persistence you are using(e.g- FilePersistenceWithDataProtection, generic PersistenceCreateor, etc)*/

//defining persistence config for PersistenceCreator
const persistenceConfiguration = {
    cachePath,
    dataProtectionScope: DataProtectionScope.CurrentUser,
    serviceName: "test-msal-electron-service",
    accountName: "test-msal-electron-account",
    usePlaintextFileOnLinux: false,
}

  const msalConfig = {
    auth: {
        clientId: "CLIENT_ID_HERE",
        authority: `${AAD_ENDPOINT_HOST}TENANT_ID_HERE`,
    },
    cache: {
        cachePlugin: null // set later in main.js as shown above 
    },
    system: {
        loggerOptions: {
            loggerCallback(loglevel, message, containsPii) {
                console.log(message);
            },
            piiLoggingEnabled: false,
            logLevel: LogLevel.Verbose,
        },
    },
};
...

module.exports = {
  msalConfig: msalConfig,
  protectedResources: protectedResources,
  REDIRECT_URI: REDIRECT_URI,
  persistenceConfiguration
};

Observação para desenvolvedores do Electron

Exemplo do Electron: este exemplo mostra como integrar a biblioteca msal-node-extensions ao seu aplicativo Electron empacotado com o webpack.

Se você estiver usando essa extensão para o Electron, poderá enfrentar um erro semelhante a este:

Uncaught Exception:
Error: The module
"<path-to-project>\node_modules\...\dpapi.node" was compiled against a different Node.js version using NODE_MODULE_VERSION 85. This version of Node.js requires NODE_MODULE_VERSION 80. Please try re-compiling or re-installing the module...."

Esse erro provavelmente ocorre devido às diferenças de versão do Node.js entre o projeto do Electron e a extensão. Isso pode ser tratado recriando o pacote com as seguintes etapas:

  • Instale electron-rebuild com o comando npm i -D electron-rebuild se você ainda não o tiver instalado.
  • Remova packages-lock.json do projeto se ele existir
  • Execute ./node_modules/.bin/electron-rebuild

Exemplos

  1. Exemplo de Electron-webpack para persistência
  2. Exemplo de extensões msal-node