SDK JavaScript (@auris/js)
@auris/js v0.1.0@auris/js è l’SDK fondamentale di Auris. È una libreria zero-dipendenze che funziona in browser, Node.js 18+, ed edge runtime (Cloudflare Workers, Vercel Edge, Deno). Sono incluse sia build ESM (import) che CJS (require), insieme a dichiarazioni TypeScript complete.
Gli SDK React e Next.js sono wrapper leggeri attorno a @auris/js. Se stai costruendo un’applicazione framework-agnostica o hai bisogno dell’API di livello più basso, usa direttamente questo pacchetto.
Installazione
npm install @auris/jspnpm add @auris/jsyarn add @auris/jsAurisClient
AurisClient è il punto di ingresso principale. Crea un’istanza per applicazione.
Costruttore
import { AurisClient } from '@auris/js'
const auris = new AurisClient({
domain: 'auth.tuodominio.com', // Dominio del tenant Auris (obbligatorio)
clientId: 'app_xxxxx', // Client ID dell'applicazione dalla Console (obbligatorio)
redirectUri: 'http://localhost:3000/callback', // Deve corrispondere a un Callback URL registrato (obbligatorio per i flussi PKCE)
tenant: 'my-tenant', // Identificativo tenant inviato come header x-tenant (opzionale)
storage: 'localStorage', // Archiviazione token: 'localStorage' | 'sessionStorage' | 'memory' | istanza TokenStore
autoRefresh: true, // Aggiorna automaticamente i token di accesso prima della scadenza (default: true)
scope: 'openid profile email', // Scope OAuth2 da richiedere (default: 'openid profile email')
})Opzioni di configurazione:
| Opzione | Tipo | Obbligatorio | Default | Descrizione |
|---|---|---|---|---|
domain | string | Sì | — | Il dominio del tenant Auris, senza https:// |
clientId | string | Sì | — | Client ID dell’applicazione dalla Console |
redirectUri | string | Condizionale | — | URL di callback per i flussi PKCE. Deve essere registrato nella Console. |
tenant | string | No | 'default' | Identificativo tenant inviato come header HTTP x-tenant |
storage | string | TokenStore | No | 'localStorage' | Dove persistere i token |
autoRefresh | boolean | No | true | Aggiorna i token di accesso automaticamente prima della scadenza |
scope | string | No | 'openid profile email' | Scope OAuth2 separati da spazio |
Negli edge runtime e negli ambienti Node.js senza localStorage, l’SDK ricade automaticamente sull’archiviazione in memoria. Passa storage: 'memory' esplicitamente se vuoi attivare questo comportamento negli ambienti browser.
Metodi di Autenticazione
loginWithRedirect(options?)
Avvia il flusso Authorization Code OAuth2 con PKCE. Genera un code verifier e un challenge, memorizza il verifier, poi reindirizza il browser alla pagina di login ospitata da Auris.
Firma:
loginWithRedirect(options?: LoginWithRedirectOptions): Promise<void>Parametri:
| Opzione | Tipo | Descrizione |
|---|---|---|
login_hint | string | Pre-compila il campo email |
prompt | 'login' | 'none' | login forza la ri-autenticazione. none restituisce un errore se non esiste una sessione attiva. |
screen_hint | 'signup' | Apre la schermata di registrazione invece di quella di login |
connection | string | Forza uno specifico alias di connessione SSO |
locale | string | Imposta il locale della pagina ospitata (en, it, de, fr, es) |
state | string | Valore state personalizzato. L’SDK genera un valore casuale sicuro se omesso. |
// Login redirect base
await auris.loginWithRedirect()
// Apri la schermata di registrazione
await auris.loginWithRedirect({ screen_hint: 'signup' })
// Pre-compila l'email e forza la ri-autenticazione
await auris.loginWithRedirect({ login_hint: '[email protected]', prompt: 'login' })handleRedirectCallback()
Completa il flusso OAuth2 PKCE dopo che l’utente torna alla tua applicazione. Legge code e state dall’URL corrente, valida lo state, scambia il codice per i token e memorizza il risultato.
Chiama questo metodo esattamente una volta nella pagina di callback quando si carica per la prima volta.
Firma:
handleRedirectCallback(): Promise<AuthResult>Restituisce: AuthResult
const result = await auris.handleRedirectCallback()
if (result.user) {
console.log('Autenticato come', result.user.email)
window.location.href = '/dashboard'
}login(email, password)
Autenticazione diretta email/password senza redirect. Restituisce i token immediatamente.
Firma:
login(email: string, password: string): Promise<AuthResult>Il login diretto invia le credenziali al server dell’applicazione. Non è consigliato per le applicazioni browser perché bypassa i vantaggi di sicurezza della pagina di login ospitata (CAPTCHA, rate limiting, rilevamento login sospetti, MFA). Usa loginWithRedirect() per l’autenticazione degli utenti finali nelle app browser.
const result = await auris.login('[email protected]', 'hunter2')
console.log(result.user.id)signup(email, password, options?)
Registra un nuovo utente e restituisce i token immediatamente.
Firma:
signup(email: string, password: string, options?: SignupOptions): Promise<AuthResult>Opzioni:
| Opzione | Tipo | Descrizione |
|---|---|---|
firstName | string | Nome dell’utente |
lastName | string | Cognome dell’utente |
username | string | Username (deve essere univoco nel tenant) |
metadata | Record<string, unknown> | Metadati utente personalizzati memorizzati nell’account |
const result = await auris.signup('[email protected]', 'passwordsicura', {
firstName: 'Bob',
lastName: 'Smith',
})logout(options?)
Revoca il refresh token, cancella i token memorizzati e opzionalmente reindirizza il browser.
Firma:
logout(options?: LogoutOptions): Promise<void>Opzioni:
| Opzione | Tipo | Descrizione |
|---|---|---|
returnTo | string | URL a cui reindirizzare dopo il logout. Deve essere nella stessa origine del tuo redirectUri. |
// Cancella i token e reindirizza alla home page
await auris.logout({ returnTo: 'http://localhost:3000' })
// Cancella i token senza reindirizzare (es. in un contesto Node.js)
await auris.logout()getUser()
Restituisce l’utente attualmente autenticato dal token ID memorizzato. Restituisce null se l’utente non è autenticato.
Firma:
getUser(): Promise<UserInfo | null>Restituisce: UserInfo | null
const user = await auris.getUser()
if (user) {
console.log(user.id) // ID utente Auris
console.log(user.email)
console.log(user.roles) // string[] — ruoli assegnati
console.log(user.metadata) // Record<string, unknown>
}isAuthenticated()
Restituisce true se l’utente ha un token di accesso valido (non scaduto).
Firma:
isAuthenticated(): Promise<boolean>if (await auris.isAuthenticated()) {
// Procedi con le operazioni autenticate
}getAccessToken()
Restituisce il token di accesso corrente. Se autoRefresh è abilitato e il token è scaduto, scambia automaticamente il refresh token per un nuovo token di accesso prima di restituirlo.
Firma:
getAccessToken(): Promise<string | null>const token = await auris.getAccessToken()
// Usa il token nelle richieste API
const response = await fetch('/api/data', {
headers: { Authorization: `Bearer ${token}` },
})refreshToken()
Scambia manualmente il refresh token memorizzato per una nuova coppia di token di accesso e refresh.
Firma:
refreshToken(): Promise<AuthResult>const result = await auris.refreshToken()
console.log(result.accessToken)loginWithMagicLink(email)
Invia un’email con magic link all’indirizzo specificato. L’utente clicca il link nell’email per completare l’autenticazione tramite verifyMagicLink().
Firma:
loginWithMagicLink(email: string): Promise<void>await auris.loginWithMagicLink('[email protected]')
// Reindirizza o mostra un messaggio "Controlla la tua email"verifyMagicLink(token)
Verifica un token magic link (estratto dall’URL su cui l’utente ha cliccato). Restituisce token e informazioni utente in caso di successo.
Firma:
verifyMagicLink(token: string): Promise<AuthResult>const urlParams = new URLSearchParams(window.location.search)
const token = urlParams.get('token')
if (token) {
const result = await auris.verifyMagicLink(token)
console.log('Autenticato:', result.user)
}forgotPassword(email)
Invia un’email di reimpostazione password all’indirizzo specificato.
Firma:
forgotPassword(email: string): Promise<void>await auris.forgotPassword('[email protected]')loginWithSocial(provider)
Reindirizza l’utente al provider di identità social specificato. Auris gestisce il flusso OAuth del provider e restituisce l’utente al tuo redirectUri con un codice di autorizzazione.
Firma:
loginWithSocial(provider: SocialProvider): Promise<void>Provider supportati:
type SocialProvider =
| 'google'
| 'github'
| 'microsoft'
| 'apple'
| 'facebook'
| 'discord'
| 'linkedin'
| 'twitter'
| 'slack'await auris.loginWithSocial('google')
await auris.loginWithSocial('github')getM2MToken(clientSecret, scopes?)
Ottiene un token di accesso machine-to-machine usando il grant OAuth2 client_credentials. Usalo per chiamate API server-to-server dove non è coinvolto nessun utente.
Firma:
getM2MToken(clientSecret: string, scopes?: string[]): Promise<M2MTokenResult>const result = await auris.getM2MToken('cs_live_xxxxx', ['read:users', 'manage:roles'])
console.log(result.accessToken)
console.log(result.expiresIn) // secondi alla scadenzaNon usare mai getM2MToken() nel codice browser. Il clientSecret deve rimanere solo lato server. Usa questo metodo nelle route API Node.js, nei worker in background e negli script CLI.
onAuthStateChange(callback)
Si iscrive ai cambiamenti dello stato di autenticazione. Il callback viene eseguito ogni volta che l’utente accede, esce, o il token viene aggiornato.
Firma:
onAuthStateChange(callback: (user: UserInfo | null) => void): UnsubscribeRestituisce: Unsubscribe — chiamala per rimuovere il listener.
const unsubscribe = auris.onAuthStateChange((user) => {
if (user) {
console.log('Accesso effettuato:', user.email)
} else {
console.log('Disconnesso')
}
})
// In seguito, quando non hai più bisogno del listener:
unsubscribe()Modulo Permessi
Accessibile tramite auris.permissions. Tutti i metodi chiamano l’API Auris e richiedono che l’utente sia autenticato.
check(permissions)
Verifica se l’utente corrente ha uno o tutti i permessi specificati.
Firma:
check(permissions: string[]): Promise<PermissionCheckResult>Restituisce: PermissionCheckResult
interface PermissionCheckResult {
has: (permission: string) => boolean
hasAll: boolean // true se l'utente ha tutti i permessi nell'array
hasAny: boolean // true se l'utente ha almeno un permesso nell'array
results: Record<string, boolean> // mappa risultati per-permesso
}const result = await auris.permissions.check(['manage:users', 'view:reports'])
if (result.has('manage:users')) {
// Mostra UI admin
}
if (result.hasAll) {
// L'utente ha entrambi i permessi
}checkOne(permission)
Verifica un singolo permesso. Restituisce true se consentito, false altrimenti.
Firma:
checkOne(permission: string): Promise<boolean>const puoEliminare = await auris.permissions.checkOne('delete:documents')
if (puoEliminare) {
mostraBottoneElimina()
}listUserPermissions()
Restituisce l’elenco completo delle stringhe di permesso assegnate all’utente corrente in tutti i suoi ruoli.
Firma:
listUserPermissions(): Promise<string[]>const permessi = await auris.permissions.listUserPermissions()
console.log(permessi) // ['view:documents', 'create:documents', 'manage:users', ...]Modulo FGA
Accessibile tramite auris.fga. Implementa l’autorizzazione fine-grained in stile Zanzibar. Richiede che la funzionalità FGA sia abilitata sul tenant.
check(input)
Verifica se un soggetto ha una relazione con un oggetto.
Firma:
check(input: FgaCheckInput): Promise<FgaCheckResult>interface FgaCheckInput {
objectType: string // es. 'document'
objectId: string // es. 'doc_abc123'
relation: string // es. 'viewer'
subjectType: string // es. 'user'
subjectId: string // es. l'ID dell'utente corrente
}
interface FgaCheckResult {
allowed: boolean
resolution?: ResolutionNode[] // traccia modalità explain
}const result = await auris.fga.check({
objectType: 'document',
objectId: 'doc_abc123',
relation: 'editor',
subjectType: 'user',
subjectId: user.id,
})
if (result.allowed) {
abilitaModalitaModifica()
}expand(input)
Espande una relazione per elencare tutti i soggetti (utenti o gruppi) che la hanno su un dato oggetto.
Firma:
expand(input: FgaExpandInput): Promise<ExpandTree>const tree = await auris.fga.expand({
objectType: 'project',
objectId: 'proj_xyz',
relation: 'member',
})
console.log(tree)listObjects(input)
Elenca tutti gli ID oggetto di un dato tipo su cui il soggetto ha la relazione specificata.
Firma:
listObjects(input: FgaListObjectsInput): Promise<string[]>// Elenca tutti i documenti che l'utente corrente può visualizzare
const documentIds = await auris.fga.listObjects({
objectType: 'document',
relation: 'viewer',
subjectType: 'user',
subjectId: user.id,
})writeTuples(tuples)
Scrive una o più tuple di relazione nel store FGA.
Firma:
writeTuples(tuples: WriteTupleInput[]): Promise<void>await auris.fga.writeTuples([
{
objectType: 'document',
objectId: 'doc_abc123',
relation: 'editor',
subjectType: 'user',
subjectId: 'usr_456',
},
])deleteTuples(tuples)
Elimina una o più tuple di relazione dallo store FGA.
Firma:
deleteTuples(tuples: WriteTupleInput[]): Promise<void>await auris.fga.deleteTuples([
{
objectType: 'document',
objectId: 'doc_abc123',
relation: 'editor',
subjectType: 'user',
subjectId: 'usr_456',
},
])Client di Gestione
createManagementClient(config) crea un client per la Management API che si autentica con M2M client_credentials. Usalo nel codice backend (script Node.js, route API, strumenti CLI) per gestire il tenant a livello programmatico.
Firma:
import { createManagementClient } from '@auris/js'
const mgmt = await createManagementClient({
domain: 'auth.tuodominio.com',
clientId: 'app_xxxxx',
clientSecret: 'cs_live_xxxxx',
tenant: 'my-tenant',
})Utenti
// Elenca utenti con paginazione
const { users, total } = await mgmt.users.list({ page: 1, limit: 50 })
// Ottieni un singolo utente per ID
const user = await mgmt.users.get('usr_abc123')
// Crea un utente
const newUser = await mgmt.users.create({
email: '[email protected]',
password: 'password-temporanea',
firstName: 'Alice',
roles: ['editor'],
})
// Aggiorna un utente
await mgmt.users.update('usr_abc123', { firstName: 'Alicia' })
// Disabilita un utente (soft-disable — non può effettuare il login)
await mgmt.users.update('usr_abc123', { enabled: false })
// Elimina un utente
await mgmt.users.delete('usr_abc123')Organizzazioni
const orgs = await mgmt.organizations.list()
const org = await mgmt.organizations.get('org_xyz')
const newOrg = await mgmt.organizations.create({ name: 'Acme Corp', slug: 'acme' })
await mgmt.organizations.update('org_xyz', { name: 'Acme Corporation' })
await mgmt.organizations.delete('org_xyz')Ruoli
const roles = await mgmt.roles.list()
const role = await mgmt.roles.get('role_abc')
const newRole = await mgmt.roles.create({ name: 'Editor', description: 'Può modificare i contenuti' })
await mgmt.roles.update('role_abc', { description: 'Può visualizzare e modificare i contenuti' })
await mgmt.roles.delete('role_abc')Verifica Webhook
verifyWebhookSignature(options) verifica che un webhook in ingresso sia stato inviato da Auris e non sia stato manomesso. Usa HMAC-SHA256.
Firma:
import { verifyWebhookSignature } from '@auris/js'
const isValid = await verifyWebhookSignature({
payload: rawBody, // string o Buffer — il corpo grezzo della richiesta
signature: headerValue, // valore dell'header X-Webhook-Signature
secret: 'whsec_xxxxx', // segreto di firma dalla Console
timestamp: headerTs, // valore dell'header X-Webhook-Timestamp
maxAge: 300, // opzionale: rifiuta webhook più vecchi di N secondi (default: 300)
})Esempio Node.js (Express):
import express from 'express'
import { verifyWebhookSignature } from '@auris/js'
const app = express()
app.post('/webhooks/auris', express.raw({ type: 'application/json' }), async (req, res) => {
const isValid = await verifyWebhookSignature({
payload: req.body.toString('utf-8'),
signature: req.headers['x-webhook-signature'],
secret: process.env.AURIS_WEBHOOK_SECRET,
timestamp: req.headers['x-webhook-timestamp'],
})
if (!isValid) {
return res.status(401).json({ error: 'Firma non valida' })
}
const event = JSON.parse(req.body)
console.log('Evento ricevuto:', event.type)
res.json({ received: true })
})Verifica JWT
verifyJwt(token, jwksUrl) verifica un token di accesso emesso da Auris usando le chiavi pubbliche dall’endpoint JWKS. Zero dipendenze — usa la Web Crypto API nei browser e in Node.js 18+.
Firma:
import { verifyJwt } from '@auris/js'
const payload = await verifyJwt(token, 'https://auth.tuodominio.com/.well-known/jwks.json')La funzione restituisce il payload JWT decodificato se la firma è valida, oppure lancia un’eccezione se il token è scaduto, malformato o firmato con una chiave sconosciuta. I risultati del recupero chiavi sono memorizzati nella cache per 1 ora.
import { verifyJwt } from '@auris/js'
try {
const payload = await verifyJwt(
accessToken,
`https://${process.env.AURIS_DOMAIN}/.well-known/jwks.json`
)
console.log('ID Utente:', payload.sub)
console.log('Ruoli:', payload.roles)
} catch (err) {
console.error('Token non valido:', err.message)
}Tipi TypeScript
Tipi chiave esportati da @auris/js:
// Risultati autenticazione
interface AuthResult {
user: UserInfo
accessToken: string
refreshToken?: string
expiresIn: number
tokenType: 'Bearer'
}
// Informazioni utente
interface UserInfo {
id: string
sub: string
email: string
emailVerified: boolean
name: string
firstName: string
lastName: string
username: string
picture?: string
roles: string[]
metadata: Record<string, unknown>
tenant: string
createdAt: string
}
// Risultato token M2M
interface M2MTokenResult {
accessToken: string
expiresIn: number
tokenType: 'Bearer'
scope: string
}
// Risultato verifica permesso
interface PermissionCheckResult {
has: (permission: string) => boolean
hasAll: boolean
hasAny: boolean
results: Record<string, boolean>
}
// Tipi FGA
interface FgaCheckInput {
objectType: string
objectId: string
relation: string
subjectType: string
subjectId: string
subjectRelation?: string
}
interface FgaCheckResult {
allowed: boolean
resolution?: ResolutionNode[]
}
// Interfaccia adapter di archiviazione
interface TokenStore {
get(key: string): string | null | Promise<string | null>
set(key: string, value: string): void | Promise<void>
remove(key: string): void | Promise<void>
}
// Funzione di disiscrizione da onAuthStateChange
type Unsubscribe = () => voidAdapter di Archiviazione Personalizzato
Implementa l’interfaccia TokenStore per persistere i token in qualsiasi backend di archiviazione.
import { AurisClient, TokenStore } from '@auris/js'
class RedisTokenStore implements TokenStore {
constructor(private redis: RedisClient, private prefix = 'auris:') {}
async get(key: string) {
return this.redis.get(this.prefix + key)
}
async set(key: string, value: string) {
await this.redis.set(this.prefix + key, value, { EX: 60 * 60 * 24 })
}
async remove(key: string) {
await this.redis.del(this.prefix + key)
}
}
const auris = new AurisClient({
domain: 'auth.tuodominio.com',
clientId: 'app_xxxxx',
storage: new RedisTokenStore(redisClient),
})Gestione degli Errori
Tutti i metodi async lanciano un AurisError in caso di errore.
import { AurisClient, AurisError } from '@auris/js'
try {
await auris.login('[email protected]', 'passworderrata')
} catch (err) {
if (err instanceof AurisError) {
console.error(err.code) // es. 'invalid_credentials', 'account_locked', 'mfa_required'
console.error(err.message) // Messaggio leggibile
console.error(err.status) // Codice di stato HTTP (es. 401, 403, 429)
}
}Codici di errore comuni:
| Codice | Stato | Descrizione |
|---|---|---|
invalid_credentials | 401 | Email o password errate |
account_locked | 403 | Account temporaneamente bloccato dopo tentativi falliti |
mfa_required | 403 | Richiesta sfida MFA — usa il login ospitato |
invalid_token | 401 | Il token è scaduto o malformato |
permission_denied | 403 | L’utente non ha il permesso richiesto |
rate_limited | 429 | Troppe richieste — rispetta l’header Retry-After |
not_found | 404 | La risorsa non esiste |
validation_error | 422 | Il corpo della richiesta non ha superato la validazione |
Correlati
- SDK React — Contesto React, hook e componenti costruiti su @auris/js
- SDK Next.js — Helper server-side ed Edge Middleware per Next.js
- Guida Login Ospitato — Procedura completa del flusso PKCE
- Autorizzazione Fine-Grained — Modello FGA e gestione tuple
- Webhook — Consegna webhook e verifica HMAC