Authorization

Wafeq implements the OAuth 2.0 authorization framework.

Endpoints

GET https://app.wafeq.com/oauth/authorize/
POST https://app.wafeq.com/oauth/token/
POST https://app.wafeq.com/oauth/token/revoke/

Authorization Code Flow

Prerequisites

This guide assumes that you already have created an app.

Examples

You can find example apps implementing the authorization code flow in the oauth2-client-examples repository.

List of scopes

ScopeDescription
basicBasic access to organization info
usersAccess to organization list of users
bulk_invoicesBulk sending invoices api
chart_of_accounts.readRead-only access to chart of accounts data
chart_of_accounts.writeRead and Write access to chart of accounts data
bank_accounts.readRead-only access to bank_accounts data
bank_accounts.writeRead and Write access to bank accounts data
beneficiaries.readRead-only access to beneficiaries data
beneficiaries.writeRead and Write access to beneficiaries data
contacts.readRead-only access to contacts data
contacts.writeRead and Write access to contacts data
employees.readRead-only access to employees data
employees.writeRead and Write access to employees data
tax_rates.readRead-only access to tax_rates data
tax_rates.writeRead and Write access to tax_rates data
invoices.readRead-only access to invoices data
invoices.writeRead and Write access to invoices data
expenses.readRead-only access to expenses data
expenses.writeRead and Write access to expenses data
bills.readRead-only access to bills data
bills.writeRead and Write access to bills data
journals.readRead-only access to journals data
journals.writeRead and Write access to journals data
reportsRead-only access to reports
payroll.readRead-only access to payroll data
payroll.writeRead and Write access to payroll data
payments.readRead-only access to payments data
payments.writeRead and Write access to payments data

Request User Authorization

The first step is to request authorization from the user, so your app can access the Wafeq resources in behalf that user.
To do so, your application must build and send a GET request to the /oauth/authorize/ endpoint with the following parameters:

Query ParamValue
client_idRequired: The Client ID generated after registering your application.
response_typeRequired: Set to code.
redirect_uriRequired: The URI to redirect to after the user grants or denies permission. This URI needs to have been entered in the Redirect URI allowlist that you specified when you registered your application. The value of redirect_uri here must exactly match one of the values you entered when you registered your application, including upper or lowercase, terminating slashes, and such.
scopeRequired: A space-separated list of scopes.
stateOptional, but strong recommended: This provides protection against attacks such as cross-site request forgery. See RFC-6749.

If you're implementing the PKCE extension, you must include these additional parameters.

Query ParamValue
code_challenge_methodRequired: Set to S256
code_challengeRequired: Set to the code challenge that your app calculated.

In order to generate the code_challenge, your app should hash the code verifier using the SHA256 algorithm.
The code verifier is a random string between 43 and 128 characters in length. It can contain letters, digits,
underscores, periods, hyphens, or tildes.

Response

User accepts

Query ParamsValue
codeAn authorization code that can be exchanged for an Access Token.
stateThe value of the state parameter supplied in the request.

Example,

https://your-domain.com/callback?code=NApCCg..BkWtQ&state=34fFs29kd09

User denies

Query ParamsValue
errorThe reason authorization failed, for example: access_denied.
stateThe value of the state parameter supplied in the request.

Example,

https://your-domain.com/callback?error=access_denied&state=34fFs29kd09

Request Access Token

If the user accepted your request, then your app is ready to exchange the authorization code for an Access Token.
It can do this by making a POST request to the /token/ endpoint.

The body of this POST request must contain the following parameters encoded in application/x-www-form-urlencoded:

Request Body ParameterValue
grant_typeRequired: This field must contain the value authorization_code.
codeRequired: The authorization code returned from the previous request.

If you're implementing the PKCE extension, you must include these additional parameters.

Request Body ParameterValue
client_idRequired: The Client ID generated after registering your application.
code_verifierRequired: The value of this parameter must match the value of the code_verifier that your app generated in the previous step.

