Authentication and Authorization

OAuth 2.0 is an open authorization protocol that enables applications to obtain secure, delegated access to user accounts on an HTTP service. It works by authorizing third-party applications to access specific user data without requiring access to a user's private credentials. Your application uses OAuth libraries or endpoints to implement the OAuth 2.0 authorization that allows it to access the data through CORE APIs. This means it can use OAuth 2.0 to obtain permission from a CORE user to access and modify data in the CORE company database. The OAuth 2.0 Authorization Code flow allows your app to access CORE APIs on behalf of a user, after the user grants consent. For more information on OAuth 2.0, see RFC 6749.

All requests to CORE APIs must be sent over HTTPS and require TLS 1.2 or higher. Requests sent over insecure HTTP or unsupported TLS versions are rejected.


OpenID Connect

OpenID Connect (OIDC) 1.0 is a simple identity layer and authentication protocol built on top of OAuth 2.0. It enables your application to verify the identity of the end-user based on authentication performed by the CORE Authorization Server, and to obtain basic profile information about the user in a secure and interoperable way.

OIDC is optional in CORE APIs. You only use it if your application needs to know the identity of the user (for example, to display their name or email, or to implement single sign-on). If you only need to access CORE APIs on behalf of a user, you can use OAuth 2.0 without OIDC.

OIDC can be used with any application type supported by CORE, including web, native, and JavaScript apps.

Using OpenID Connect

To use OIDC, simply include the openid scope in your authorization request when using the Auth Code flow. You may also request additional OIDC scopes (profile, email, and address) to access more user information.

Example authorization request
GET /connect/authorize?client_id=YOUR_CLIENT_ID&response_type=code&scope=openid%20profile%20email&redirect_uri=https://yourapp.com/oauth-callback

When the user completes authentication and grants consent, your app receives an authorization code. Exchange this code at the token endpoint as usual. Because you requested the openid scope, the token response includes an id_token (a JSON Web Token containing user identity claims), along with the usual access_token.

Example token response
  • id_token: Contains information about the authenticated user, signed by CORE
  • access_token: Used to access CORE APIs

After receiving the id_token, your app should validate it to ensure it was issued by CORE and has not been tampered with. Check Tokens: Validate an ID Token for details. If your app needs additional user profile information, you can call the userinfo endpoint using the access token. Check Tokens: User Info Endpoint for details.


Discovery Document

The Discovery Document is a JSON document containing key-value pairs that provide details about the CORE authorization server. The information provided by the discovery document includes authorization URLs, token, endpoints, scopes and userinfo. You can find CORE’s discovery document on:


Application Types

When you register an app on the CORE Developer Portal, you must select an application type, which determines how your app connects and interacts with CORE APIs. The table below summarizes the key differences between each application type, including where your code runs, whether a client secret is used, and whether security features like Proof Key for Code Exchange (PKCE) and Pushed Authorization Requests (PAR) are required. Use this table to understand the requirements for each app type.

Application Type (Developer Portal) Where code runs Client secret used PKCE PAR

Regular Web App

Server-side backend

Yes

Optional but recommended

No

Web App (FAPI/PAR)

Server-side backend

Yes

Required

Required

JavaScript App

Browser

No

Optional but recommended

No

Native App

Mobile or Desktop

No

Required

No

Proof Key for Code Exchange (PKCE) is a security technique that helps protect OAuth 2.0 Authorization Code flows against authorization code interception attacks. It is primarily used by public clients, such as mobile apps and single-page applications, which cannot securely store a client_secret, but it can also be used by confidential clients for additional protection. The client generates a random code_verifier and creates a code_challenge by applying a cryptographic hash to the verifier. The code_challenge is sent in the initial authorization request, and the original code_verifier is required when exchanging the authorization code for tokens. This ensures that only the app that started the flow can complete it. For details, see RFC 7636.

Choosing an Application Type

Choosing the right application type depends primarily on where your code runs and whether it can securely store a client secret. Below are the recommended use cases for each app type:

  • Regular Web App for server-side applications such as Node.js, ASP.NET Core, PHP, or Java Spring that can securely store a client secret
  • Web App (FAPI/PAR) for the same server-side scenario where your environment also requires FAPI 2.0 compliance or a hardened OAuth pattern for regulated or security-sensitive integrations
  • JavaScript App for single-page applications that run entirely in the browser with no server-side component, such as React, Angular, or Vue
  • Native App for applications that run on a mobile or desktop device, such as iOS, Android, Windows, or macOS

