Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

@betha-plataforma/oauth

Package Overview
Dependencies
Maintainers
1
Versions
6
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@betha-plataforma/oauth

Biblioteca JavaScript para lidar com o fluxo do OAuth 2.0 em aplicações Web, com suporte a TypeScript.

latest
npmnpm
Version
1.1.7
Version published
Weekly downloads
24
-7.69%
Maintainers
1
Weekly downloads
 
Created
Source

@betha-plataforma/oauth

Biblioteca JavaScript para lidar com o fluxo do OAuth 2.0 em aplicações Web, com suporte a TypeScript.

Atualmente o fluxo suportado é o Implicit, abaixo temos um exemplo de como configurá-lo.

Este fluxo é usado para aplicativos móveis e aplicações web, onde a capacidade de armazenar segredos no cliente não é garantida. Entenda melhor sobre este fluxo neste guia Introdução ao OAuth 2 da Digital Ocean e caso queira entender na prática acesse o OAuth 2.0 Playground.

Configurações

Após instalar, algumas configurações são necessárias.

Configurando variáveis dos Serviços

Para realizar as configurações é necessário saber os hosts de alguns serviços, como OAuth, Login e Usuários.

Estes valores podem ser obtidos conforme constam em https://suite.cloud.betha.com.br/env.js

Entretanto sugerimos a importação dessa URL como um script no index.html para que a aplicação possa obter os valores de forma dinâmica por meio da variável window['___bth'].envs. Assim caso em algum momento seja necessário alteração nestes valores, eles serão refletidos automaticamente.

<!DOCTYPE html>
<html>
  <head>
    <title>OAuth Playground</title>
  </head>
  <body>
    <!-- ... HTML ... -->

    <!-- Variáveis do Env.js -->
    <script src="https://suite.cloud.betha.com.br/env.js"></script>

    <!-- App Scripts -->
  </body>
</html>

No playground/webpack.config.js é definido uma variável dinamica chamada "envjs" a qual irá preencher a URL nos templates playground/src/index.html e playground/src/auth/callback/callback.html

Configurando provedor OAuth

Com as variáveis dos serviços em mãos, basta criar uma configuração de provedor OAuth.

const OAUTH_URL = window["___bth"].envs.suite.oauth.v1.host;
const SERVICE_LOGIN_URL = window["___bth"].envs.suite["service-login"].v1.host;
const USERS_URL = window["___bth"].envs.suite.usuarios.v1.host;

const provider = {
  authorization_endpoint: `${OAUTH_URL}/authorize`,
  check_session_iframe: `${SERVICE_LOGIN_URL}/openidsso.jsp`,
  end_session_endpoint: `${SERVICE_LOGIN_URL}/logout?continue=${OAUTH_URL}/authorize?client_id=${config.clientId}%26response_type=token%26redirect_uri=${config.redirectUri}%26scope=${config.scope}`,
  introspect_endpoint: `${OAUTH_URL}/tokeninfo`,
  token_endpoint: `${OAUTH_URL}/token`,
  userinfo_endpoint: `${USERS_URL}/api/usuarios/@me`,
};

Exemplo em playground/src/auth/oauth-provider.js

Configurando Cliente (aplicação)

Além do provedor também é preciso configurar o cliente, que representa a aplicação que irá consumir os recursos autenticados.

ℹ️ Atualmente as aplicações clientes são registradas e mantidas pela equipe da Plataforma, caso não possua os dados necessários, favor entrar em contato.

const clientConfig = {
  scope: "SCOPES",
  clientId: "CLIENT_ID",
  redirectUri: `${window.location.origin}/auth/callback.html`,
  silentRedirectUri: `${window.location.origin}/auth/silent-callback.html`,
};

Onde:

Exemplo em playground/src/auth/oauth-application.js

Criando instância do OAuth

As configurações do cliente e do provedor OAuth podem ser mescladas e utilizadas para criar uma instância do OAuth para a aplicação.

É por meio desta instância que serão realizadas as interações com recursos de autenticação como: login, logout, obter token de acesso, verificar se há sessão ativa, obter dados do usuário, etc.

