npm package: @intelicity/gates-auth
Description: Framework-agnostic AWS Cognito authentication library with multi-tenant support
Latest version: 0.1.4

# @intelicity/gates-auth

Biblioteca de autenticação AWS Cognito — framework-agnostic, multi-tenant, com PKCE nativo e suporte a popup e redirect.

## Instalação

```bash
npm install @intelicity/gates-auth
# ou
pnpm add @intelicity/gates-auth
```

> React adapter incluído no mesmo pacote via `@intelicity/gates-auth/react`. Requer React >= 18 como peer dependency.

---

## Uso básico

```typescript
import { CognitoAuth } from '@intelicity/gates-auth';

const auth = new CognitoAuth({
  domain:      'auth.empresa.com',
  clientId:    'seu-client-id',
  redirectUri: 'https://app.com/callback',
});

await auth.signIn();
```

---

## Adapter React

```tsx
// src/auth.ts
import { CognitoAuth } from '@intelicity/gates-auth';

export const auth = new CognitoAuth({
  domain:      'auth.empresa.com',
  clientId:    'seu-client-id',
  redirectUri: 'https://app.com',
});
```

```tsx
// src/main.tsx
import { AuthProvider } from '@intelicity/gates-auth/react';
import { auth } from './auth';

createRoot(document.getElementById('root')!).render(
  <AuthProvider auth={auth} handleCallback>
    <App />
  </AuthProvider>
);
```

```tsx
// src/components/Navbar.tsx
import { useAuth } from '@intelicity/gates-auth/react';

function Navbar() {
  const { isAuthenticated, isLoading, signIn, signOut } = useAuth();

  if (isLoading) return <Spinner />;

  return isAuthenticated
    ? <button onClick={() => signOut()}>Sair</button>
    : <button onClick={() => signIn()}>Entrar</button>;
}
```

---

## Configuração

| Parâmetro | Tipo | Obrigatório | Padrão | Descrição |
|-----------|------|:-----------:|--------|-----------|
| `domain` | `string` | ✅ | — | Domínio do Cognito Hosted UI (sem `https://`) |
| `clientId` | `string` | ✅ | — | App Client ID no User Pool |
| `redirectUri` | `string` | ✅ | — | URL de callback registrada no Cognito |
| `strategy` | `'redirect' \| 'popup'` | — | `'redirect'` | Estratégia de autenticação |
| `loginMethod` | `'directLogin' \| 'federation'` | — | `'directLogin'` | Endpoint de login |
| `storage` | `'localStorage' \| 'sessionStorage' \| 'memory'` | — | `'localStorage'` | Onde persistir a sessão |
| `autoRefresh` | `boolean` | — | `true` | Renova tokens automaticamente antes de expirar |
| `refreshThresholdSeconds` | `number` | — | `300` | Segundos antes do vencimento para renovar |

---

## Fluxo redirect

```typescript
// Iniciar login
await auth.signIn(); // navega para o Cognito

// Na página de callback
if (new URLSearchParams(location.search).has('code')) {
  await auth.handleCallback();
  window.history.replaceState({}, '', location.pathname);
}
```

## Fluxo popup

```typescript
const auth = new CognitoAuth({ ..., strategy: 'popup' });

try {
  await auth.signIn(); // aguarda o login na janela popup
} catch (err) {
  if (err.code === 'popup_closed') { /* usuário fechou */ }
}
```

---

## Lendo o estado

```typescript
// Snapshot pontual
const { status, user, tokens, error } = auth.getState();

// Reativo
const unsubscribe = auth.on('stateChange', ({ state }) => {
  console.log(state.status); // 'idle' | 'pending' | 'authenticated' | 'error' | 'unauthenticated'
});
unsubscribe(); // cancelar
```

## Chamadas autenticadas

```typescript
// Retorna token válido, renovando automaticamente se necessário
const token = await auth.getValidAccessToken();

await fetch('https://api.empresa.com/dados', {
  headers: { Authorization: `Bearer ${token}` },
});
```

## Sign out

```typescript
await auth.signOut();                          // logout simples
await auth.signOut({ global: true });          // revoga refresh token
await auth.signOut({ strategy: 'popup' });     // sem navegar a página principal
```

---

## Eventos

```typescript
auth.on('signIn',         ({ user, tokens }) => { });
auth.on('signOut',        ()                => { });
auth.on('tokenRefreshed', ({ tokens })      => { });
auth.on('error',          ({ error })       => { });
auth.on('stateChange',    ({ state })       => { });
auth.on('any',            (payload)         => { }); // todos os eventos
```

---

## Tipos exportados

```typescript
import type {
  CognitoAuthConfig,
  AuthState,
  AuthStatus,
  AuthUser,
  AuthTokens,
  AuthError,
  AuthEventType,
  SignOutOptions,
  Strategy,
  StorageType,
  LoginMethod,
} from '@intelicity/gates-auth';
```

---

## Múltiplas instâncias

Cada instância tem sua própria store isolada — ideal para microfrontends com múltiplos App Clients no mesmo User Pool.

```typescript
const authAppA = new CognitoAuth({ clientId: 'client-app-a', ... });
const authAppB = new CognitoAuth({ clientId: 'client-app-b', ... });
```

---

## Uso via CDN (projetos legados)

Para projetos sem bundler, a biblioteca está disponível como bundle IIFE via jsDelivr:

```html
<!-- Sempre a versão mais recente -->
<script src="https://unpkg.com/@intelicity/gates-auth/dist/cdn/gates-auth.global.js"></script>

<!-- Versão fixada (recomendado em produção) -->
<script src="https://unpkg.com/@intelicity/gates-auth@0.1.3/dist/cdn/gates-auth.global.js"></script>
```

Após carregar o script, `GatesAuth` fica disponível globalmente:

```html
<script>
  var auth = new GatesAuth.CognitoAuth({
    domain:      'auth.empresa.com',
    clientId:    'seu-client-id',
    redirectUri: window.location.origin,
  });

  // Iniciar login
  document.getElementById('btn-login').addEventListener('click', function () {
    auth.signIn();
  });

  // Processar callback (fluxo redirect)
  if (new URLSearchParams(window.location.search).has('code')) {
    auth.handleCallback().then(function () {
      window.history.replaceState({}, '', window.location.pathname);
    });
  }

  // Reagir a mudanças de estado
  auth.on('stateChange', function (payload) {
    var state = payload.state;
    if (state.status === 'authenticated') {
      console.log('Usuário:', state.user.name);
    }
  });
</script>
```

> O adapter React **não está disponível** via CDN — é exclusivo para projetos com bundler.

---

## Requisitos

- Ambiente com suporte a **Web Crypto API** (`crypto.subtle`) — todos os browsers modernos e Node.js >= 15
- **PKCE** sempre ativo — gerado internamente, invisível para o consumidor
- React adapter requer **React >= 18**