npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@betha-plataforma/oauth

v1.1.7

Published

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

Readme

@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