const OAUTH_URL = window["___bth"].envs.suite.oauth.v1.host;
const SERVICE_LOGIN_URL = window["___bth"].envs.suite["service-login"].v1.host;
const USERS_URL = window["___bth"].envs.suite.usuarios.v1.host;

const oAuthConfig = {
  scope: "SCOPES",
  clientId: "CLIENT_ID",
  redirectUri: `${window.location.origin}/auth/callback.html`,
  silentRedirectUri: `${window.location.origin}/auth/silent-callback.html`,
  provider: {
    authorization_endpoint: `${OAUTH_URL}/authorize`,
    check_session_iframe: `${SERVICE_LOGIN_URL}/openidsso.jsp`,
    end_session_endpoint: `${SERVICE_LOGIN_URL}/logout?continue=${OAUTH_URL}/authorize?client_id=${config.clientId}%26response_type=token%26redirect_uri=${config.redirectUri}%26scope=${config.scope}`,
    introspect_endpoint: `${OAUTH_URL}/tokeninfo`,
    token_endpoint: `${OAUTH_URL}/token`,
    userinfo_endpoint: `${USERS_URL}/api/usuarios/@me`,
  },
};

export const oAuthApp: OAuthApplication = new OAuthApplication(oAuthConfig);

Exemplo em playground/src/auth/oauth-application.js

Adequando inicialização da aplicação

Quando a aplicação for inicializada e não houver uma sessão ativa, deve-se chamar o método login(), disponível na instância do OAuth. Este método irá lidar com os passos necessários para o usuário efetuar o login.

import { oAuthApp } from "./oauth-application.ts";

if (!oAuthApp.hasActiveSession()) {
  oAuthApp.login();
} else {
  /**
   * Iniciar a aplicação, renderizando recursos autenticados
   */
  bootstrap();
}

Exemplo em playground/src/index.js

Lidando com redirecionamento do Login

Após o usuário efetuar o login, ele será redirecionado para o redirectUri configurado na instância do OAuth.

Este redirecionamento irá entregar para a aplicação alguns valores por meio de parâmetros da URL. Nesta página a aplicação deverá executar o método handleCallback() da instância do OAuth para prosseguir com o fluxo.

import { oAuthApp } from "./oauth-application.ts";

oAuthApp.handleCallback();

Exemplo em playground/src/auth/callback/callback.html e playground/src/auth/callback/callback.js

Obtendo novo token de acesso em segundo plano

Após autenticado, é possível renovar o token de acesso em segundo plano. Para isso é necessário ter uma página que emita algumas informações para a aplicação de origem. Essa página é configurada no silentRedirectUri ao instanciar a aplicação OAuth.

<html>
  <head>
    <script>
      parent.postMessage(location.hash, location.origin);
    </script>
  </head>
</html>

Exemplo em playground/src/auth/callback/silent-callback.html

Monitorando eventos de sessão

Durante o ciclo de vida de uma sessão alguns eventos provenientes de autenticação podem ser capturados para apresentar um feedback ao usuário.

A captura dos eventos pode ser feita por meio da instância de um Monitor de Eventos, criado a partir da instância do OAuth.

import { OAuthMonitor } from "@betha-plataforma/oauth";
import { oauthApp } from "./oauth-application.ts";

const monitorOptions = {
  app: oauthApp,
  interval: 1000,
};

const monitor = new OAuthMonitor(monitorOptions, {
  onSessionChanged: () => {
    // OAuth session changed
  },
  onSessionEnded: () => {
    // OAuth session ended
  },
  onSessionRestablished: () => {
    // OAuth session restabilished
  },
});

monitor.start();

Exemplo em playground/src/auth/oauth-monitor.js

Fornecendo feedback ao usuário

O componente recomendado para o feedback é a modal. Ela deve ser utilizada no formato bloqueante, ou seja, não permite fechar por meio da interface ou do teclado. Isto evita que o usuário utilize o sistema que pode estar inoperável por falta de autenticação. Para evitar empilhamento, é sugerido fechar as modais abertas ao receber qualquer evento.

As interfaces apresentadas são modelos baseados no Design System dos sistemas Cloud da Betha. É importante preservar as características do sistema no qual as interfaces serão apresentadas.

