Vimine (browser)
import { Vimine } from '@vimine/sdk';const vimine = new Vimine(options);Vimine handles Sign in with Vimine (OAuth 2.1 + PKCE), the member’s session and the calls to the
member API. One instance per client; create it once and reuse it.
Options
Section titled “Options”| Option | Type | Default | |
|---|---|---|---|
clientId |
string |
— | your vmc_… (required) |
redirectUri |
string |
— | the page that calls handleRedirect(), registered for the client (required) |
scopes |
Scope[] |
['profile:read', 'membership:read'] |
permissions asked by signIn() |
storage |
'session' | 'local' | 'memory' | TokenStorage |
'session' |
where the session and the pending sign-in live |
storageKey |
string |
vimine:<clientId>: |
key prefix in the storage |
locale |
Locale |
'it' |
language of the sign-in and consent pages |
apiUrl |
string |
https://api.vimine.network |
API origin |
appUrl |
string |
https://app.vimine.network |
origin of the sign-in pages |
fetch |
typeof fetch |
globalThis.fetch |
for tests and polyfills |
navigate |
(url) => void |
top.location.assign |
how to leave the page |
The constructor throws a VimineError (invalid_options) without clientId or redirectUri.
Sign-in
Section titled “Sign-in”signIn(options?)
Section titled “signIn(options?)”Sends the top window to the sign-in and consent page. Call it from a user gesture (a click). From inside
a cross-origin iframe the navigation is refused (framed): the sign-in page is never shown in a frame.
| Option | |
|---|---|
scopes |
permissions of this sign-in |
prompt |
'login' (credentials always) or 'consent' (consent always) |
returnTo |
your own state, kept locally and returned by handleRedirect() — it is not sent |
createSignInUrl(options?)
Section titled “createSignInUrl(options?)”Builds the authorization URL and remembers the pending sign-in (PKCE verifier and state) without
navigating. Useful when you render the link yourself.
hasRedirectParams(url?)
Section titled “hasRedirectParams(url?)”true when the URL (default: the current page) carries the parameters of a return (code+state or error).
handleRedirect({ url?, cleanUrl? })
Section titled “handleRedirect({ url?, cleanUrl? })”On the callback page: checks the state, exchanges the code for tokens and stores the session. Returns
{ session, returnTo }, or null when the URL carries no sign-in parameters. With cleanUrl (default
true) it removes code, state and error from the address bar.
Errors (VimineError.code): access_denied and the other OAuth errors when the member did not authorise;
no_flow when no sign-in was started from this browser (storage empty or expired); state_mismatch when the
return does not match; invalid_grant when the code expired or was already used.
Session
Section titled “Session”getSession() · isSignedIn()
Section titled “getSession() · isSignedIn()”The stored session, or null.
interface Session { accessToken: string; refreshToken: string | null; expiresAt: number; // ms, absolute scope: Scope[]; sub: string | null; // the member's identifier for your association (vms_…) mode?: 'live' | 'test'; // 'test' for sessions of a test client aps?: AssociationRef | null; // the association: slug, name, picture_url}getAccessToken()
Section titled “getAccessToken()”A valid access token, refreshed when it expires within 30 seconds. Throws not_signed_in without a session.
refresh()
Section titled “refresh()”Rotates the session with the refresh token (a single request even when called concurrently). When the refresh token is no longer usable the session is cleared and the error rethrown.
signOut({ everywhere?, postLogoutRedirectUri?, state? })
Section titled “signOut({ everywhere?, postLogoutRedirectUri?, state? })”Revokes the refresh token (RFC 7009, best effort) and forgets the session. With everywhere: true it then
sends the browser to the Vimine app’s /oauth/logout, which ends the member’s session and comes back to
postLogoutRedirectUri (default redirectUri; it must be on a registered origin).
onChange(listener)
Section titled “onChange(listener)”listener(session | null) on every sign-in, refresh and sign-out; with storage: 'local' also for those that
happened in other tabs. Returns the unsubscribe function.
Member API
Section titled “Member API”request(path, init?)
Section titled “request(path, init?)”An authenticated call: Authorization: Bearer, JSON in and out, errors as VimineError, one retry after a
refresh when the response is 401. init.idempotencyKey becomes the Idempotency-Key header.
const events = await vimine.request('/v1/me/membership/events?limit=5');| Scope | ||
|---|---|---|
me.get() |
profile:read |
the profile (Me), with codicefiscale_check: how the person is identified (null = not yet) |
me.update(patch) |
profile:write |
phone, gender, and the identification: date, place and country of birth (birth_country), fiscal code — optional, may be added later. A code that disagrees answers 422 with a codicefiscale_mismatch entry; when it is confirmable, the person confirms it with codicefiscale_confirmed: true (guide) |
membership
Section titled “membership”| Scope | ||
|---|---|---|
membership.get() |
membership:read |
the card: status, verdict, expires_at, statuto, card |
membership.request(body, { idempotencyKey? }) |
membership:request |
membership request; an idempotency key is generated when absent. 422 identification_required when the profile is not identified: err.errors names what is missing, completed with me.update() |
membership.events({ limit?, cursor? }) |
membership:read |
status history, paginated |
membership.statuto() |
membership:read |
the in-force statuto and the member’s acceptance |
membership.acceptStatuto({ version, sha256? }) |
statuto:accept |
records the acceptance |
membership.card() |
membership:read |
the card token (QR) and its window; 409 not_active unless the membership is active |
membership.renew({ version, sha256? }) |
POST /v1/me/membership/renew |
self-service renewal: at once when free with no approval gate, otherwise a request to the secretariat |
membership.setNetworkOptIn(bool) |
PATCH /v1/me/membership/network-opt-in |
network consent (network:manage) |
membership.googleWalletUrl() |
GET /v1/me/membership/wallet/google |
a “Save to Google Wallet” link; 409 not_active unless the membership is active |
membership.cardSvg() |
GET /v1/me/membership/card.svg |
the card as SVG (with the QR); 409 not_active unless the membership is active |
membership.emailCard() |
POST /v1/me/membership/card/email |
e-mails the member their card |
events
Section titled “events”The association’s published events, members-only ones included (events:read). The public ones need no
sign-in: vimine.public.events.
events.list({ filter?, from?, to?, limit? }) |
filter: upcoming (default), past, cancelled, all |
events.get(slug) |
copy, images, registration types with places left |
events.eligibility(slug) |
may the member register? per type, with reasons (membership_required, sold_out, …) |
registrations
Section titled “registrations”The member’s registrations (registrations:read / registrations:write). See the Events and registrations guide.
registrations.create(slug, { registration_type, note?, quantity? }, opts?) |
free type → confirmed with the QR token; with a contribution → reserved with payment_instructions; 422 not_eligible with the reasons; Idempotency-Key generated |
registrations.list({ filter? }) · registrations.get(id) |
the member’s registrations (filter: 'upcoming') |
registrations.cancel(id) |
cancel inside the event’s window (409 window_closed after) |
registrations.tokenPayload(id) |
the QR content of a confirmed registration, or null |
connections
Section titled “connections”connections.list() |
the apps the member authorised in this association |
connections.revoke(clientId) |
withdraws consent from an app (its sessions end) |
public
Section titled “public”The public, credential-less endpoints: see publicApi.
Storage
Section titled “Storage”storage |
Where | When |
|---|---|---|
'session' (default) |
sessionStorage: per tab, gone when it closes |
the safest default for a public client |
'local' |
localStorage: shared across tabs, survives restarts; sign-out propagates to other tabs |
apps where the member expects to stay signed in |
'memory' |
memory only | SSR, tests, kiosks |
TokenStorage |
an object of yours { get, set, remove } |
Node, encrypted storages, native apps |
Where browser storage is unavailable (private mode, about:blank) the SDK falls back to memory.
MemoryStorage is exported.
Utilities
Section titled “Utilities”createPkce()→{ verifier, challenge, method: 'S256' },createVerifier(),createChallenge(verifier),createState(),base64url(bytes)— PKCE andstateon WebCrypto, if you build the flow by hand.DEFAULT_API_URL,DEFAULT_APP_URL.publicApi(options?)— see Public API.VimineError— see Errors.