Applogin — accesso unificato
Aggiungi l'accesso con Google ed email/password alla tua applicazione con un solo script. Tutta l'autenticazione — accesso, registrazione, verifica dell'email, reset della password, Google — avviene dentro un iframe protetto su applogin.one. La tua pagina non vede mai la password dell'utente e non verifica nulla: ricevi solo un token limitato alla tua app già pronto.
- Disegna il modulo di accesso/registrazione (nel proprio iframe) — tu non ne costruisci nessuno.
- Riceve la password, controlla le credenziali, invia e verifica i codici via email — tu non verifichi nulla.
- Mantiene un account per email (Google e password puntano allo stesso account).
- Mantiene una sessione tra le applicazioni e riprende l'accesso tra le tue app in silenzio.
Come funziona
Applogin è un provider di autenticazione (come Auth0/Clerk), ma il modulo di accesso è servito in un frame dal nostro dominio. La tua app apre quel frame (in una modale) tramite l'SDK e riceve il risultato via postMessage. Il token è un JWT firmato con il segreto della tua applicazione (aud=app_id): in qualsiasi altra applicazione è inutilizzabile.
| Concetto | Che cos'è |
|---|---|
| Applicazione (app) | Un'entità della piattaforma. Ha un app_id pubblico, un jwt_secret (verifica del token nel backend) e le liste allowed_origins / redirect_uris. |
| Utente finale | Un account globale (uno per email) condiviso da tutte le applicazioni della piattaforma. Google e password puntano allo stesso account. |
| Token di app | JWT (HS256, aud=app_id) firmato con il jwt_secret della tua app. Sostenuto da una sessione revocabile. |
| Sessione SSO | Sessione globale nel cookie HttpOnly+Partitioned al_sso su applogin.one. Condivisa all'interno dello stesso sito di primo livello. |
Avvio rapido
Includi due script e monta il widget: tenta l'SSO in silenzio, mostra un pulsante «Accedi», apre il modulo ospitato in un frame e restituisce l'utente.
<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>
Tutto qui. Modulo, registrazione, codici via email, Google e reset della password sono gestiti da Applogin. L'unico requisito: registrare un app_id ed elencare le tue allowed_origins (vedi Creare un'applicazione).
?v=1 negli URL degli script impedisce al browser di servire un SDK obsoleto dalla cache dopo gli aggiornamenti.Il widget ApploginUI consigliato
Un «lucchetto» pronto per la tua app: finché l'utente non è connesso mostra una schermata con il pulsante «Accedi»; un clic apre il modulo ospitato in una modale; dopo l'accesso chiama onAuth(user) e rimuove la schermata.
| Metodo | Descrizione |
|---|---|
ApploginUI.mount({ appId, onAuth, onLogout, title? }) | Monta. Tenta l'SSO silenzioso; se disconnesso, mostra la schermata «Accedi». |
ApploginUI.logout() | Esci (revoca la sessione, mostra di nuovo la schermata). |
ApploginUI.getUser() | L'utente corrente o null. |
Il profilo (avatar, nome, email) e il pulsante di uscita li disegni tu da onAuth(user) — quella è la tua UI. I dati dell'utente arrivano pronti.
Metodi dell'SDK (applogin.js) basso livello
Se vuoi una UX tua invece del widget, usa l'SDK direttamente. Chiama prima Applogin.init({ appId }). Il token è salvato in localStorage sotto al_token_<appId>.
| Metodo | Descrizione | Restituisce |
|---|---|---|
init({ appId }) | Inizializzazione. | — |
getSession() | SSO silenzioso: riprende la sessione se l'utente ha effettuato l'accesso in un'altra app dello stesso sito. | { authenticated, token, user } |
openLogin() | Apre la modale con il modulo ospitato (iframe su applogin.one). | { token, user, lang } o null |
verify() | Verifica il token corrente. | { valid, user } |
logout() | Esci (revoca la sessione e cancella il token). | — |
getToken() | Il token di app corrente. | 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
Accesso unico (SSO)
All'accesso Applogin imposta il cookie al_sso con l'attributo Partitioned. La chiave di partizione è il sito di primo livello (quello più esterno). Quindi:
- Più tue app sotto uno stesso sito (es. incorporate in
appdock.pro) condividono la sessione →getSession()nella seconda app riprende l'accesso senza modulo. - La stessa app aperta come sito separato (altro primo livello) è un'altra partizione → l'utente accede di nuovo.
const s = await Applogin.getSession(); // ← {authenticated:true,…} if a session exists in this partition
if (s.authenticated) showApp(s.user);
allowed_origins di un'app devono elencare sia il suo dominio sia il dominio contenitore (es. appdock.pro).allowed_origins (un sito estraneo non ottiene mai un token).Lingue
Il modulo di accesso ospitato parla 10 lingue: English, Deutsch, Français, Español, Italiano, Português, 日本語, 한국어, 中文, Русский. Per impostazione predefinita si apre nella lingua del browser dell'utente (con l'inglese come riserva); la lingua si cambia direttamente nel modulo — il menu con le bandiere in basso.
- Forzare una lingua. Passa
langal widget o all'SDK:ApploginUI.mount({ appId, lang: "it" })oppureApplogin.init({ appId, lang: "it" })— il modulo si apre in quella lingua. Senza l'opzione, l'SDK invia automaticamente la lingua del browser. - Rileggere la scelta. L'utente può cambiare lingua dentro il modulo. Il risultato di
Applogin.openLogin()contienelang— la lingua del modulo al momento dell'accesso — così la tua pagina può seguirla. Il widget la salva anche (localStorageal_lang): il prossimo modulo si aprirà in quella lingua. - Le email seguono il modulo. Le email di verifica e di ripristino partono nella lingua del modulo.
Sotto il cofano l'URL del modulo accetta ?lang=xx (codice di due lettere dall'elenco sopra) — l'SDK lo passa per te.
Esempio dal vivo: AppDock
appdock.pro è un launcher a «dock»: una pagina che apre più applicazioni in iframe. Le applicazioni vivono sui propri domini:
| Applicazione | Dominio | app_id |
|---|---|---|
| Email Writer | emailwriter.online | app_emailwriter |
| Audio Recorder | audiorecorder.info | app_recorder |
Accedi a Email Writer dentro il dock, poi apri Audio Recorder (anch'esso nel dock): l'accesso viene ripreso automaticamente, perché entrambi girano sotto lo stesso sito di primo livello appdock.pro e condividono una partizione SSO.
1. Il launcher (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. Un'applicazione (es. 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. Registrazione delle app per questo scenario
Ogni applicazione elenca in allowed_origins il proprio dominio + quello del dock (frame-ancestors vede l'intera catena di antenati del frame annidato):
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.Verificare il token nel tuo backend
Il tuo frontend mette Applogin.getToken() nell'header Authorization delle sue richieste. Nel backend ci sono due modi di verifica.
1. Con l'endpoint della piattaforma considera la revoca
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. In locale (HS256 con il tuo jwt_secret) senza rete
// 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.Struttura del 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 (facoltativo)
Se un'applicazione imposta un webhook_url, la piattaforma vi invia un POST firmato con l'identità verificata a ogni accesso Google riuscito — per la sincronizzazione lato server oltre al token.
| Header | Valore |
|---|---|
X-Applogin-Timestamp | unix-ms |
X-Applogin-Signature | sha256=<hex> di 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();
Creare un'applicazione
Le applicazioni si creano nella dashboard privata applogin.one/dashboard (accesso tramite Applogin stesso). Fornisci:
| Campo | Perché |
|---|---|
name | Mostrato nel modulo di accesso («Accedi · <name>»). |
allowed_origins | Origin autorizzate a incorporare il modulo e ricevere token. Elenca il dominio dell'app + il dominio contenitore (es. il dock). |
redirect_uris | Per l'accesso Google: https://applogin.one/auth-callback.html. |
webhook_url | (facoltativo) dove inviare il webhook di accesso. |
Ricevi: app_id (pubblico), jwt_secret (verifica del token nel backend), client_secret, webhook_signing_secret.
API REST — riferimento
Base: https://applogin.one/api. Sotto, ciò che serve davvero a un integratore. Gli endpoint email/password e di scambio Google li chiama il modulo ospitato stesso — tu mai.
Per l'integratore
Verificare un token di app nel backend (con revoca). { app_id, token } → { valid, user }.
Dati pubblici dell'applicazione (name, allowed_origins). Usati dalla pagina di accesso ospitata.
Interni (li chiama il modulo ospitato/SDK, non tu)
| Endpoint | Ruolo |
|---|---|
POST /v1/email/register · verify · resend · login · reset/request · reset/confirm · password/change | email/password — chiamati dal modulo ospitato /login. |
POST /v1/auth/start, GET /oauth/google/callback, POST /v1/auth/exchange | OAuth Google (dentro il modulo ospitato). |
POST /v1/session/sso | SSO silenzioso (chiamato da /session da un iframe nascosto). |
POST /v1/session/establish | Imposta il cookie SSO nella partizione corretta (dopo Google). |
POST /v1/session/logout | Revoca della sessione (tramite SDK logout()). |
Errori
| HTTP | Quando |
|---|---|
| 400 | Input non valido (password corta, codice non valido/scaduto, «Email already registered»). |
| 403 | «Invalid credentials», accesso negato, «Too many attempts» (rate limit). |
| 404 | Applicazione/percorso sconosciuti. |
{"error":"Invalid or expired code","message":"Invalid or expired code"}
Sicurezza
- La password è isolata. I campi di input esistono solo nell'iframe di applogin.one; il JS del sito integratore non può raggiungerli.
- Token limitati all'app. Il JWT è firmato con il segreto dell'applicazione e porta
aud=app_id— il token di un'app non è valido in un'altra. - Consegna del token solo alle tue origin. Il modulo invia il token via
postMessagesolo a un'origin delleallowed_origins; la pagina di accesso è servita conContent-Security-Policy: frame-ancestors <allowed_origins>(anti-clickjacking). - La sessione globale è HttpOnly. Il cookie
al_ssoè irraggiungibile da JS; l'integratore ha in mano solo un token di app. - Anti-CSRF sull'SSO.
/v1/session/ssoemette un token solo perOrigin ∈ allowed_origins— un sito estraneo con il cookie dell'utente non ottiene nulla. - Anti-bruteforce. Rate limit su login/reset/verify (per email e per IP).
- Le password sono hashate (PBKDF2); i codici sono hashati, TTL 10 minuti, limite di tentativi; HTTPS ovunque; i token Google non vengono mai salvati. Accesso Google con PKCE (S256) + state + nonce.
Promemoria per LLM
Modello: tutta l'autenticazione avviene in un iframe su applogin.one. L'integratore NON disegna moduli, NON invia password, NON verifica codici. Include SDK + widget e riceve un token di 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: l'accesso imposta il cookie al_sso (Partitioned, per sito di primo livello). Le app sotto lo stesso sito (es. iframe di un dock come appdock.pro) condividono la sessione; un dominio separato → nuovo accesso. Le allowed_origins di un'app = il suo dominio + il dominio contenitore.
Il token è limitato all'app: iss=applogin, aud=app_id, sub=id utente, firmato con il jwt_secret dell'app.
Applogin · accesso unificato · dashboard · esempio dal vivo: AppDock