Only Regular Web App and Web App (FAPI/PAR) support refresh tokens. If your integration requires long-lived sessions or uninterrupted access without re-prompting the user for consent, use one of these app types.


Regular Web App

Regular Web App is the standard application type for server-side web applications that implement the OAuth 2.0 Authorization Code flow. Your server-side code handles token exchange and stores credentials securely. Unlike public clients (JavaScript or Native apps), Regular Web Apps use a Client Secret to authenticate with the CORE Authorization Server.

This application type is a confidential client (it runs on a server and can store secrets). Never expose your client_secret in browser code or public repositories.

Flow Summary

The Regular Web App Authorization Code flow involves these steps:

  1. Your app constructs an authorization URL and redirects the user's browser to it.
  2. The user logs in to CORE and grants consent on the consent screen.
  3. The CORE Authorization Server redirects the user back to your Redirect URI with an authorization code.
  4. Your server exchanges the authorization code for an access token (and optionally a refresh token) at the token endpoint.
Endpoints used in the flow

Base URI:

Endpoints:

  • Authorization: GET /connect/authorize
  • Token: POST /connect/token

Step 1: Redirect the user to the authorization endpoint

Your app initiates the flow by constructing an authorization URL and redirecting the user's browser to it.

Endpoint used

/connect/authorize

Example request
GET /connect/authorize?client_id=YOUR_CLIENT_ID&response_type=code&scope=readwrite%3Acore%20offline_access&redirect_uri=YOUR_REDIRECT_URI&state=STATE_VALUE

Authorization request parameters
ParameterValuesDescription
client_id
required
Your app’s Client IDIdentifies the app making the request. Use the value from your app’s details in the Developer Portal Dashboard.
scope
required
Space-delimited set of permissions that the app is requestingSpecifies what level of access your app is requesting. The values passed in this parameter inform the consent screen shown to the users.

Available scopes include:
read:core – Read only access to company data
readwrite:core – Full access to company data
offline_access – To request a refresh token
openid – Access to a user's details like name, address, etc.
profile – Access to a user's profile excluding address and email
address – Access to the address claim on the userinfo endpoint
email – Access to the email claim on the userinfo endpoint

redirect_uri
required
One of the Redirect URIs registered for your appSpecifies where the Authorization Server should send the response. The value must match exactly (including scheme, host, path, case, and any trailing slashes) with one of the Redirect URIs registered for your app in the Developer Portal. Otherwise the authorization request is rejected and the users see an error page. See Getting Started: Understanding your Redirect URI for details.
response_type
required
codeIndicates the type of response your app expects. For Authorization Code flow, this must always be code, meaning your app expects to receive an authorization code.
stateBase64-encoded JSON object that can hold multiple valuesAn optional value your app can send in the authorization request. It is returned unchanged by the Authorization Server, allowing your app to verify that the response is tied to the original request. This can help with preventing Cross-Site Request Forgery (CSRF) attacks.

Step 2: User login and consent

After being redirected, users see a secure CORE Log In screen where they enter their CORE company credentials. After logging in, they are shown a consent screen displaying your app's name and the permissions it is requesting. The users can click Grant Permission to authorize your app, or Decline to refuse access. If the users grant offline_access, your app also receives a refresh token in the token response. For more details on this step, see Getting Started: Implement Authorization Code Flow.

Step 3: Handle the redirect back to your app

If the user grants access, the CORE Authorization Server redirects to your registered Redirect URI with an authorization code and the state value (if provided):

Example response
https://YOUR_REDIRECT_URI?code=AUTHORIZATION_CODE&state=STATE_VALUE

Your app must then:

  • Extract the code from the query string.
  • Verify that the returned state matches the value your app originally sent. This round-trip check helps ensure the response belongs to a legitimate request.

If the user declines access, the Authorization Server redirects to your Redirect URI with the following parameters.

Parameter Value
error access_denied
error_description User declined access

Step 4: Exchange the authorization code for tokens

Your server exchanges the authorization code for an access token and a refresh token (if offline_access was granted) by sending a POST request to the token endpoint. This request must be made server-side and not from the browser.

