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

@integrattion/auth

v1.4.1

Published

Cliente de autenticação do ecossistema Integrattion. Implementa AUTH_CONTRACT.md §5 contra o Partners.

Readme

@integrattion/auth

Cliente de autenticação do ecossistema Integrattion. Implementa o AUTH_CONTRACT.md §5 inteira contra o Partners, que é o diretório de identidade e autorização (ADR-001).

Nenhum sistema do ecossistema implementa autenticação própria.

Por que este pacote existe assim

  • Zero dependência de runtime. RS256 é verificado com o crypto nativo do Node. Um pacote de JWT aqui só somaria superfície de supply chain a algo que ~11 sistemas vão importar.
  • Zero build no consumidor. dist/ é commitado; o app instala via npm e usa direto.
  • Zero ORM. app_users é DDL + helpers sobre pg. Dos 11 repos ativos, 9 usam pg cru e 2 usam Prisma — um schema de ORM serviria a um repo só.

Instalação

Distribuição via npm público (registry.npmjs.org), no escopo @integrattion.

npm i @integrattion/auth

Por que npm público, e não dependência git

A primeira versão distribuía por dependência git (github:integrattion-os-projects/auth#vX.Y.Z). Quebrou no build em container: node:*-alpine não tem o binário git, e o repo é privado — sem credencial disponível no container, npm ci não resolve a dependência.

GitHub Packages foi descartado pelo mesmo motivo do ADR-001: obrigaria token de registry em ~11 Dockerfiles e workflows de CI, para resolver um problema que o ecossistema, sendo de um dono só, não tem.

O pacote não contém segredo. O client ID do Google é público por contrato (AUTH_CONTRACT.md §6) — nada aqui depende de o repositório ou o registry serem privados.

# .env do app
AUTH_ISSUER_URL=https://partners.integrattion.com.br
AUTH_SYSTEM_SLUG=campaign        # slug da entity no Integrattion OS
GOOGLE_OAUTH_CLIENT_ID=965501017365-bkbucvhr3lbrl9ch4q4ngcuchff6e919.apps.googleusercontent.com

Nenhum segredo de auth no app. A validação é por chave pública.

Servidor (Express)

import { createAuthHandlers, requireRole, appUsers, DEFAULT_ROLES } from '@integrattion/auth';

const authConfig = {
  issuer: process.env.AUTH_ISSUER_URL!,
  systemSlug: process.env.AUTH_SYSTEM_SLUG!,
  roles: DEFAULT_ROLES,          // do mais forte para o mais fraco
  defaultRole: 'VIEWER',
  pool,                          // pg.Pool do app
  googleClientId: process.env.GOOGLE_OAUTH_CLIENT_ID,
};

await appUsers(pool).ensureSchema();   // ou rode APP_USERS_DDL como migration
app.use(express.json());
app.use(createAuthHandlers(authConfig));

app.use('/api', requireRole(authConfig));                 // exige sessão
app.delete('/api/campanhas/:id', requireRole(authConfig, 'ADMIN'), handler);

Rotas montadas: POST /api/auth/callback · POST /api/auth/refresh · POST /api/auth/logout · GET /api/auth/me · GET /api/auth/config · GET|PUT /api/auth/admin/users.

Bootstrap de OWNER

/api/auth/admin/users exige roles[0] (OWNER). Sem bootstrapOwners, o primeiro usuário de um sistema novo entra como defaultRole (ex.: VIEWER) e ninguém consegue abrir a tela de acessos — só com UPDATE manual no banco. bootstrapOwners resolve isso: e-mails nesta lista entram com roles[0] só na criação JIT da linha em app_users (primeiro login). Uma linha já existente nunca é alterada por causa da lista — se um OWNER foi rebaixado, o próximo login não o promove de volta.

const authConfig = {
  issuer: process.env.AUTH_ISSUER_URL!,
  systemSlug: process.env.AUTH_SYSTEM_SLUG!,
  roles: DEFAULT_ROLES,
  defaultRole: 'VIEWER',
  // O pacote NÃO lê process.env — quem lê é o app.
  bootstrapOwners: (process.env.AUTH_BOOTSTRAP_OWNERS ?? '').split(',').map(s => s.trim()).filter(Boolean),
  pool,
  googleClientId: process.env.GOOGLE_OAUTH_CLIENT_ID,
};

Comparação por e-mail é case-insensitive e com trim. Um valor que não parece e-mail em bootstrapOwners derruba o boot com erro claro, em vez de falhar silenciosamente.

Front (React)

import { AuthProvider, LoginGate, useSession, AccessAdminPage, UserMenu } from '@integrattion/auth/react';

<AuthProvider>
  <LoginGate appName="Campaign Manager">
    <header>
      <UserMenu acessosHref="/settings/access" />
    </header>
    <App />
  </LoginGate>
</AuthProvider>

useSession() devolve { user, roles, status, logout }. <AccessAdminPage /> é a tela de papéis — não escreva a sua.

<UserMenu /> é o menu de conta — avatar com iniciais, primeiro nome no botão; abre com nome completo, e-mail e papel atual, mais os itens "Acessos" (só com OWNER) e "Sair". Não escreva o seu: é exatamente o tipo de tela que cada app reimplementava diferente antes do ADR-001.

<UserMenu
  acessosHref="/settings/access"  // rota do app pra tela de papéis; null remove o item. Default: '/acessos'
  align="right"                   // lado em que o menu abre. Default: 'right'
/>

Renderiza null enquanto a sessão carrega (status === 'loading') ou sem sessão (status === 'anonymous') — não precisa de gate próprio em volta, só ficar dentro do <AuthProvider>.

Tela de login

Desde a v1.4.0, quando <LoginGate> não recebe renderLogin, ele usa <LoginScreen> — a tela padrão do ecossistema, com um layout de duas colunas (imagem + frase à direita, formulário à esquerda). Quem já usa renderLogin continua funcionando exatamente como antes; nada muda pra quem tem tela própria.

<LoginGate
  appName="Campaign Manager"
  logoUrl="/logo-campaign.svg"
  quotes={[
    'O melhor jeito de prever o futuro é criá-lo.',
    'Feito é melhor que perfeito.',
  ]}
  quoteSignature="Time Campaign Manager"
  theme="system" // 'system' (padrão) | 'light' | 'dark'
>
  <App />
</LoginGate>
  • quotes — sorteia 1 frase por montagem da tela (não re-sorteia em re-render). Sem quotes (ou array vazio), o bloco da frase some inteiro — a imagem continua.
  • quoteSignature — assinatura abaixo da frase. Padrão: usa appName.
  • logoUrl — sem logo, mostra um monograma com a inicial maiúscula de appName.
  • tagline — padrão: "Entre com sua conta Google autorizada."
  • imagesManifestUrl — manifest público [{src, source, sourceUrl, author}] sorteado para o fundo da coluna direita. Padrão: https://components.integrattion.com.br/login-assets/manifest.json. Qualquer falha (fetch, JSON, manifest vazio) cai num gradiente CSS de fallback — a tela nunca quebra por causa da imagem, e o botão do Google nunca espera por ela.
  • theme — 'system' (padrão) segue prefers-color-scheme de verdade, inclusive trocando o tema do botão do Google sozinho se o SO mudar de esquema com a tela aberta. 'light'/'dark' força o tema.

Responsivo: duas colunas a partir de 1024px. Abaixo disso, decisão de design registrada aqui: a imagem vira uma faixa fina no topo (não desaparece) e o painel de frase some — não cabe bem em tela estreita.

<LoginScreen> também é exportado como componente puro — sem useSession, recebe tudo via props (slot, error, appName, quotes etc.). Serve pra quem quer montar o próprio wrapper de sessão em volta, ou pra preview/storybook. O dono do GSI (google.accounts.id.initialize / renderButton) continua sendo <LoginGate> — <LoginScreen> só recebe o slot já pronto.

import { LoginScreen } from '@integrattion/auth/react';

<LoginScreen
  appName="Campaign Manager"
  slot={<button>Entrar com Google</button>}
  quotes={['Frase de exemplo.']}
/>

O que este pacote NÃO faz

  • Não cria pessoa nem e-mail de login (isso é só no Partners).
  • Não decide se alguém entra — só o que faz depois de entrar.
  • Não pede escopo sensível do Google. Só openid, email, profile.

Papéis

roles é ordenado do mais forte para o mais fraco; requireRole compara por posição. O padrão é OWNER > ADMIN > EDITOR > VIEWER, mas cada app define os seus.