Skip to main content
Em um cenário com multiplos benefícios e diversas integrações, lidamos com diversos sistemas e, consequentemente, com diferentes formas de autenticação. Algumas APIs utilizam JWT, outras OAuth, algumas exigem token fixo no header, e ainda existem aquelas que utilizam métodos totalmente personalizados. Com tantas abordagens, não é viável criar um ambiente multi-benefícios com estratégias de autenticações fixas. Por isso, o benSDK permite que cada benefício implementado defina sua própria auth strategy, oferecendo flexibilidade para se adaptar a qualquer modelo de autenticação.

Estrutura básica

No arquivo benefit-definition.ts existe um campo opcional:
auth?: {
    handler: (credentials: any, ctx: AuthHandlerCtx) => Promise<AuthHandlerResult>;
};
O campo auth lida com as responsabilidades de autenticação. Esse handler é justamente, onde se define uma função que irá lidar com essa responsabilidade. Um ponto interessante é que a cada mudança de estado na state-machine esse handler será chamado. Por isso, o ctx fornece algumas funções auxiliares que podem ser úteis para cachear e reutilizar tokens entre chamadas:
    get: (params: GetTokenParameters) => Promise<string | null>;
    set: (params: SetTokenParameters) => Promise<boolean>;
Essas funções servem para armazenar e recuperar tokens. Elas são especialmente úteis em cenários em que o handler é invocado com frequência, por exemplo, a cada tranasição de estado, mas o token tem um TTL maior que esse intervalo. Sendo tudo isso configurável via chamadas ao set.

Retorno esperado

O handler deve retornar um objeto simples do tipo:
export type AuthHandlerResult = {
    outcome: 'FAILED';
    reason?: string;
    retry?: boolean;
} | {
    outcome: 'SUCCEEDED';
    instance?: AxiosInstance;
};
Com esse retorno é possível informar se a autenticação foi bem-sucedida ou falhou, em caso de falha se deve ocorrer re-tentativas (até 7 vezes, com backoff exponencial). Quando a autenticação é bem-sucedida, o handler deve retornar uma instância configurada do axios através de axios.create.

Exemplo prático

Abaixo um exemplo completo de implementação de uma auth strategy personalizada, usando cache de token com ctx.tokenHelper:
auth: {
  handler: async (credentials: any, ctx: AuthHandlerCtx) => {
    const token = await ctx.tokenHelper.get({
      accountID: credentials.accountID,
      companyID: credentials.companyID,
      benefitID: credentials.benefitID
    });

    if (token) {
      return {
        outcome: 'SUCCEEDED',
        instance: axios.create({
          baseURL: 'https://api.example.com',
          headers: { Authorization: `Bearer ${token}` }
        })
      };
    }

    const res = await axios.post('https://api.example.com/auth/token', {
      login: credentials.login,
      password: credentials.password
    });

    if (res.status !== 200) {
      return {
        retry: true, // Retentará até 7 vezes, com backoff exponencial
        outcome: 'FAILED',
        reason: 'Failed to get token'
      };
    }

    await ctx.tokenHelper.set({
      accountID: credentials.accountID,
      companyID: credentials.companyID,
      benefitID: credentials.benefitID,
      valueToBeStored: res.data.token,
      storeForSeconds: 60 * 60 * 24 * 30
    });

    return {
      outcome: 'SUCCEEDED',
      instance: axios.create({
        baseURL: 'https://api.example.com',
        headers: { Authorization: `Bearer ${res.data.token}` }
      })
    };
  }
}
  1. Tenta reutilizar um token já armazenado.
  2. Caso não exista, requisita um novo token.
  3. Armazena o token para futuras chamadas.
  4. Retorna uma instância axios autenticada e pronta para uso.