Entrar com vsync (OAuth2)
Deixe pessoas entrarem no seu site ou app com a conta vsync: fluxo Authorization Code com PKCE, endpoints, escopos e exemplos.
Com Entrar com vsync o seu site ou app identifica uma pessoa pela conta dela no vsync, sem pedir senha. É o fluxo OAuth2 Authorization Code, com PKCE opcional. Qualquer desenvolvedor pode usar: basta ter um aplicativo no Portal do Desenvolvedor.
Como funciona#
- Seu site manda a pessoa para
https://vsync.lat/oauth2/authorizecomclient_id,redirect_uri,scopeestate. - O vsync pede login (se preciso) e mostra a tela de consentimento, com o nome do app, o que ele vai acessar e o domínio de destino.
- Se a pessoa clicar em Autorizar, ela volta para a sua
redirect_uricom?code=...&state=.... Se clicar em Cancelar, volta com?error=access_denied&state=.... - O servidor do seu site troca o
codepor umaccess_tokenemPOST https://api.vsync.lat/oauth2/token. - Com o
access_tokenvocê chamaGET https://api.vsync.lat/oauth2/userinfoe cria a sessão da pessoa no seu site.
Configurar o aplicativo#
No Portal do Desenvolvedor, abra o aplicativo e vá na aba OAuth2:
- Client ID: é o id do aplicativo.
- Client Secret: clique em Gerar secret. Ele aparece uma única vez e só o hash fica guardado conosco; redefinir invalida o antigo na hora. Use só no servidor, nunca em código que roda no navegador ou no celular.
- Redirect URIs: até 10 endereços. A comparação é exata (caminho, query e barra final contam). Só
https://; ohttp://é aceito apenas para o endereço local de desenvolvimento127.0.0.1. Fragmentos (#) e usuário/senha na URL não são permitidos. Nunca redirecionamos para um endereço que não esteja na lista. - Gerador de link: monta o link de autorização com os escopos que você marcar.
Escopos#
| Escopo | O que libera |
|---|---|
identify | GET /oauth2/userinfo e GET /oauth2/@me com id, usuário, nome de exibição e avatar |
email | Inclui email e verified no userinfo. Precisa vir junto com identify |
guilds | GET /oauth2/guilds: servidores da pessoa, com ícone e as permissões dela |
Separe os escopos por espaço. Um escopo desconhecido faz o pedido falhar com invalid_scope. O escopo bot não pode ser misturado com estes.
Passo 1: o link de autorização#
https://vsync.lat/oauth2/authorize?client_id=ID_DO_APP&response_type=code&redirect_uri=https%3A%2F%2Fseusite.com%2Fauth%2Fcallback&scope=identify%20email&state=VALOR_ALEATORIO&code_challenge=DESAFIO&code_challenge_method=S256| Parâmetro | Obrigatório | Descrição |
|---|---|---|
client_id | sim | Id do aplicativo |
redirect_uri | sim | Uma das redirect URIs cadastradas, idêntica |
scope | sim | Escopos separados por espaço |
response_type | não | Se enviado, deve ser code |
state | recomendado | Valor aleatório que você guarda e confere na volta (proteção contra CSRF) |
code_challenge | recomendado | PKCE: SHA-256 do code_verifier, em base64url (43 caracteres) |
code_challenge_method | com PKCE | Sempre S256 |
O código tem 5 minutos de validade e só pode ser usado uma vez.
PKCE#
PKCE protege o código mesmo que alguém o intercepte, e permite apps sem servidor (sem secret). Gere um code_verifier aleatório por login, mande o code_challenge no passo 1 e o code_verifier no passo 2:
import { createHash, randomBytes } from "node:crypto";
const verifier = randomBytes(32).toString("base64url");
const challenge = createHash("sha256").update(verifier).digest("base64url");Se o pedido de autorização levou um code_challenge, a troca exige o code_verifier correto, mesmo com client_secret. Sem client_secret, a troca só é aceita com PKCE.
Passo 2: trocar o código por token#
POST https://api.vsync.lat/oauth2/token, em application/x-www-form-urlencoded ou JSON. A autenticação do cliente vai por client_id e client_secret no corpo, ou por HTTP Basic (client_id:client_secret).
curl -X POST https://api.vsync.lat/oauth2/token \
-d grant_type=authorization_code \
-d code=CODIGO_RECEBIDO \
-d redirect_uri=https://seusite.com/auth/callback \
-d client_id=ID_DO_APP \
-d client_secret=SECRET_DO_APP \
-d code_verifier=VERIFIERconst res = await fetch("https://api.vsync.lat/oauth2/token", {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({
grant_type: "authorization_code",
code,
redirect_uri: "https://seusite.com/auth/callback",
client_id: process.env.VSYNC_CLIENT_ID,
client_secret: process.env.VSYNC_CLIENT_SECRET,
code_verifier: verifier,
}),
});
const tokens = await res.json();Resposta:
{
"access_token": "vsat_...",
"token_type": "Bearer",
"expires_in": 604800,
"refresh_token": "vsrt_...",
"scope": "identify email"
}O access_token vale 7 dias. Guarde apenas no servidor. Se um mesmo code for apresentado duas vezes, o segundo uso falha e todos os tokens emitidos a partir dele são revogados.
Renovar o token#
curl -X POST https://api.vsync.lat/oauth2/token \
-d grant_type=refresh_token \
-d refresh_token=REFRESH_TOKEN \
-d client_id=ID_DO_APP \
-d client_secret=SECRET_DO_APPA renovação faz rotação: você recebe um novo par de tokens e o antigo deixa de valer. Você pode pedir um scope menor, nunca maior que o original.
Chamar a API como a pessoa#
Envie Authorization: Bearer ACCESS_TOKEN. Esse token só funciona nos endpoints abaixo; ele não vale como sessão e não acessa nenhuma outra rota da API.
curl https://api.vsync.lat/oauth2/userinfo \
-H "Authorization: Bearer ACCESS_TOKEN"const user = await fetch("https://api.vsync.lat/oauth2/userinfo", {
headers: { Authorization: `Bearer ${tokens.access_token}` },
}).then((r) => r.json());
// { id, username, displayName, avatarUrl, bannerUrl, createdAt, email?, verified? }Use o id como identificador estável da pessoa; o nome de usuário pode mudar. email e verified só aparecem com o escopo email.
Referência dos endpoints#
| Método e caminho | Autenticação | Descrição |
|---|---|---|
GET /oauth2/authorize/info | sessão da pessoa | Valida o pedido e devolve os dados da tela de consentimento |
POST /oauth2/authorize | sessão da pessoa | Emite o código e devolve redirectUrl |
POST /oauth2/token | cliente | authorization_code e refresh_token |
POST /oauth2/token/revoke | cliente | Revoga um access_token ou refresh_token (campo token) |
GET /oauth2/@me | Bearer | Aplicativo, escopos, expiração e, com identify, o usuário |
GET /oauth2/userinfo | Bearer com identify | Dados públicos da conta |
GET /oauth2/guilds | Bearer com guilds | id, name, iconUrl, owner e permissions de cada servidor |
GET /oauth2/authorizations | sessão da pessoa | Apps que a pessoa autorizou |
DELETE /oauth2/authorizations/:appId | sessão da pessoa | Revoga todos os tokens daquele app |
Para o dono do aplicativo: GET e PUT /developer/applications/:id/oauth2 (lista redirectUris) e POST /developer/applications/:id/oauth2/reset-secret.
Erros#
O endpoint de token responde no formato OAuth2, { "error": "...", "error_description": "..." }:
error | Quando |
|---|---|
invalid_client (401) | client_id desconhecido, client_secret errado, ou cliente sem secret e sem PKCE |
invalid_grant | Código usado, expirado ou de outro app; redirect_uri diferente; code_verifier errado; refresh token inválido |
invalid_scope | Escopo desconhecido ou tentativa de ampliar escopos ao renovar |
invalid_request | Parâmetro obrigatório faltando |
unsupported_grant_type | Só authorization_code e refresh_token |
Os endpoints com Bearer respondem 401 para token inválido, expirado ou revogado, e 403 quando falta o escopo. Há limite de requisições por IP no endpoint de token; veja Erros e limites.
Controle da pessoa#
Em Configurações > Apps autorizados a pessoa vê quais apps têm acesso e pode revogar o acesso a qualquer momento. Revogar derruba todos os tokens e a renovação passa a falhar; trate isso como "sessão encerrada" no seu site.
Boas práticas#
- Confira o
statena volta e descarte se não bater. - Faça a troca do código e as chamadas à API no servidor; navegadores bloqueiam essas chamadas feitas direto de outros sites.
- Use PKCE sempre que possível.
- Não guarde o
client_secretno repositório; use variáveis de ambiente. - Peça só os escopos de que precisa.