The request must also include the following HTTP headers:

Header ParametersValue
AuthorizationRequired: Base 64 encoded string that contains the Client ID and Client Secret Key. The field must have the format: Authorization: Basic <base64 encoded client_id:client_secret>
Content-TypeRequired: Always set to application/x-www-form-urlencoded.

Response

KeyValue TypeValue Description
access_tokenstringAn Access Token that can be provided in subsequent calls
refresh_tokenstringAn Refresh token which is used to fetch a new access_token to be then used in making authenticated API calls.
token_typestringHow the Access Token may be used: always Bearer.
expires_inintThe time period (in seconds) for which the Access Token is valid.

Example:

curl --location \
    --request POST https://app.wafeq.com/oauth/token/ \
    --header 'Authorization: Basic NTMwO...3MWJi' \
    --header 'Content-Type: application/x-www-form-urlencoded' \
    --data-urlencode 'redirect_uri=https://your-domain.com/callback' \
    --data-urlencode 'grant_type=authorization_code' \
    --data-urlencode 'code=83YqX...mlezV'

The response will be similar to this:

{
   "access_token": "NgA6ZcYI...ixn8bUQ",
   "refresh_token": "NgAagA...Um_SHo",
   "token_type": "Bearer",
   "expires_in": 3600
}

Request a refreshed Access Token

Access tokens are deliberately set to expire after a short time, after which new tokens may be granted by supplying the refresh token originally obtained during the authorization code exchange.
In order to refresh the token, a POST request must be sent with the following body parameters encoded in application/x-www-form-urlencoded:

Request Body ParameterValue
grant_typeRequired: Set it to refresh_token.
refresh_tokenRequired: The refresh token returned from the authorization code exchange.

If you're implementing the PKCE extension, you must include these additional parameters.

Request Body ParameterValue
client_idRequired: The Client ID generated after registering your application.

The request must also include the following HTTP headers:

Header ParametersValue
AuthorizationRequired: Base 64 encoded string that contains the Client ID and Client Secret Key. The field must have the format: Authorization: Basic <base64 encoded client_id:client_secret>
Content-TypeRequired: Always set to application/x-www-form-urlencoded.

Example:

curl --location \
    --request POST https://app.wafeq.com/oauth/token/ \
    --header 'Authorization: Basic NTMwO...3MWJi' \
    --header 'Content-Type: application/x-www-form-urlencoded' \
    --data-urlencode 'grant_type=refresh_token' \
    --data-urlencode 'refresh_token=0uOmz...GNu77'

The response will be similar to this:

{
   "access_token": "NgA6ZcYI...ixn8bUQ",
   "token_type": "Bearer",
   "expires_in": 3600
}

Revoking a Token

To enhance security and allow users to revoke access to their data, Wafeq provides a token revocation endpoint. This allows clients to invalidate both access tokens and refresh tokens.

To revoke a token, send a POST request to the token revocation endpoint:

POST https://app.wafeq.com/oauth/token/revoke/

Request Parameters

The request must include the following parameters in the body, encoded as application/x-www-form-urlencoded:

ParameterDescription
client_idRequired: Your OAuth 2.0 client ID.
client_secretRequired: Your OAuth 2.0 client secret.
tokenRequired: The token to be revoked. This can be either an access token or a refresh token.
token_type_hintRequired: A hint about the type of token being revoked. Can be either access_token or refresh_token.

Headers

The request must include the following HTTP header:

HeaderValue
Content-TypeRequired: Always set to application/x-www-form-urlencoded.

Example Request

Here's an example using cURL:

curl --location \
    --request POST https://app.wafeq.com/oauth/token/revoke/ \
    --header 'Content-Type: application/x-www-form-urlencoded' \
    --data-urlencode "client_id=$CLIENT_ID" \
    --data-urlencode "client_secret=$CLIENT_SECRET" \
    --data-urlencode "token=NgA6ZcYI...ixn8bUQ" \
    --data-urlencode "token_type_hint=access_token"