# Entrar com Vimine

> O fluxo OAuth 2.1 + PKCE do clique ao callback, a sessão, as chamadas à API e o logout, com e sem o SDK.

URL: https://developers.vimine.network/pt/guides/sign-in/

Os associados de uma associação entram no seu site com a conta Vimine deles e autorizam você, com um consentimento
explícito, a usar alguns dos seus dados. É OAuth 2.1 com PKCE: a senha só é digitada na página do Vimine, nunca na
sua; o seu site recebe tokens limitados às permissões concedidas.

:::note[Antes de começar]
Você precisa de um cliente **Site** ou **App nativo** com o seu `redirect_uri` registrado — veja
[Registrar um cliente](https://developers.vimine.network/pt/start/register-a-client/) — e do SDK instalado ([Instalar o SDK](https://developers.vimine.network/pt/start/install/)).
Para desenvolver sem tocar em dados reais, use um cliente de **teste** e o [sandbox](https://developers.vimine.network/pt/guides/sandbox/).
:::

## O fluxo

1. A partir de um **clique** do associado, o seu site manda o navegador (a janela principal, nunca um iframe) para a
   página de autorização:
   ```
   https://app.vimine.network/authorize
       ?client_id=vmc_…&redirect_uri=https://www.example.org/vimine/callback
       &response_type=code&state=…&code_challenge=…&code_challenge_method=S256
       &scope=profile:read%20membership:read
   ```
2. O associado entra (se ainda não tiver entrado) e vê **quem** está recebendo **o quê**. Ele confirma ou cancela.
3. O Vimine manda o navegador de volta para o seu `redirect_uri` com `code` e `state` (ou `error=access_denied`).
4. O seu site troca o código em `POST https://api.vimine.network/v1/oauth/token`
   (`grant_type=authorization_code`, `code`, `code_verifier`, `client_id`, `redirect_uri`) e recebe um
   access token (10 minutos) e um refresh token (rotativo; 30 dias, 14 de inatividade).

O SDK faz tudo isso por você.

## Com o SDK

```js title="qualquer página"
import { Vimine } from '@vimine/sdk';

const vimine = new Vimine({
    clientId: 'vmc_…',
    redirectUri: 'https://www.example.org/vimine/callback',
    scopes: ['profile:read', 'membership:read']
});

// a partir de um clique: `returnTo` é um estado seu, você o recebe de volta depois do callback
document.querySelector('#sign-in').addEventListener('click', () => vimine.signIn({ returnTo: location.pathname }));
```

```js title="página de callback"
const result = await vimine.handleRedirect();   // null quando a URL não traz parâmetros de login
if (result) location.replace(result.returnTo || '/');
```

Opções de `signIn()`:

| Opção | Efeito |
|---|---|
| `scopes` | as permissões a pedir neste login (padrão: as do construtor, ou `profile:read membership:read`) |
| `prompt: 'login'` | força o formulário de credenciais mesmo com uma sessão Vimine ativa |
| `prompt: 'consent'` | mostra sempre a tela de consentimento |
| `returnTo` | um estado seu (por exemplo, a página de onde o associado partiu), guardado localmente e devolvido por `handleRedirect()` |

`handleRedirect()` lança um [`VimineError`](https://developers.vimine.network/pt/sdk/errors/) com `code` `access_denied` quando o associado
cancelou, `state_mismatch` ou `no_flow` quando o retorno não corresponde a um login iniciado neste navegador.

## A sessão

- Os tokens ficam no `sessionStorage` (por aba). `storage: 'local'` os compartilha entre as abas e sincroniza o logout;
  `'memory'` nunca os persiste. Você pode passar um adaptador seu.
- `vimine.getAccessToken()` renova sozinho 30 segundos antes do vencimento; uma chamada que recebe 401 é repetida uma
  vez depois da renovação. Um refresh token **reutilizado** (um copiado, por exemplo) revoga toda a família de sessões.
- `vimine.onChange(session => …)` avisa sobre login, renovação e logout.
- `vimine.getSession().sub` é o identificador do associado **para a sua associação** (`vms_…`): estável no tempo,
  diferente em cada associação, nunca um id interno.

## O que você pode pedir

```js
await vimine.me.get();                                     // profile:read
await vimine.me.update({ phone: '+39 …' });                // profile:write
await vimine.membership.get();                             // membership:read — status, verdict, expires_at, statuto, card
await vimine.membership.events({ limit: 20 });             // histórico de status
await vimine.membership.statuto();                         // o statuto em vigor e se o associado o aceitou
await vimine.membership.acceptStatuto({ version: 3 });     // statuto:accept
await vimine.membership.request({ accept_statuto: { version: 3 }, privacy_notice: { version: 2 } });   // membership:request → carteirinha pendente
await vimine.membership.card();                            // o token da carteirinha (QR) e a sua janela
await vimine.legal.acceptances();                          // legal:read → o que a pessoa aceitou e o que ainda está pendente
await vimine.legal.record({ kind: 'privacy_notice', version: 2 });   // legal:accept → ciência do aviso da associação
await vimine.connections.list();  await vimine.connections.revoke('vmc_…');
```
:::note[Documentos jurídicos]
`legal.acceptances()` lista as aceitações da pessoa e, em `pending`, os documentos ainda a confirmar na sua versão
em vigor: as condições de uso da conta e o aviso de privacidade da plataforma (`platform`), o aviso desta associação
aos associados (`privacy_notice`). Mostre o texto (`GET /v1/legal/{kind}`, `GET /v1/aps/{slug}/privacy-notice`) e
registre a confirmação com `legal.record()`: a versão precisa ser a que está em vigor, senão `422 <kind>_outdated`.
:::
:::note[Ativação]
O que acontece com um pedido (`membership.request()`) depende de **como a associação admite os seus associados** — `admission` no perfil público, explicado em [Admissão e ativação](https://developers.vimine.network/pt/guides/admission/). Se quem decide é a diretoria, ele fica `pending` com `pending_reasons` ordenados (`approval`, depois `payment`) e a taxa só é paga depois da admissão (`payment_open`); caso contrário, ele já nasce **ativo** quando o tipo é gratuito, ou quando a taxa é registrada. Uma carteirinha ativa pode trazer um `valid_from` no futuro: a carteirinha vale na entrada a partir daí. Mostre ao associado `quota` e `payment_instructions` sempre que `payment` estiver presente.
:::

`verdict` é o que conta na entrada: `valid`, `expired`, `statuto_required` (nova aceitação atrasada) ou
`inactive`. Quem ainda não é associado também pode entrar e usar `membership.request`: o consentimento às
permissões de adesão também é permitido a quem não é associado; as outras permissões exigem uma carteirinha
naquela associação.

Cada método está detalhado em [`Vimine`](https://developers.vimine.network/pt/sdk/browser/); as respostas, em [Tipos](https://developers.vimine.network/pt/sdk/types/).

## O logout

```js
await vimine.signOut();                        // revoga a sessão da API e a esquece
await vimine.signOut({ everywhere: true });    // também encerra a sessão Vimine do associado e volta para o seu site
```

Com `everywhere`, o navegador passa por
`https://app.vimine.network/oauth/logout?client_id=…&post_logout_redirect_uri=…`; o endereço de retorno precisa estar
numa origem registrada para o cliente. Quando o associado sai do Vimine, todas as sessões de API dos apps dele são
revogadas (single sign-out); o mesmo acontece quando ele revoga um app em **Apps conectados** ou redefine a
senha.

## Sem o SDK

Se você não pode usar o SDK (outra linguagem, uma plataforma low-code), o fluxo é OAuth 2.1 padrão.

**Autorização** — `GET https://app.vimine.network/authorize`

| Parâmetro | |
|---|---|
| `client_id` | o seu `vmc_…` |
| `redirect_uri` | um dos registrados, idêntico |
| `response_type` | `code` |
| `state` | valor aleatório, para comparar no retorno |
| `code_challenge`, `code_challenge_method` | PKCE, só `S256` |
| `scope` | permissões separadas por espaço |
| `prompt` | opcional: `login`, `consent` |
| `ui_locales` | opcional: um dos idiomas do Vimine — `it` (padrão), `en`, `zh-Hans`, `zh-Hant`, `fr`, `es`, `de`, `pt-BR` |

**Troca** — `POST https://api.vimine.network/v1/oauth/token`, corpo `application/x-www-form-urlencoded`:

```
grant_type=authorization_code&code=…&code_verifier=…&client_id=vmc_…&redirect_uri=…
```

```json title="resposta"
{ "access_token": "…", "token_type": "Bearer", "expires_in": 600, "refresh_token": "…",
  "scope": "profile:read membership:read", "sub": "vms_…" }
```

**Renovação** — o mesmo endpoint com `grant_type=refresh_token&refresh_token=…&client_id=…`: a resposta traz
um **novo** refresh token (o antigo continua válido por 15 segundos para as requisições concorrentes; depois, reutilizá-lo
revoga toda a família).

**Revogação** — `POST /v1/oauth/revoke` com `token=…&token_type_hint=refresh_token` (RFC 7009).

**Descoberta** — `GET https://api.vimine.network/.well-known/oauth-authorization-server` (RFC 8414) lista
endpoints, escopos e métodos suportados.

Os erros desses endpoints usam o formato OAuth: `{ "error": "invalid_grant", "error_description": "…" }`.
