Implementando um Plugin de Autenticação para Guarapi
Published: 2024-01-10 18:31:58

Olá!

Gostaria de compartilhar uma Prova de Conceito (POC) de um plugin de autenticação em desenvolvimento para o Guarapi. Este plugin visa oferecer funcionalidades de autenticação e renovação de tokens JWT.

Para mais informações e para colaborar, acesse nosso Discord [Guarapi Development](https://discord.gg/bs3Upnw5) e confira o [GitHub do Guarapi](https://github.com/guarapi/guarapi).

Aqui está uma breve amostra do código do plugin:

```ts
import { Plugin, Request } from 'guarapi';
import { Methods } from 'guarapi/dist/lib/router';
import { sign } from 'jsonwebtoken';

interface SingConfig<P extends { sub: string | number }> {
  route: string;
  getJWTPayload: (req: Request) => Promise<P>;
}

export interface GuarapiAuthPluginConfig<P extends { sub: string | number }> {
  signIn?: SingConfig<P>;
  refreshToken?: SingConfig<P>;
  salt: string;
  tokenExpiresIn: string;
  refreshTokenExpiresIn: string;
  issuer: string;
  audience: string;
}

export default function guarapiAuthPlugin<P extends { sub: string | number }>(
  guarapiAuthPluginConfig: GuarapiAuthPluginConfig<P>,
) {
  const { salt, audience, issuer, tokenExpiresIn, refreshTokenExpiresIn, signIn, refreshToken } =
    guarapiAuthPluginConfig;

  const routesMap: Record<string, SingConfig<P> | undefined> = {
    [signIn?.route || '']: signIn,
    [refreshToken?.route || '']: refreshToken,
  };

  async function getTokens(req: Request, route: SingConfig<P>) {
    const { sub, ...jwtPayload } = await route.getJWTPayload(req);

    return {
      token: sign({ sub, ...jwtPayload }, salt, {
        expiresIn: route === signIn ? tokenExpiresIn : refreshTokenExpiresIn,
        audience,
        issuer,
      }),

      refreshToken: sign({ sub, ...jwtPayload }, salt, {
        expiresIn: refreshTokenExpiresIn,
        audience,
        issuer,
      }),
    };
  }

  const plugin: Plugin = (app) => {
    app.use(async (req, res, next) => {
      const route = routesMap[req.url || ''];
      const method = req.method?.toLocaleLowerCase();

      if (route && method === Methods.POST) {
        const tokens = await getTokens(req, route);
        res.json(tokens);
        return;
      }

      next();
    });

    return {
      name: 'guarapiAuthPlugin',
    };
  };

  return plugin;
}
```

Este plugin permite configurar rotas de autenticação e renovação de tokens JWT, adaptáveis às necessidades do projeto. Ele utiliza o pacote jsonwebtoken para gerar os tokens com base nas configurações fornecidas.

A configuração básica para este plugin é a seguinte:

```ts
import { Guarapi, bodyParserPlugin, middlewarePlugin } from 'guarapi';
import guarapiAuthPlugin, { GuarapiAuthPluginConfig } from './guarapi-auth-plugin';

interface PayloadRequest {
  userId: string;
}

export default async function initPlugins(app: Guarapi) {
  const authConfig: GuarapiAuthPluginConfig<{ sub: string; userId: string }> = {
    signIn: {
      route: '/auth/signin',
      getJWTPayload: async (req) =>
        Promise.resolve({ sub: 'teste', userId: (req.body as PayloadRequest)?.userId }),
    },
    refreshToken: {
      route: '/auth/refresh',
      getJWTPayload: async (req) =>
        Promise.resolve({ sub: 'teste', userId: (req.body as PayloadRequest)?.userId }),
    },
    audience: 'teste',
    issuer: 'issuer-1',
    salt: 'secret',
    refreshTokenExpiresIn: '24h',
    tokenExpiresIn: '1h',
  };

  app.plugin(bodyParserPlugin);
  app.plugin(middlewarePlugin);
  app.plugin(guarapiAuthPlugin(authConfig));
}
```

Estou buscando feedback da comunidade sobre a estrutura, a lógica de funcionamento e possíveis melhorias que podem ser implementadas neste plugin. Sintam-se à vontade para discutir e compartilhar suas opiniões, sugestões ou dúvidas relacionadas a esta POC.

Agradeço antecipadamente por qualquer contribuição ou feedback que possam oferecer!

### Nossas redes:

| Plataforma   | Link                                                |
|--------------|-----------------------------------------------------|
| Reddit       | [Guarapi Subreddit](https://www.reddit.com/r/Guarapi/) |
| Daily.dev     | [Daily.dev Invite](https://dly.to/BAbWhWqJ7cs)      |
| Discord      | [Discord Invite](https://discord.com/invite/KQwZtsTF) |
| Repositório  | [Guarapi no GitHub](https://github.com/guarapi/guarapi) |