Endpoint used

/connect/token

Example request
curl --request POST \
  --url /connect/token \
  --header 'content-type: application/x-www-form-urlencoded' \
  --data 'grant_type=authorization_code' \
  --data 'redirect_uri=YOUR_REDIRECT_URI' \
  --data 'code=AUTHORIZATION_CODE' \
  --data 'client_id=YOUR_CLIENT_ID' \
  --data 'client_secret=YOUR_CLIENT_SECRET'

Token request parameters
Parameter Description

grant_type required

Must be authorization_code

code required

The authorization code received at your Redirect URI in Step 3

redirect_uri required

Must match the Redirect URI used in the authorization request

client_id required

Your app's Client ID

client_secret required

Your app's Client Secret

Example response

A refresh_token is included only if the user granted offline_access. The endpoint field in the response is your Base URL for all subsequent API calls.

Response fields
Field Description
access_token The token your app must include in all CORE API requests
refresh_token Used to obtain a new access token without user interaction (only returned if offline_access was granted)
expires_in Remaining lifetime of the access token in seconds
token_type Identifies the type of token returned

Common Errors and Troubleshooting

Authorization redirect fails

Common causes:

  • redirect_uri does not exactly match the registered value
  • client_id is incorrect or belongs to a different app
  • An invalid or unsupported scope was requested (invalid_scope)
Token exchange fails

Common causes:

  • Wrong or reused authorization code (invalid_grant)
  • redirect_uri mismatch between the authorization and token requests
  • Missing or incorrect client_secret (invalid_client)

Security Notes

  • Store client_secret on the server only. Never expose it in client-side code, URLs, or logs.
  • Always use and validate the state parameter to mitigate CSRF attacks.
  • Authorization codes are single-use. Discard them immediately after the token exchange.
  • Use short-lived sessions for pending authorization requests and clear them after the token exchange is complete.

Web App (FAPI/PAR)

Web App (FAPI/PAR) is a high-security application type for server-side web applications that must use a hardened OAuth 2.0 pattern. It is designed for regulated or security-sensitive integrations and builds on the Regular Web App Authorization Code flow, with these key differences:

  • The authorization request parameters are pushed to a backchannel Pushed Authorization Request (PAR) endpoint first, instead of being placed directly in the browser redirect query string.
  • The browser redirect uses a short-lived request_uri reference returned by the PAR endpoint.
  • PKCE is required, in addition to Client Secret.

This application type is a confidential client (it runs on a server and can store secrets). Never expose your client_secret or PKCE code_verifier in browser code.

Flow Summary

The Web App (FAPI/PAR) Authorization Code flow typically includes these steps:

  1. Your server generates PKCE values (code_verifier and code_challenge).
  2. Your server sends a Pushed Authorization Request (PAR) to CORE Authorization Server and receives a request_uri.
  3. Your app redirects the user’s browser to the authorization endpoint using the request_uri.
  4. CORE Authorization Server authenticates the user and shows the consent screen.
  5. After the user grants consent, CORE Authorization Server redirects the user back to your redirect URI with an authorization code.
  6. Your server exchanges the code for tokens at the token endpoint, sending the client_secret and code_verifier.

For more details on PAR, refer to RFC 9126.

Endpoints used in the flow

Base URI:

Endpoints:

  • PAR: POST /connect/par
  • Authorization: GET /connect/authorize
  • Token: POST /connect/token

Step 1: Generate PKCE values

Before you start the flow, your server must:

  • Generate a code_verifier: a cryptographically random string (43–128 characters)
  • Derive a code_challenge: Base64 URL-encoded SHA-256 hash of the code_verifier
  • Set code_challenge_method to S256

Store the code_verifier securely on the server (for example, in the user’s session) until the token exchange step.

Step 2: Send the Pushed Authorization Request (PAR)

Unlike the Regular Web App flow, your server sends the authorization parameters to the PAR endpoint instead of sending authorization parameters directly to /connect/authorize in the browser.

Endpoint used

/connect/par

