Authentication
Vestoris is its own OAuth 2.0 authorization server (RFC 6749). Its metadata is at https://vestoris.com/.well-known/oauth-authorization-server (RFC 8414). Every request is over HTTPS; the API sends HSTS, takes no cookies (a request with only the site's session cookie is refused with session_not_accepted) and needs no CSRF token: the bearer token is the credential.
| Grant | For | Acts as |
|---|---|---|
| Client credentials | A system (nightly jobs, integrations) | The client's service account |
| Authorization code with PKCE | An app used by people | The person who signed in and consented |
| Personal access token | Your own scripts | You |
Access tokens are opaque (vat_...), last one hour (or less, as the Admin sets), and are stored only as keyed hashes. Never put a token in a URL: Vestoris reads them only from the Authorization header.
Client credentials (service accounts)
An Admin creates a service account client on API clients and webhooks: a name, a role (its privileges), the scopes, and optionally an IP allow-list (CIDR). The client secret (vcs_...) is shown once.
curl -X POST https://vestoris.com/oauth/token \
-u "$VESTORIS_CLIENT_ID:$VESTORIS_CLIENT_SECRET" \
-d grant_type=client_credentials -d "scope=orders:read market:read"{"access_token":"vat_...","token_type":"Bearer","expires_in":3600,"scope":"orders:read market:read"}The secret can also be sent in the form (client_secret_post). Rotation: "Rotate secret" issues a new one; the old one keeps working for the overlap you choose (up to 7 days), so you can deploy without downtime.
private_key_jwt (RFC 7523): register your public key (RSA 2048+ or EC P-256) instead of using a secret, and authenticate with a signed assertion (iss and sub = your client_id, aud = the token endpoint URL, a unique jti, exp within 5 minutes):
curl -X POST https://vestoris.com/oauth/token \
-d grant_type=client_credentials \
-d client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer \
-d "client_assertion=$SIGNED_JWT"A service account can never sign off compliance or workflow rules, and it can approve orders and overrides only if an Admin ticked "may approve" (with a warning); four eyes still applies.
Authorization code with PKCE (apps for people)
An Admin registers an app with its exact HTTPS redirect URIs (no wildcards). PKCE with S256 is required.
- Make a random
code_verifierand itscode_challenge= BASE64URL(SHA-256(verifier)). - Send the person to the consent screen:
https://vestoris.com/oauth/authorize?response_type=code&client_id=vc_...&redirect_uri=https%3A%2F%2Fapp.example.com%2Fcallback&scope=portfolio%3Aread%20orders%3Aread&state=xyz&code_challenge=...&code_challenge_method=S256- The person signs in and sees what the app asks for. They grant only scopes their role and privileges can use: the token gets the intersection of the app's scopes and their entitlements. Vestoris returns them to your redirect URI with
codeandstate. - Exchange the code (once, within 10 minutes):
curl -X POST https://vestoris.com/oauth/token -u "$VESTORIS_CLIENT_ID:$VESTORIS_CLIENT_SECRET" \
-d grant_type=authorization_code -d "code=$CODE" -d "code_verifier=$VERIFIER" \
-d redirect_uri=https://app.example.com/callbackYou get an access token and a refresh token (vrt_...). Refresh tokens rotate: each refresh returns a new one and the old one stops working. Using an old refresh token again is treated as theft: every token of that sign-in is revoked.
curl -X POST https://vestoris.com/oauth/token -u "$VESTORIS_CLIENT_ID:$VESTORIS_CLIENT_SECRET" \
-d grant_type=refresh_token -d "refresh_token=$REFRESH_TOKEN"People see and withdraw the apps they authorized on My API access; withdrawing revokes the app's tokens at once.
Personal access tokens
On My API access, choose a name, the scopes (only those your role can use) and an expiry (up to a year). The token (vpt_...) is shown once and acts as you.
Introspection and revocation
# RFC 7662: is this token active, and for what?
curl -X POST https://vestoris.com/oauth/introspect -u "$VESTORIS_CLIENT_ID:$VESTORIS_CLIENT_SECRET" -d "token=$TOKEN"
# RFC 7009: revoke an access or refresh token (a refresh token revokes its whole chain)
curl -X POST https://vestoris.com/oauth/revoke -u "$VESTORIS_CLIENT_ID:$VESTORIS_CLIENT_SECRET" -d "token=$TOKEN"The token endpoint takes POST only; a GET is refused (credentials never travel in URLs).