OAuth 2.0
Authorization Code + PKCE — for a store plugin a merchant connects themselves.
VUZ runs a standard OAuth 2.0 Authorization Code flow with PKCE (RFC 7636), served by a
dedicated oauth-server app — a separate NestJS service from the main API
(client-api). This is the flow used by the WooCommerce plugin today.
Ask VUZ (developers@vuz.co.il) for the oauth-server base URL for your environment and
to register your integration as an OAuth client (client_id / redirect URI). The examples
below use an <oauth-base-url> placeholder — substitute the base URL you were given
(locally the oauth-server defaults to http://localhost:3022).
The flow
Generate a PKCE pair
Create a code_verifier (random string) and its code_challenge (BASE64URL(SHA256(code_verifier))) client-side, per RFC 7636.
Redirect the merchant to /oauth/authorize
GET /oauth/authorize
?response_type=code
&client_id=<your_client_id>
&redirect_uri=<your_redirect_uri>
&scope=documents:write%20clients:write%20business:read
&code_challenge=<code_challenge>
&code_challenge_method=S256
&state=<random_csrf_token>The merchant logs in (or is already logged in) to VUZ, picks which of their businesses to connect (if they have more than one), and sees a consent screen listing exactly the scopes you requested.
Merchant approves — VUZ redirects back with a code
GET <your_redirect_uri>?code=<authorization_code>&state=<same_state>Verify state matches what you sent (CSRF protection) before proceeding.
Exchange the code for tokens
curl -X POST <oauth-base-url>/oauth/token \
-d grant_type=authorization_code \
-d code=<authorization_code> \
-d redirect_uri=<your_redirect_uri> \
-d client_id=<your_client_id> \
-d client_secret=<your_client_secret> \
-d code_verifier=<code_verifier>Response:
{
"access_token": "vuz_at_...",
"refresh_token": "vuz_rt_...",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "documents:write clients:write business:read"
}Call the API
curl https://api.vuz.co.il/api/v1/documents \
-H "Authorization: Bearer vuz_at_..."Refreshing
Access tokens expire in 1 hour. Exchange the refresh token before then:
curl -X POST <oauth-base-url>/oauth/token \
-d grant_type=refresh_token \
-d refresh_token=<your_refresh_token> \
-d client_id=<your_client_id> \
-d client_secret=<your_client_secret>Refresh tokens rotate on every use — the response contains a new refresh token; the old
one is invalidated. If you present an already-used (stale) refresh token, VUZ treats it as
theft and revokes the entire token family — you must send the merchant through
/oauth/authorize again.
Revoking
POST /oauth/revokeThe merchant can also revoke access from their own VUZ dashboard at any time — your
integration must handle a sudden 401 token_revoked on any call and re-trigger the connect
flow.
Scopes
Request only what you need — the consent screen shows the merchant exactly what you're
asking for. See Auth → Scopes for the full list; it is the same
canonical scope model (50 resource:action scopes) shared with API keys, enforced
identically on every route.

