Sign in with Rankly
Permetti agli utenti Rankly di accedere alla tua app con il loro account Rankly. Implementa OAuth 2.0 + OpenID Connect standard contro gli endpoint pubblicati su Rankly. Niente librerie custom: qualsiasi client OIDC funziona out-of-the-box.
1. Cos'è e quando usarlo
Sign in with Rankly è un OAuth 2.0 + OpenID Connect provider gestito da Rankly. Usalo quando:
- Vuoi permettere agli utenti Rankly di loggarsi nella tua app senza creare un secondo account.
- Vuoi leggere/scrivere dati Rankly a nome di un utente specifico (rispettando i suoi permessi sulle org di cui è membro).
- Stai costruendo un bot Discord, un overlay caster, un'app mobile, una dashboard custom che deve agire come quell'utente.
Per integrazioni server-to-server senzaun utente specifico (es. job notturno che legge tutti i tornei di un'org), usa invece le API key Bearer: sono org-bound, più semplici, e non richiedono il flow utente.
2. Registrare la tua app
Self-service: se sei admin/owner di un'organizzazione Rankly, registri il client da Account → Organizzazione → App OAuth in pochi secondi. Ottieni client_id (pubblico) + client_secret (segreto, mostrato una sola volta).
Devi indicare:
- Nome app (quello che l'utente vede sulla pagina di consenso).
- Tipo:
web(backend server-side con client_secret),public(SPA/native con PKCE solo),native,user-agent-based. - Redirect URI(s): l'URL della tua app dove Rankly rispedirà l'utente dopo il consenso.
https://obbligatorio (eccettohttp://localhostper dev).
Conserva il client_secret nel password manager / vault del tuo deploy. Il secret non è recuperabile: se lo perdi, cancella il client e creane uno nuovo.
3. Discovery URL
Tutto parte da qui. Il discovery URL espone gli endpoint, gli algoritmi supportati e la JWKS URI in formato JSON standard OIDC:
GET https://api.rankly.it/api/auth/.well-known/openid-configurationQualsiasi libreria OIDC moderna (openid-client per Node.js, Authlib per Python, AppAuth per mobile) lo legge in automatico. Non serve hardcodare gli URL dei singoli endpoint.
4. Authorization Code Flow
È il flow standard server-side. Per SPA/native usa la variante con PKCE (S256 supportato).
Step 1 — redirect a Rankly
La tua app costruisce l'URL di authorize e ci spedisce l'utente:
https://api.rankly.it/api/auth/oauth2/authorize?
response_type=code
&client_id=<YOUR_CLIENT_ID>
&redirect_uri=<YOUR_REDIRECT_URI>
&scope=openid profile email tournaments:read
&state=<RANDOM_STRING_FOR_CSRF>
&code_challenge=<PKCE_S256_CHALLENGE> # se PKCE
&code_challenge_method=S256 # se PKCERankly verifica la session utente: se non è loggato, lo manda a /signin. Una volta loggato, mostra la pagina di consenso con i tuoi scope tradotti in italiano. L'utente preme Autorizza → Rankly redirige al tuo redirect_uri con:
<YOUR_REDIRECT_URI>?code=<AUTH_CODE>&state=<TUO_STATE>Importante: verifica che state coincida con quello che hai mandato (CSRF guard).
Step 2 — scambio code → token
Lato server (mai dal browser per i client web):
POST https://api.rankly.it/api/auth/oauth2/token
Content-Type: application/x-www-form-urlencoded
Authorization: Basic base64(client_id:client_secret)
grant_type=authorization_code
&code=<AUTH_CODE>
&redirect_uri=<YOUR_REDIRECT_URI>
&code_verifier=<PKCE_VERIFIER> # se PKCERisposta:
{
"access_token": "...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "...",
"id_token": "eyJhbGciOiJSUzI1NiIs...",
"scope": "openid profile email tournaments:read"
}Esempio Node.js (openid-client)
import { Issuer } from 'openid-client';
const issuer = await Issuer.discover('https://api.rankly.it/api/auth');
const client = new issuer.Client({
client_id: process.env.RANKLY_CLIENT_ID,
client_secret: process.env.RANKLY_CLIENT_SECRET,
redirect_uris: ['https://your-app.com/auth/callback'],
response_types: ['code'],
});
// Step 1: redirect
const url = client.authorizationUrl({
scope: 'openid profile email tournaments:read',
state,
});
// Step 2 (route /auth/callback):
const params = client.callbackParams(req);
const tokenSet = await client.callback(redirectUri, params, { state });
const userinfo = await client.userinfo(tokenSet.access_token);
// userinfo => { sub, name, email, ... }Esempio cURL
# Step 2 dopo aver ricevuto ?code=XYZ
curl -X POST https://api.rankly.it/api/auth/oauth2/token \
-u "$CLIENT_ID:$CLIENT_SECRET" \
-d "grant_type=authorization_code" \
-d "code=XYZ" \
-d "redirect_uri=https://your-app.com/auth/callback"5. Scope disponibili
openid— obbligatorio per OIDC, identifica l'utente (subclaim).profile— accesso a username (preferred_username), nome, avatar (picture).email— accesso all'email.offline_access— emetterefresh_token, permette di rinnovare l'access_token senza re-login.tournaments:read— chiamate GET su/api/v1/orgs/{orgId}/tournamentse affini, nei limiti delle membership dell'utente.tournaments:write— chiamate POST/PATCH/DELETE su tornei, match, participants. Richiede membershipadmin/ownerdell'org target.
Chiedi solo gli scope che usi davvero. Più scope chiedi, più la pagina di consenso risulta intrusiva, meno utenti accettano.
6. Profilo utente
GET https://api.rankly.it/api/auth/oauth2/userinfo
Authorization: Bearer <access_token>Risposta:
{
"sub": "usr_xxx",
"preferred_username": "gas",
"name": "Andrea Gasloli",
"given_name": "Andrea",
"family_name": "Gasloli",
"picture": "https://.../avatar.png",
"email": "andrea@example.com",
"email_verified": true
}Usa preferred_usernamecome identità visibile: è lo username Rankly, unico e scelto dall'utente. name è il nome che arriva dal provider social (Google/Discord) e può mancare o non corrispondere. subè l'ID stabile da salvare nel tuo DB. Gli stessi claim (preferred_username, picture) sono anche nell'id_token quando chiedi lo scope profile.
preferred_usernameè assente solo per gli utenti che non hanno ancora completato l'onboarding su Rankly (username temporaneo): in quel caso mostra name e invitali a completare il profilo.
7. Chiamate API a nome utente
L'access_tokenemesso vale anche come Bearer per l'API REST di Rankly https://api.rankly.it/api/v1/*:
curl https://api.rankly.it/api/v1/orgs/<orgId>/tournaments \
-H "Authorization: Bearer <access_token>"La prima chiamata tipica dopo il login è i tornei dell'utente: non serve conoscere il suo id, l'identità è quella del token.
curl https://api.rankly.it/api/v1/me/tournaments \
-H "Authorization: Bearer <access_token>"
{
"tournaments": [
{
"tournament": { "id": "trn_...", "slug": "slam-3", "name": "PBI Slam #3", "status": "completed", "startsAt": "2026-06-14T09:00:00.000Z" },
"org": { "slug": "probladers-italy", "name": "ProBladers Italy", "logoUrl": "https://..." },
"participation": { "status": "active", "role": "player", "checkedInAt": "2026-06-14T08:40:12.000Z" },
"isCoOrganizer": false,
"stats": {
"matchesPlayed": 7, "matchesWon": 5, "matchesLost": 2, "matchesDrawn": 0,
"pointsFor": 26, "pointsAgainst": 17,
"finalRank": 3, "participantsCount": 32
}
}
]
}statsè dal punto di vista dell'utente: contano solo i match completati con entrambi i lati (bye esclusi);finalRank è valorizzato solo per i tornei completed (null se non classificato, es. eliminato nella fase Swiss di un torneo a due fasi);participantsCount = iscritti attivi. Per i tornei in cui è solo co-organizer (participation: null) le stats sono a zero. Alternativa senza token, profilo pubblico: GET /api/v1/public/users/by-username/{preferred_username}(solo tornei visibili pubblicamente, senza stats). Schema completo in /docs/api.
Regole:
- Membership check: il backend verifica che l'utente sia member dell'org target. Se non lo è →
403 oauth_user_not_member. - Scope check: qualunque chiamata a
/api/v1/*richiede almenotournaments:read(→403 scope_required:tournaments:read); le mutation richiedonotournaments:write, che implica anche la lettura. Un token con soloopenid profile emailserve per il login, non per l'API. - Revoca: il token smette di valere se l'utente revoca l'app da
/account/oauth-authorizations, se il client viene disabilitato o cancellato dal pannello org (401 client_disabled/401 invalid_token), o se l'account utente viene sospeso (401 user_suspended). - Ereditarietà admin: se l'utente è admin/owner di una federazione, può accedere a tutti i club affiliati (sub-org) senza membership esplicita su ciascuno.
- Subscription: l'org target deve avere sub
trialingoactive. Altrimenti read sono ok, write →402 subscription_required.
8. Refresh token
Se hai chiesto lo scope offline_access, ricevi un refresh_tokeninsieme all'access_token. Usalo per rinnovare:
POST https://api.rankly.it/api/auth/oauth2/token
Content-Type: application/x-www-form-urlencoded
Authorization: Basic base64(client_id:client_secret)
grant_type=refresh_token
&refresh_token=<REFRESH_TOKEN>Durata di default: access_token 1 ora, refresh_token 7 giorni. Rotation: ogni refresh emette un nuovo refresh, il precedente viene invalidato (rotazione standard OIDC).
9. Verifica id_token (JWKS)
Gli id_token sono JWT firmati RS256. Verifica la firma offline scaricando la chiave pubblica da:
GET https://api.rankly.it/api/auth/jwksLe librerie OIDC fanno questa verifica in automatico (jose, jsonwebtoken con jwks-rsa, ecc). La rotazione delle chiavi è gestita lato Rankly: il kidnell'header del JWT indica quale chiave usare.
# Esempio con jose (Node.js)
import { createRemoteJWKSet, jwtVerify } from 'jose';
const JWKS = createRemoteJWKSet(
new URL('https://api.rankly.it/api/auth/jwks'),
);
const { payload } = await jwtVerify(idToken, JWKS, {
issuer: 'https://api.rankly.it',
audience: process.env.RANKLY_CLIENT_ID,
});10. Errori comuni
Sul flow OAuth
invalid_client: client_id non trovato o client_secret sbagliato. Verifica le credenziali.invalid_grant: code già scambiato (single-use), scaduto (10 min), o redirect_uri diverso da quello del request.unauthorized_client: il tuo client non è autorizzato a usare quel grant_type. Perwebok auth_code+refresh, perpublicsolo auth_code+PKCE.- Redirect dopo consenso fallisce: probabile
redirect_urinon whitelisted in fase di registrazione.
Sull'API call
401 invalid_token: access_token sconosciuto, revocato dall'utente o del client cancellato. Rifai il login.401 token_expired: access_token scaduto (1 ora). Usa il refresh_token.401 client_disabled: il client è disabilitato dal pannello org. Riabilitalo o creane uno nuovo.401 user_suspended: l'account Rankly dell'utente è sospeso. Non c'è nulla da fare lato app.403 oauth_user_not_member: l'utente non è member dell'org target.403 scope_required:tournaments:read: il token non ha scope API. Richieditournaments:read(owrite) nella authorize.403 scope_required:tournaments:write: mancano scope per la mutation. Richieditournaments:writenello scope iniziale.402 subscription_required: l'org target non ha subscription attiva.
Contatto + revoca lato utente
Email tecnico: support@rankly.it. Risposta in italiano entro 1 giorno lavorativo.
Lato utente: gli utenti Rankly vedono le tue app autorizzate su /account/oauth-authorizationse possono revocarle in qualsiasi momento. Dopo la revoca, l'utente dovrà riautorizzare la tua app dal flusso /authorize standard.