ℹ️ Nos exemplos abaixo foi utilizado o Bootstrap 4, que é um framework bem comum para abstrair o comportamento e estilização dos componentes.

Quando a sessão for alterada

Abaixo um modelo de apresentação quando a sessão for alterada

modal_session_changed

  • Ilustração: user-changed.png
  • Mensagem: "O usuário lorem.ipsum entrou no sistema"
  • Botão: "Atualizar página"
<div
  id="session_changed_modal"
  class="modal fade"
  data-backdrop="static"
  data-keyboard="false"
  tabindex="-1"
  aria-hidden="true"
>
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-body p-4">
        <div class="row text-center">
          <div class="col-md-12">
            <img
              style="width: 110px; margin-bottom: 12px;"
              src="/images/user-changed.png"
            />
            <h5 class="mb-4">
              O usuário <strong id="session_changed_userid"></strong> entrou no
              sistema
            </h5>
          </div>
        </div>
        <div class="text-center">
          <button
            class="btn btn-primary"
            onclick="window.location.reload()"
            style="width: 220px;"
          >
            Atualizar página
          </button>
        </div>
      </div>
    </div>
  </div>
</div>

O evento pode ser capturado por meio do método onSessionChanged, disponível no Monitor de Eventos

new OAuthMonitor(monitorOptions, {
  onSessionChanged: () => {
    const userInfo = getUserInfo();
    document.querySelector("#session_changed_userid").innerHTML = userInfo.id;

    $("#session_ended_modal").modal("hide");
    $("#session_changed_modal").modal("show");
  },
});

Exemplo em playground/src/index.html e playground/src/auth/oauth-monitor.js

Quando a sessão for encerrada

Abaixo um modelo de apresentação quando a sessão for encerrada

modal_session_ended

  • Ilustração: logout.png
  • Mensagem: "Você saiu do sistema"
  • Botão: "Fazer login"
<div
  id="session_ended_modal"
  class="modal fade"
  data-backdrop="static"
  data-keyboard="false"
  tabindex="-1"
  aria-hidden="true"
>
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-body p-4">
        <div class="row text-center">
          <div class="col-md-12">
            <img
              style="width: 110px; margin-bottom: 12px;"
              src="/images/logout.png"
            />
            <h5 class="mb-4">Você saiu do sistema</h5>
          </div>
        </div>
        <div class="text-center">
          <button
            class="btn btn-primary"
            onclick="window.location.reload()"
            style="width: 220px;"
          >
            Fazer login
          </button>
        </div>
      </div>
    </div>
  </div>
</div>

O evento pode ser capturado por meio do método onSessionEnded, disponível no Monitor de Eventos

new OAuthMonitor(monitorOptions, {
  onSessionEnded: () => {
    $("#session_changed_modal").modal("hide");
    $("#session_ended_modal").modal("show");
  },
});

Exemplo em playground/src/index.html e playground/src/auth/oauth-monitor.js

Possibilitando Logout da Conta do Usuário

Esta parte da interface compõe a estrutura visual da aplicação e deve ser utilizada para fornecer as informações da sessão atual como nome, usuário e foto e também possibilita a realização do logout e acesso à Central do Usuário.

./docs/images/conta-usuario.png

ℹ️ Neste exemplo foi utilizado os Web Components da biblioteca @betha-plataforma/estrutura-componentes, que fornece os componentes necessários para compor a estrutura de uma aplicação front-end de maneira agnóstica a frameworks

Criando o componente na interface

<html>
  <head>
    <link
      rel="stylesheet"
      href="https://unpkg.com/@betha-plataforma/estrutura-componentes/dist/estrutura-componentes/estrutura-componentes.css"
    />
  </head>
  <body>
    <bth-app menu-vertical>
      <bth-conta-usuario slot="menu_ferramentas"></bth-conta-usuario>
    </bth-app>

    <script
      type="module"
      src="https://unpkg.com/@betha-plataforma/estrutura-componentes/dist/estrutura-componentes/estrutura-componentes.esm.js"
    ></script>
    <script
      nomodule
      src="https://unpkg.com/@betha-plataforma/estrutura-componentes/dist/estrutura-componentes/estrutura-componentes.js"
    ></script>
  </body>
