An integration or script authenticates to the Dawiso REST API as an OAuth2 client, using the client-credentials grant. An integration client is a purpose-built client for unattended services: it proves its identity with a key pair it generates itself, so no secret is exchanged when it’s provisioned or when it authenticates. For the separate, secret-based OAuth2 client flow, see Machine identity for services.
How a machine identity gets its permissions
A machine identity acts as the Dawiso user it’s bound to and inherits that user’s role. Binding an integration to an administrator account grants it every administrator endpoint, not just the one it needs.
Application scopes narrow that down. An endpoint can declare a scope, and only a client granted that scope can call it. The bound user’s role is still evaluated first; the scope is an extra check on top of it, not a replacement.
A scope is checked only on endpoints that declare one. An endpoint with no scope requirement still goes by the bound user’s role.
Provision an integration client
Provisioning has two parts: the integration generates its own key pair, and an administrator registers the public half against a bound account and scopes.
Generate a key pair
Generate an EC P-256 (ES256) key pair on the machine that runs the integration. Keep the private key in your secret store; you will send only the public JWK set to the Dawiso administrator.
{
"keys": [
{
"kty": "EC",
"crv": "P-256",
"kid": "8f14e45fceea167a5a36dedd4bea2543",
"alg": "ES256",
"x": "…",
"y": "…"
}
]
}
Every key needs a kid. A set containing private key material (a d member) is rejected.
Register the client
An administrator sends a POST request to /api/oauth2/integration-clients.
{
"clientName": "Contoso user sync",
"boundUserLogin": "technical.admin",
"scopes": ["dawiso:user_sync"],
"jwkSet": "{\"keys\":[{\"kty\":\"EC\",\"crv\":\"P-256\",\"kid\":\"…\",\"x\":\"…\",\"y\":\"…\"}]}",
"accessTokenLifetimeMinutes": 10
}
The response returns the client_id. There is no client secret; the key pair is the credential. accessTokenLifetimeMinutes is optional, defaults to 10, and must be between 1 and 60.
When external user synchronization is enabled, bind the client to technical.admin. The synchronization deletes every account that isn’t in the pushed payload, except the built-in technical.admin, technical.contributor and technical.viewer logins, so a purpose-made service account would be removed by the integration’s own first run.
Request an access token
The client signs a short-lived JWT assertion with its private key and sends it to /api/oauth2/token as form fields:
| Form field | Value |
|---|---|
grant_type | client_credentials |
client_id | The value returned by the registration endpoint |
client_assertion_type | urn:ietf:params:oauth:client-assertion-type:jwt-bearer |
client_assertion | The signed JWT (see below) |
scope | The scope the call needs, for example dawiso:user_sync |
The assertion is signed with ES256 and needs:
- a
typheader ofclient-authentication+jwt issandsubset to theclient_idaudset to theissuervalue from/.well-known/openid-configuration. This isn’t necessarily the API base address: an instance served behind a separate public host issues tokens under the public one- a unique
jtiand a shortexp
Send the resulting access_token on every subsequent request as Authorization: Bearer <access_token>. An assertion signed by a key the client hasn’t registered is refused with 401 and invalid_client. Requesting a scope the client wasn’t granted fails with 400.
Rotate the key
Rotation needs no administrator: the client replaces its own key set, and only its own.
- Generate a new key pair.
PUT /api/oauth2/integration-clients/{clientId}/keyswith a set containing both public keys, authenticated with an access token obtained using the current key.- Switch the integration to sign with the new key.
PUTthe same endpoint again with the new key alone. The old key stops working immediately.
Both keys are accepted during the overlap in step 2, so the switch causes no downtime. A client cannot change another client’s keys; the attempt is refused with 403.
Available application scopes
Dawiso defines its own scopes with the dawiso: prefix. They are additional to the standard OIDC scopes: openid, profile, email, and offline_access.
| Scope | Required by |
|---|---|
dawiso:user_sync | POST /api/auth/external-user-sync |
Scope required for the external user sync
POST /api/auth/external-user-sync requires an administrator account. When the caller presents an OAuth2 token, the call also requires the dawiso:user_sync scope. Browser sessions and existing personal-token integrations are unaffected.
The External User Sync application is the main consumer of this endpoint. For where it sits among the Dawiso authentication methods, see Authentication methods.
Compared with a personal API token
A personal API token carries the full role of its owner for as long as it stays valid, and it has to be handed to whoever operates the integration.
An integration client’s private key never leaves the machine that generated it. The access token it buys expires in minutes, and its scopes limit what it reaches until then. Prefer it for any integration.