ruLog in to Senler

OAuth Integration

First obtain the client credentials and register a Redirect URI, then set the permissions. Keep Client Secret only on the server.

Authorization request

Open https://senler.io/oauth/authorize in the browser with these parameters:

  • response_type=code, the only supported response type;
  • client_id, the application's Client ID;
  • redirect_uri, an exact registered address;
  • subject=project|user, the access scenario; project is used when omitted;
  • project_id, an optional preselected project only for subject=project;
  • scope, an optional set of can_* permissions in selected mode or project_access/user_access in dynamic mode;
  • state, a random one-time value stored by the integration until the user returns.

Example project authorization with project selection in Senler AI:

https://senler.io/oauth/authorize?response_type=code&client_id=CLIENT_ID&redirect_uri=https%3A%2F%2Fexample.com%2Foauth%2Fcallback&subject=project&scope=project_access&state=RANDOM_STATE

For the user scenario, replace subject=project with subject=user, use the matching scope, and do not add project_id.

After approval, Senler AI returns code and the original state to the Redirect URI. After denial, it returns error=access_denied, error_description, and state. The integration server must compare the returned state with the stored value. The code is valid for 10 minutes and can be used only once.

Exchanging the code for tokens

Send POST https://api.senler.io/api/apps/oauth/token as application/x-www-form-urlencoded or JSON. Client ID and Client Secret can be passed through HTTP Basic or body fields, but not as two conflicting values.

curl -X POST https://api.senler.io/api/apps/oauth/token \
  -u 'CLIENT_ID:CLIENT_SECRET' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'grant_type=authorization_code' \
  --data-urlencode 'code=AUTHORIZATION_CODE' \
  --data-urlencode 'redirect_uri=https://example.com/oauth/callback'

The response contains access_token, refresh_token, token_type=Bearer, expires_in, scope, and subject. It also returns project_id for subject=project or user_id for subject=user. Use the access token as Authorization: Bearer ... and rely on expires_in instead of assuming a lifetime.

Refreshing tokens

To refresh, send grant_type=refresh_token and the current refresh_token to the same endpoint, authenticating the OAuth client again.

curl -X POST https://api.senler.io/api/apps/oauth/token \
  -u 'CLIENT_ID:CLIENT_SECRET' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'grant_type=refresh_token' \
  --data-urlencode 'refresh_token=REFRESH_TOKEN'

After a successful request, the previous refresh token is revoked and the response contains a new token pair. Store both new values before the next refresh.

Revoking a user authorization

To disconnect one external client or revoke your own user authorization, open Connected applications in Account settings. Disconnecting a client ends access only for that connection; revoking the user authorization disconnects all of its clients. Client Secret regeneration replaces the OAuth client key, but it does not revoke user access that has already been granted.

Token endpoint errors

The token endpoint returns { "error": "...", "error_description": "..." }:

  • invalid_request means a required parameter is absent or parameters conflict;
  • invalid_client means Client ID or Client Secret is invalid; the HTTP status is 401;
  • invalid_grant means the code or refresh token expired, was already used, was revoked, or was issued to another client;
  • unauthorized_client means the application type does not support OAuth;
  • unsupported_grant_type means grant_type is not supported.

Start a new authorization after invalid_grant, verify the current Client Secret after invalid_client, and correct other errors using error_description. Do not retry the same request indefinitely.