</html>

Configurando informações da sessão e método de logout

import { oAuthApp } from "./oauth-application";

const profile = oAuthApp.getUser();
const accessToken = oAuthApp.getSession().accessToken.access_token;

const contaUsuario = document.querySelector("bth-conta-usuario");
contaUsuario.usuario = profile.id;
contaUsuario.nome = profile.name;
contaUsuario.fotoUrl = `${profile.photo}?access_token=${accessToken}`;

contaUsuario.addEventListener("logout", async () => {
  await oAuthApp.logout();
});

Exemplo em playground/src/index.html, playground/src/app/bootstrap.js e playground/src/auth/services/authentication.js

Requisições

Ao interagir com recursos autenticados por meio de requisições HTTP, algumas operações podem ser padronizadas no intuito de abstrair a necessidade de lidar com autenticação em cada funcionalidade. Geralmente cria-se um Client HTTP responsável por implementar este mecanismo.

ℹ️ Neste exemplo foi utilizado o Axios, que é um HTTP Client bem comum para Browsers.

Autenticando requisições

O cabeçalho Authorization deve estar presente, com o valor Bearer <AUTH_TOKEN>, onde o AUTH_TOKEN pode ser obtido da instância do OAuth.

import { oAuthApp } from './oauth-application';

const Axios = axios.create();

/**
 * Registra interceptor para autenticar requisições
 */
Axios.interceptors.request.use(config => {
  if (config.method === 'OPTIONS') {
    return config;
  }

  const accessToken = oAuthApp.getSession().accessToken.access_token;
  config.headers.Authorization = `Bearer ${accessToken}`;

  return config;
});

export Axios;

Exemplo em playground/src/core/api.js e playground/src/auth/services/authentication-context.js

Lidando com requisições que falharam

As requisições que falharam com o código de resposta 401 (Unauthorized) devem ser armazenadas. Na sequência o processo de atualização do token da sessão deve ser realizado:

  • Caso seja possível atualizar, as requisições que falharam devem ser efetuadas novamente.
  • Caso não seja possível atualizar, deve ser chamado o método de login
import { oAuthApp } from "./oauth-application";
import { addRequestRetry } from "./retries.js";

const Axios = axios.create();

/**
 * Registra interceptor para lidar com requisições que falharam
 */
Axios.interceptors.response.use(
  (response) => response,
  (error) => {
    if (error.response.status === 401) {
      return new Promise((resolve, reject) =>
        addRequestRetry(error.config, resolve, reject)
      );
    }

    return Promise.reject(error);
  }
);

export default Axios;

O interceptor armazena as requisições que falharam para possibilitar o mecanismo de retentativa. Caso não consiga atualizar o token, é solicitado o login.

import api from "./api";
import { oAuthApp } from "./oauth-application";

let isRefreshingToken = false;
let retryQueue = [];

async function requireAuthentication() {
  try {
    await oAuthApp.silentRefresh();
  } catch (e) {
    return oAuthApp.login();
  }

  const session = oAuthApp.getSession();
  return session.accessToken.access_token;
}

export function addRequestRetry(request, resolve, reject) {
  retryQueue.push({ request, resolve, reject });

  if (!isRefreshingToken) {
    startRefreshing();

    return requireAuthentication()
      .then(() => {
        retryAllRequests();
        stopRefreshing();
      })
      .catch(stopRefreshing);
  }
}

function retryAllRequests() {
  retryQueue.forEach(retryRequest);
  retryQueue = [];
}

function retryRequest({ request, resolve, reject }) {
  api.request(request).then(resolve).then(reject);
}

function startRefreshing() {
  isRefreshingToken = true;
}

function stopRefreshing() {
  isRefreshingToken = false;
}

Exemplo em playground/src/core/api.js, playground/src/core/retries.js e playground/src/auth/services/authentication.js

Playground

Exemplos podem ser encontrados no playground

Keywords

oauth 2

FAQs

Package last updated on 23 Jul 2025

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts