Applogin — login unificado
Adicione login com Google e e-mail/senha ao seu aplicativo com um único script. Toda a autenticação — login, cadastro, verificação de e-mail, redefinição de senha, Google — acontece dentro de um iframe protegido em applogin.one. Sua página nunca vê a senha do usuário e não valida nada: você recebe apenas um token restrito ao seu app, pronto para usar.
- Renderiza o formulário de login/cadastro (no próprio iframe) — você não constrói nenhum.
- Recebe a senha, confere as credenciais, envia e verifica códigos por e-mail — você não verifica nada.
- Mantém uma conta por e-mail (Google e senha apontam para a mesma conta).
- Mantém uma sessão entre aplicativos e retoma o login entre seus apps em silêncio.
Como funciona
O Applogin é um provedor de autenticação (como Auth0/Clerk), mas o formulário de login é servido em um frame do nosso domínio. Seu app abre esse frame (em um modal) pelo SDK e recebe o resultado via postMessage. O token é um JWT assinado com o segredo do seu aplicativo (aud=app_id): em qualquer outro aplicativo ele é inútil.
| Conceito | O que é |
|---|---|
| Aplicativo (app) | Uma entidade da plataforma. Tem um app_id público, um jwt_secret (verificação do token no backend) e as listas allowed_origins / redirect_uris. |
| Usuário final | Uma conta global (uma por e-mail) compartilhada por todos os aplicativos da plataforma. Google e senha apontam para a mesma conta. |
| Token de app | JWT (HS256, aud=app_id) assinado com o jwt_secret do seu app. Amparado por uma sessão revogável. |
| Sessão SSO | Sessão global no cookie HttpOnly+Partitioned al_sso em applogin.one. Compartilhada dentro de um mesmo site de nível superior. |
Início rápido
Inclua dois scripts e monte o widget: ele tenta o SSO em silêncio, mostra um botão «Entrar», abre o formulário hospedado em um frame e devolve o usuário.
<script src="https://applogin.one/applogin.js?v=1"></script>
<script src="https://applogin.one/applogin-ui.js?v=1"></script>
<script>
ApploginUI.mount({
appId: "app_your_id",
onAuth: (user) => renderApp(user), // signed in: { id, email, name, picture, email_verified }
onLogout: () => showLanding()
});
// sign-out button: ApploginUI.logout();
</script>
É isso. Formulário, cadastro, códigos por e-mail, Google e redefinição de senha ficam por conta do Applogin. O único requisito: registrar um app_id e listar suas allowed_origins (ver Criar um aplicativo).
?v=1 nas URLs dos scripts evita que o navegador sirva um SDK desatualizado do cache após atualizações.O widget ApploginUI recomendado
Um «cadeado» pronto para o seu app: enquanto o usuário está deslogado, mostra uma tela com o botão «Entrar»; um clique abre o formulário hospedado em um modal; após o login chama onAuth(user) e remove a tela.
| Método | Descrição |
|---|---|
ApploginUI.mount({ appId, onAuth, onLogout, title? }) | Montar. Tenta o SSO silencioso; se deslogado, mostra a tela «Entrar». |
ApploginUI.logout() | Sair (revoga a sessão, mostra a tela de novo). |
ApploginUI.getUser() | O usuário atual ou null. |
O perfil (avatar, nome, e-mail) e o botão de sair você mesmo renderiza em onAuth(user) — essa é a sua UI. Os dados do usuário chegam prontos.
Métodos do SDK (applogin.js) baixo nível
Se você quiser sua própria UX em vez do widget, use o SDK diretamente. Chame primeiro Applogin.init({ appId }). O token fica no localStorage sob al_token_<appId>.
| Método | Descrição | Retorna |
|---|---|---|
init({ appId }) | Inicialização. | — |
getSession() | SSO silencioso: retoma a sessão se o usuário entrou em outro app do mesmo site. | { authenticated, token, user } |
openLogin() | Abre o modal do formulário hospedado (iframe em applogin.one). | { token, user, lang } ou null |
verify() | Verifica o token atual. | { valid, user } |
logout() | Sair (revoga a sessão e limpa o token). | — |
getToken() | O token de app atual. | string | null |
Applogin.init({ appId: "app_xxx" });
// on load — silently try SSO:
const s = await Applogin.getSession();
if (s.authenticated) showApp(s.user);
else {
const r = await Applogin.openLogin(); // modal with the applogin.one form
if (r) showApp(r.user);
}
// attach Applogin.getToken() to your backend requests
Login único (SSO)
No login, o Applogin grava o cookie al_sso com o atributo Partitioned. A chave da partição é o site de nível superior (o mais externo). Portanto:
- Vários dos seus apps sob um mesmo site (ex.: incorporados em
appdock.pro) compartilham a sessão →getSession()no segundo app retoma o login sem formulário. - O mesmo app aberto como site separado (outro nível superior) é outra partição → o usuário entra de novo.
const s = await Applogin.getSession(); // ← {authenticated:true,…} if a session exists in this partition
if (s.authenticated) showApp(s.user);
allowed_origins de um app precisam listar o próprio domínio e o domínio que o envolve (ex.: appdock.pro).allowed_origins (um site estranho nunca recebe um token).Idiomas
O formulário de login hospedado fala 10 idiomas: English, Deutsch, Français, Español, Italiano, Português, 日本語, 한국어, 中文, Русский. Por padrão ele abre no idioma do navegador do usuário (inglês como reserva); o idioma pode ser trocado direto no formulário — o menu de bandeiras embaixo.
- Forçar um idioma. Passe
langao widget ou ao SDK:ApploginUI.mount({ appId, lang: "pt" })ouApplogin.init({ appId, lang: "pt" })— o formulário abre nesse idioma. Sem a opção, o SDK envia automaticamente o idioma do navegador. - Ler a escolha de volta. O usuário pode trocar o idioma dentro do formulário. O resultado de
Applogin.openLogin()contémlang— o idioma do formulário no momento do login — para a sua página acompanhar. O widget também o guarda (localStorageal_lang), e o próximo formulário abrirá nele. - Os e-mails seguem o formulário. Os e-mails de verificação e redefinição são enviados no idioma do formulário.
Por baixo dos panos a URL do formulário aceita ?lang=xx (código de duas letras da lista acima) — o SDK o envia por você.
Exemplo ao vivo: AppDock
appdock.pro é um lançador tipo «dock»: uma página que abre vários aplicativos em iframes. Os aplicativos vivem em seus próprios domínios:
| Aplicativo | Domínio | app_id |
|---|---|---|
| Email Writer | emailwriter.online | app_emailwriter |
| Audio Recorder | audiorecorder.info | app_recorder |
Entre no Email Writer dentro do dock e depois abra o Audio Recorder (também no dock): o login é retomado automaticamente, porque ambos rodam sob o mesmo site de nível superior appdock.pro e compartilham uma partição SSO.
1. O lançador (appdock.pro)
<button class="tile" data-src="https://emailwriter.online/">Email Writer</button>
<button class="tile" data-src="https://audiorecorder.info/">Audio Recorder</button>
<iframe id="frame" allow="microphone; clipboard-write"></iframe>
<script>
document.querySelectorAll(".tile").forEach(t =>
t.onclick = () => document.getElementById("frame").src = t.dataset.src);
</script>
2. Um aplicativo (ex.: emailwriter.online)
<script src="https://applogin.one/applogin.js?v=1"></script>
<script src="https://applogin.one/applogin-ui.js?v=1"></script>
<script>
ApploginUI.mount({
appId: "app_emailwriter",
title: "Email Writer — sign in",
onAuth: (user) => { // render the profile + the app
header.textContent = user.name + " · " + user.email;
app.hidden = false;
},
onLogout: () => { app.hidden = true; }
});
</script>
3. Registro dos apps para este cenário
Cada aplicativo lista em allowed_origins seu próprio domínio + o domínio do dock (frame-ancestors vê toda a cadeia de ancestrais do frame aninhado):
app_emailwriter → allowed_origins: ["https://emailwriter.online", "https://appdock.pro"]
app_recorder → allowed_origins: ["https://audiorecorder.info", "https://appdock.pro"]
// redirect_uris (for Google): ["https://applogin.one/auth-callback.html"]
ApploginUI.mount.Verificando o token no seu backend
Seu frontend coloca Applogin.getToken() no cabeçalho Authorization das requisições. No backend há duas formas de verificação.
1. Pelo endpoint da plataforma considera revogação
POST https://applogin.one/api/v1/session/verify
{ "app_id": "app_xxx", "token": "<JWT from Authorization>" }
// → { "valid": true, "user": { "id": 2, "email": "…", "email_verified": true, "name": "…", "picture": null } }
// invalid/revoked (logout) → { "valid": false, "user": null }
2. Localmente (HS256 com seu jwt_secret) sem rede
// Node.js
const jwt = require("jsonwebtoken");
const claims = jwt.verify(token, process.env.APPLOGIN_JWT_SECRET, {
algorithms: ["HS256"], audience: "app_xxx", issuer: "applogin"
});
// claims.sub — user id, claims.email, claims.email_verified
# Python
import jwt
claims = jwt.decode(token, APPLOGIN_JWT_SECRET, algorithms=["HS256"],
audience="app_xxx", issuer="applogin")
/v1/session/verify.Estrutura do JWT
{
"iss": "applogin",
"aud": "app_xxx", // your app_id
"sub": "2", // user id (as a string)
"jti": "…", // session id (for revocation)
"email": "user@example.com",
"email_verified": true,
"name": "Jane", "picture": null,
"iat": 1782194619, "exp": 1784786619 // ~30 days
}
Webhook (opcional)
Se um aplicativo define um webhook_url, a plataforma envia para lá um POST assinado com a identidade verificada a cada login Google bem-sucedido — para sincronização no servidor além do token.
| Cabeçalho | Valor |
|---|---|
X-Applogin-Timestamp | unix-ms |
X-Applogin-Signature | sha256=<hex> de timestamp + "." + rawBody |
const exp = "sha256=" + crypto.createHmac("sha256", WEBHOOK_SIGNING_SECRET)
.update(ts + "." + rawBody).digest("hex");
if (!crypto.timingSafeEqual(Buffer.from(exp), Buffer.from(sig))) reject();
Criar um aplicativo
Os aplicativos são criados no painel privado applogin.one/dashboard (login pelo próprio Applogin). Você informa:
| Campo | Para quê |
|---|---|
name | Aparece no formulário de login («Entrar · <name>»). |
allowed_origins | Origens autorizadas a incorporar o formulário e receber tokens. Liste o domínio do app + o domínio que o envolve (ex.: o dock). |
redirect_uris | Para o login Google: https://applogin.one/auth-callback.html. |
webhook_url | (opcional) para onde enviar o webhook de login. |
Você recebe: app_id (público), jwt_secret (verificação do token no backend), client_secret, webhook_signing_secret.
API REST — referência
Base: https://applogin.one/api. Abaixo, o que um integrador realmente precisa. Os endpoints de e-mail/senha e de troca do Google são chamados pelo próprio formulário hospedado — nunca por você.
Para o integrador
Verificar um token de app no backend (com revogação). { app_id, token } → { valid, user }.
Dados públicos do aplicativo (name, allowed_origins). Usados pela página de login hospedada.
Internos (chamados pelo formulário hospedado/SDK, não por você)
| Endpoint | Papel |
|---|---|
POST /v1/email/register · verify · resend · login · reset/request · reset/confirm · password/change | e-mail/senha — chamados pelo formulário hospedado /login. |
POST /v1/auth/start, GET /oauth/google/callback, POST /v1/auth/exchange | OAuth do Google (dentro do formulário hospedado). |
POST /v1/session/sso | SSO silencioso (chamado por /session de um iframe oculto). |
POST /v1/session/establish | Grava o cookie SSO na partição correta (após o Google). |
POST /v1/session/logout | Revogação da sessão (pelo SDK logout()). |
Erros
| HTTP | Quando |
|---|---|
| 400 | Entrada inválida (senha curta, código inválido/expirado, «Email already registered»). |
| 403 | «Invalid credentials», acesso negado, «Too many attempts» (limite de tentativas). |
| 404 | Aplicativo/rota desconhecidos. |
{"error":"Invalid or expired code","message":"Invalid or expired code"}
Segurança
- A senha é isolada. Os campos de entrada existem apenas dentro do iframe de applogin.one; o JS do site integrador não os alcança.
- Tokens restritos ao app. O JWT é assinado com o segredo do aplicativo e carrega
aud=app_id— o token de um app é inválido em outro. - Entrega do token apenas às suas origens. O formulário envia o token via
postMessageapenas para uma origem deallowed_origins; a página de login é servida comContent-Security-Policy: frame-ancestors <allowed_origins>(anti-clickjacking). - A sessão global é HttpOnly. O cookie
al_ssoé inacessível ao JS; o integrador só tem em mãos um token de app. - Anti-CSRF no SSO.
/v1/session/ssoemite um token apenas paraOrigin ∈ allowed_origins— um site estranho com o cookie do usuário não recebe nada. - Anti-força bruta. Limites de tentativas em login/reset/verify (por e-mail e por IP).
- As senhas são armazenadas com hash (PBKDF2); os códigos com hash, TTL de 10 minutos e limite de tentativas; HTTPS em tudo; os tokens do Google nunca são armazenados. Login Google com PKCE (S256) + state + nonce.
Cola para LLM
Modelo: toda a autenticação acontece em um iframe em applogin.one. O integrador NÃO renderiza formulário, NÃO envia senhas, NÃO verifica códigos. Ele inclui SDK + widget e recebe um token de app.
// include
<script src=https://applogin.one/applogin.js?v=1></script>
<script src=https://applogin.one/applogin-ui.js?v=1></script>
// mount (a lock on the app)
ApploginUI.mount({ appId, onAuth:(user)=>..., onLogout:()=>... });
ApploginUI.logout();
// low level
Applogin.init({ appId });
await Applogin.getSession(); // {authenticated, token, user} — silent SSO
await Applogin.openLogin(); // {token, user, lang}|null — modal with the form
Applogin.getToken(); await Applogin.verify(); await Applogin.logout();
// backend: verify the token
POST https://applogin.one/api/v1/session/verify {app_id, token} -> {valid, user}
// or locally: jwt.verify(token, jwt_secret, {algorithms:["HS256"], audience:app_id, issuer:"applogin"})
SSO: o login grava o cookie al_sso (Partitioned, por site de nível superior). Apps sob o mesmo site (ex.: iframes de um dock como appdock.pro) compartilham a sessão; um domínio separado → novo login. As allowed_origins de um app = seu domínio + o domínio que o envolve.
O token é restrito ao app: iss=applogin, aud=app_id, sub=id do usuário, assinado com o jwt_secret do app.
Applogin · login unificado · painel · exemplo ao vivo: AppDock