Example request using form-encoded body
curl --request POST \
  --url /connect/par \
  --header 'content-type: application/x-www-form-urlencoded' \
  --data 'client_id=YOUR_CLIENT_ID' \
  --data 'client_secret=YOUR_CLIENT_SECRET' \
  --data 'response_type=code' \
  --data 'redirect_uri=YOUR_REDIRECT_URI' \
  --data 'scope=readwrite%3Acore%20offline_access' \
  --data 'state=STATE_VALUE' \
  --data 'code_challenge=YOUR_CODE_CHALLENGE' \
  --data 'code_challenge_method=S256'

PAR request parameters
Parameter Description

client_id required

Your app’s Client ID from the Developer Portal

client_secret required

Your app’s Client Secret that you must have stored securely when registering the app on the Developer Portal

response_type required

Must be code

redirect_uri required

Must exactly match a Redirect URI registered for your app

scope required

Space-delimited scopes, URL-encoded in form requests. Example: readwrite:core offline_access

state strongly recommended

CSRF protection value returned back to your redirect URI

code_challenge required

PKCE code challenge derived from code_verifier

code_challenge_method required

Must be S256

A successful PAR response returns a short-lived request_uri value:

Example response

Save the full request_uri value and use it immediately in the redirect step. Do not treat it as a long-lived value.

Step 3: Redirect the user to the authorization endpoint

After receiving the request_uri, redirect the user’s browser to /connect/authorize using only the client_id and request_uri.

Endpoint used

/connect/authorize

Example request
GET ?client_id=YOUR_CLIENT_ID&request_uri=REQUEST_URI

Step 4: User Consent

From this point forward, the user experience is the same as the Regular Web App flow. For more details on this step, see Getting Started: Implement Authorization Code Flow.

  1. Users see a secure CORE Log In screen where they need to enter their CORE company credentials.
  2. After logging in, users see a consent screen showing requested permissions (scopes).
  3. On the consent screen, users can click Grant Permission to grant the selected permissions to your app or Decline to refuse access.
  4. If the users grant permission, the Authorization Server redirects them to your Redirect URI with an authorization code.

Step 5: Handle the redirect back to your app

If a user grants access to your app, the CORE Authorization Server redirects to your registered redirect_uri with a code and (if you provided it) state.

Example response
https://YOUR_REDIRECT_URI?code=AUTHORIZATION_CODE&state=STATE_VALUE

Your app must then:

  • Extract code
  • Verify that state matches the value you originally generated and stored

If the user declines consent, your app receives an error response at the redirect URI (error=access_denied).

Step 6: Exchange the authorization code for tokens

Your server exchanges the authorization code for tokens using the token endpoint. For Web App (FAPI/PAR), the token request must include:

  • client_secret (confidential client)
  • code_verifier (PKCE)
Endpoint used

/connect/token

Example request
curl --request POST \
  --url /connect/token \
  --header 'content-type: application/x-www-form-urlencoded' \
  --data 'grant_type=authorization_code' \
  --data 'redirect_uri=YOUR_REDIRECT_URI' \
  --data 'code=AUTHORIZATION_CODE' \
  --data 'client_id=YOUR_CLIENT_ID' \
  --data 'client_secret=YOUR_CLIENT_SECRET' \
  --data 'code_verifier=YOUR_CODE_VERIFIER'

Token request parameters
Parameter Description

grant_type required

Must be authorization_code

code required

Authorization code received at your redirect URI

redirect_uri required

Must match the redirect URI used earlier in the PAR request

client_id required

Your app's Client ID

client_secret required

Your app's Client Secret

code_verifier required

The original PKCE verifier used to generate the code_challenge

The response contains an access_token. If the user granted offline_access, the response also includes a refresh_token.

Example response

Common Errors and Troubleshooting

PAR request fails immediately

Common causes:

  • Invalid client credentials (invalid_client)
  • Missing required parameter (invalid_request)
  • Redirect URI mismatch
  • Scope not valid (invalid_scope)
Authorization redirect fails

Common causes:

  • Expired or invalid request_uri
  • Wrong (client_id)
  • Attempting to reuse a (request_uri)
Token exchange fails

Common causes:

  • Wrong or reused authorization code (invalid_grant)
  • Redirect URI mismatch
  • Missing or incorrect code_verifier
  • Invalid client_secret

Security Notes

  • Store client_secret and code_verifier on the server only.
  • Always use and validate state to mitigate CSRF.
  • Use short-lived sessions for pending authorization requests and clear them after the token exchange.

JavaScript App

JavaScript apps are single-page apps (or browser-based apps) that run entirely in the browser after loading the Javascript and HTML source code from a web page. As the entire source is available to the browser, they cannot maintain the confidentiality of a client secret. So the secret is not used for these apps. The Authorization Code flow here is similar to Regular Web App, but at the last step, the authorization code is exchanged for an access token without using the client secret.

Authorization

The authorization code is a temporary code that a client exchanges for an access token. The code is obtained from an authorization server, where the user gets a chance to see what information the client is requesting and whether to approve or deny the request.

Step 1: Initiating the Authorization Request

The first step of the flow is to initiate the authorization process by redirecting the user to CORE authorization server. The discussion here assumes the base URI is:

GET /connect/authorize?client_id=a17c21ed&response_type=code&state=5ca75bd30&redirect_uri=https://example-app.com/auth

Authorization Grant Parameters

The following parameters are used to make the authorization request.

Name Value Description

response_type

code

response_type is set to code indicating that you want an authorization code as the response

client_id

The client ID you obtain from the developer portal dashboard

The client_id is the identifier for your app. You will have received a client_id when first registering your app on the CORE developer portal

redirect_uri

One of the redirect URI values listed for this project in the developer portal dashboard

Required. Determines where the response is sent. The value of this parameter must exactly match one of the values listed for this app in the app settings. This includes the scheme, host, path, case, and any trailing slash

scope

These are the set of permissions that the application requests. Multiple scopes can be passed in a single request separated by whitespace

Required. Identifies the CORE API access that your application is requesting. The values passed in this parameter inform the consent screen that is shown to the user.
Available scopes include:
read:core- Read only access to company data
readwrite:core- Full access to company data
openid- Provides access to a user's details like name, address, etc.
profile- Provides access to a user's profile excluding address and email
address- Provides access to address claim at the UserInfo endpoint
email- Provides access to email claim at the UserInfo endpoint

state (recommended)

This field can be a Base64 encoded JSON object that can hold multiple values

Authorization protocols provide a state parameter. During authentication, the application sends this parameter in the authorization request. The Authorization Server returns this parameter unchanged in the response. Your application can use this parameter in order to make sure that the response belongs to a request that was initiated by the same user. Therefore, state helps mitigate CSRF attacks. Restore the previous state of your application


The lack of using a client secret means that using the state parameter is even more important for single-page apps.

Step 2: User Consent
After the user visits the authorization page, CORE displays a log-in window. Enter you CORE credentials and click Login.

permission-screen

When logged in, CORE displays a consent dialog with the name of your application and CORE Company name, requesting permission to access with your authorization credentials including scope, etc.

permission-screen

If you click Grant Permission, the server redirects to the website with an authorization code and state value in the URL query string.

CORE does not allow you to log-in to multiple companies during a single client app instance.

Handling the Response

The response is sent to the redirect_uri that you specified in the request. All responses are returned in the query string, as shown below:

Response
 http://yourdemoapp.com?code=CODE

Step 3: Exchange the Authorization Code for an Access Token

To exchange the Authorization Code for an Access Token, the app makes a POST request to CORE’s token endpoint. The request will have the following parameters.

Name Values Description
grant_type Authorization code Required. The grant_type parameter must be set to “authorization_code“
code Code value received Required. This parameter is for the authorization code received from the authorization server, which is in the query string parameter “code”
redirect_uri One of the redirect URI values listed for this project in the developer portal dashboard If the redirect URL was included in the initial authorization request, it must be included in the token request as well and must be identical
Client_Id The client ID you obtain from the developer portal dashboard Required.Despite the client secret not being used in this flow, the request requires sending the client ID to identify the application making the request. This means the client must include the client ID as a POST body parameter

Example: The request might look like the following.

Request


The response is sent back as a json object given below:

Response


Handling the Response

A successful response to this request contains the following fields:

Name Description
access_token The token that must be used to access the CORE APIs
token_type Identifies the type of token returned. At this time, the field will always have the value Bearer
Expires_in The remaining lifetime of the access token in seconds. The value always returned is 3600 seconds (1 hour)
Id_token Returned for openid and associated user scopes for user authentication

Native App

If you are building a native application, the authorization code flow with a Proof Key for Code Exchange (PKCE) is the favored method for regulating the access between your application and a resource server. It includes an additional step at the beginning and an extra verification at the end.

When the native app begins the authorization request, instead of immediately launching a browser, the client first creates what is known as a ‘Code Verifier .‘ It is a cryptographically random string using the characters A-Z, a-z, 0-9, and the punctuation characters -._~ (hyphen, period, underscore, and tilde), between 43 and 128 characters long.

After the app has generated the code verifier, it uses that to create the ‘Code Challenge.’ The code challenge is a BASE64-URL-encoded string of SHA256 hash of the code verifier.

A complete authorization request will include the following parameters.


Initiating the Authorization Request

GET /connect/authorize?response_type=code&client_id=bJyXzz6X4pY0Qc5EuvKXL9UZ1hvGvt3X.apps.bqe.com&redirect_uri=http://localhost/pkcetestapp&scope=readwrite:core&state=pcMYJ722TrooUTrk&code_challenge=2cWTIbQvY6MNnIK4J8-p1Bb_8gqvv7YSZGRllDyb7f4&code_challenge_method=S256


Authorization Grant Parameters

The following parameters are used to make the authorization request.

Parameter Value Description

response_type

Code

Response_type is set to code indicating that you want an authorization code as the response

client_id

The client_id you obtain from the Developer Portal

The client_id is the identifier for your app. You will have received a client_id when first registering your app on the CORE Developer Portal

redirect_uri

One of the redirect URI values listed for this project in the developer portal dashboard

Required. Determines where the response is sent. The value of this parameter must exactly match one of the values listed for this app in the app settings. This includes the scheme, the same case

 

scope

Required. Identifies the CORE API access that your application is requesting. The values passed in this parameter inform the consent screen that is shown to the user. Available scopes include:
read:core- Read only access to company data
readwrite:core- Full access to company data
openid- Provides access to a user's details like name, address, etc.
profile- Provides access to a user's profile excluding address and email
address- Provides access to address claim at the UserInfo endpoint
email- Provides access to email claim at the UserInfo endpoint

State (recommended)

This field can be a Base64 encoded JSON object that can hold multiple values

Authorization protocols provide a state parameter. During authentication, the application sends this parameter in the authorization request. The Authorization Server returns this parameter unchanged in the response.
Your application can use this parameter in order to
make sure that the response belongs to a request that was initiated by the same user. Therefore, state helps mitigate CSRF attacks

code_challenge

The code challenge generated

Base64-URL-encoded string of SHA256 hash of the Code Verifier

code_challenge_method

Whether the challenge is the plain verifier string or SHA256 hash of the string

Step 2: User Consent

After you visit the authorization page, CORE displays a log-in window. Enter your CORE credentials and click Login.

permission-screen

When logged in, CORE displays a consent dialog with the name of your application and CORE Company name, requesting permission to access your authorization credentials including scope, etc.

permission-screen

If you click Grant Permission, the server redirects to the website with an authorization code and state.

CORE does not allow you to log-in to multiple companies amid a single client app instance.

Handling the response
The response is sent to the redirect URI specified in the request. All responses are returned in the query string as shown below:

Response
 https://www.coredemo.com/oauth-redirect?code=CODE


Step 3: Exchanging Authorization Code for an Access Token

To exchange the Authorization Code for an Access Token, the app makes a POST request to CORE token endpoint. The request has the following parameters:

Name Values Description

grant_type

Authorization Code

Required. The grant_type parameter must be set to ‘authorization_code’

code

Code value received

Required. This parameter is for the authorization code received from the authorization server, which is in the query string parameter ‘code’

redirect_uri

One of the redirect URI values listed for this project in the Developer Portal

If the redirect URI was included in the initial authorization request, it must be included in the token request as well and must be identical

client_Id

The client id you obtain from the Developer Portal

This is the applications registered client id

code_verifier

Cryptographically random string

The code verifier for the PKCE request that the app originally generated before the authorization request

Example: The actual request might look like the following.

Request


The response is sent back as a json object given below:

Response


Handling the response

A successful response to this request contains the following fields:

Name Description
access_token The token that must be used to access the CORE APIs.
expires_in The remaining lifetime of the access token in seconds. The value always returned is 3600 seconds (one hour). Use the refresh token to get a fresh one
token_type Identifies the type of token returned. At this time, this field will always have the value 'bearer'
id_token Returned for openid and associated user scopes during authentication