PHPackages                             rebelpl/oauth2-businesscentral - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Authentication &amp; Authorization](/categories/authentication)
4. /
5. rebelpl/oauth2-businesscentral

ActiveLibrary[Authentication &amp; Authorization](/categories/authentication)

rebelpl/oauth2-businesscentral
==============================

Business Central OAuth 2.0 Client Provider for The PHP League OAuth2-Client

v1.2(8mo ago)11.8k↓42.4%MITPHPPHP ^7.2|^8

Since May 6Pushed 8mo ago1 watchersCompare

[ Source](https://github.com/rebelpl/oauth2-businesscentral)[ Packagist](https://packagist.org/packages/rebelpl/oauth2-businesscentral)[ RSS](/packages/rebelpl-oauth2-businesscentral/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (4)Dependencies (4)Versions (5)Used By (0)

Business Central OAuth2 Client
==============================

[](#business-central-oauth2-client)

This package provides # Business Central OAuth 2.0 support for the PHP League's [OAuth 2.0 Client](https://github.com/thephpleague/oauth2-client).

Pre-requisites
--------------

[](#pre-requisites)

The app you want to connect to BC must be setup in [Entra admin center](https://entra.microsoft.com/#home) &gt; Identity &gt; Applications &gt; [App registrations](https://entra.microsoft.com/#view/Microsoft_AAD_RegisteredApps/ApplicationsListBlade/quickStartType~/null/sourceType/Microsoft_AAD_IAM)

There are two main authorization flow options, you need to set up your app accordingly:

### Option 1: Client credentials (service-to-service)

[](#option-1-client-credentials-service-to-service)

With this option the app will always work with the same set of permissions - defined in Business Central.

- Authentication: Web + Redirect URI =
- Certificates &amp; secrets: New client secret
- API permissions: Add permission &gt; Dynamics 365 Business Central &gt; Application permissions &gt; *API.ReadWrite.All*

In Business Central go to Microsoft Entra Applications, add the New app using Application (client) ID. Set up permissions required for the app (for example *D365 BUS FULL ACCESS*). Depending on the tenant's settings, administrator might need to "Grant Consent" for the app.

### Option 2: Authorization code (login-as)

[](#option-2-authorization-code-login-as)

With this option the app will work with the permissions of the user who uses it (and needs to log in).

- Authentication: Web + Redirect URI =
- Certificates &amp; secrets: New client secret
- API permissions: Add permission &gt; Dynamics 365 Business Central &gt; Delegated permissions: *Financials.ReadWrite.All*, *user\_impersonation*

Depending on the tenant's settings, administrator might need to grant consent for the app. You can use `$provider->getAdminConsentUrl()` for that purpose.

Installation
------------

[](#installation)

To install, use composer:

```
composer require rebelpl/oauth2-businesscentral

```

Usage
-----

[](#usage)

Usage is the same as The League's OAuth client, using `\Rebel\OAuth2\Client\Provider\BusinessCentral` as the provider.

### Client Credentials Grant

[](#client-credentials-grant)

```
$provider = new Rebel\OAuth2\Client\Provider\BusinessCentral([
    // Required
    'tenantId'                  => 'mydomain.com',
    'clientId'                  => 'xxxxx-yyyy-zzzz-xxxx-yyyyyyyyyyyy',
    'clientSecret'              => '*************************',
]);

$token = $provider->getAccessToken('client_credentials', [
    'scope' => Rebel\OAuth2\Client\Provider\BusinessCentral::CLIENT_CREDENTIALS_SCOPE
]);

// We might save the token somewhere safe for later use
$filename = __DIR__ . '/tokens.json';
file_put_contents($filename, json_encode($token->jsonSerialize(), JSON_PRETTY_PRINT));
```

### Authorization Code Grant

[](#authorization-code-grant)

```
$provider = new Rebel\OAuth2\Client\Provider\BusinessCentral([
    // Required
    'tenantId'                  => 'mydomain.com',
    'clientId'                  => 'xxxxx-yyyy-zzzz-xxxx-yyyyyyyyyyyy',
    'clientSecret'              => '*************************',
    'redirectUri'               => 'https://example.com/callback-url',
]);

// For CSRF protection
session_start();

// Handle OAuth error message
if (isset($_GET['error'])) {
    echo "Error: " . $_GET['error'] . "";
    echo "Description: " . $_GET['error_description'] . "";
    exit();
}

// If we don't have an authorization code then get one
if (!isset($_GET['code'])) {

    $authorizationUrl = $provider->getAuthorizationUrl();
    $_SESSION['oauth2state'] = $provider->getState();
    header('Location: ' . $authorizationUrl);
    exit;

// Check given state against previously stored one to mitigate CSRF attack
} elseif (empty($_GET['state']) || ($_GET['state'] !== $_SESSION['oauth2state'])) {

    if (isset($_SESSION['oauth2state'])) {
        unset($_SESSION['oauth2state']);
    }

    exit('Invalid state');

} else {

    // Try to get an access token (using the authorization code grant)
    $token = $provider->getAccessToken('authorization_code', [
        'code' => $_GET['code']
    ]);

    // We have an access token, which we may use in authenticated
    // requests against the Business Central API.
    echo 'Access Token: ' . $token->getToken() . "";
    echo 'Refresh Token: ' . $token->getRefreshToken() . "";
    echo 'Expired in: ' . $token->getExpires() . "";
    echo 'Already expired? ' . ($token->hasExpired() ? 'expired' : 'not expired') . "";

    // We might save the token somewhere safe for later use,
    // but remember it should be stored per-user, not globally
    $filename = __DIR__ . '/tokens.json';
    file_put_contents($filename, json_encode($token->jsonSerialize(), JSON_PRETTY_PRINT));
}
```

Refreshing a Token
------------------

[](#refreshing-a-token)

```
$provider = new Rebel\OAuth2\Client\Provider\BusinessCentral([
    // Required
    'tenantId'                  => 'mydomain.com',
    'clientId'                  => 'xxxxx-yyyy-zzzz-xxxx-yyyyyyyyyyyy',
    'clientSecret'              => '*************************',
]);

// load existing tokens from storage
$filename = __DIR__ . '/tokens.json';
$token = new League\OAuth2\Client\Token\AccessToken(json_decode(file_get_contents($filename), true));

if ($token->hasExpired()) {
    $token = $provider->getAccessToken('refresh_token', [
        'refresh_token' => $token->getRefreshToken()
    ]);

    // Purge old tokens and store new ones to your data store.
    file_put_contents($filename, json_encode($token->jsonSerialize(), JSON_PRETTY_PRINT));
}
```

Use access token - API v2
-------------------------

[](#use-access-token---api-v2)

```
// ...
$tenantId = $provider->getTenantId();
$environment = 'production';

// API v2.0:
$apiUrl = "https://api.businesscentral.dynamics.com/v2.0/$tenantId/$environment/api/v2.0";

$client = new GuzzleHttp\Client();
$response = $client->get($apiUrl . '/companies', [
    'headers' => [
        'Authorization' => 'Bearer ' . $token->getToken(),
        'Accept' => 'application/json'
    ]
]);

$data = json_decode($response->getBody(), true);
if (!isset($data['value'])) {
    throw new \Exception('No data returned from API.');
}

echo "Available companies (API):\n";
foreach ($data['value'] as $company) {
    echo " - {$company['name']}:\t{$company['id']}\n";
}
```

Use access token - OData v4
---------------------------

[](#use-access-token---odata-v4)

```
// ...
$tenantId = $provider->getTenantId();
$environment = 'production';

// OData v4:
$oDataUrl = "https://api.businesscentral.dynamics.com/v2.0/$tenantId/$environment/ODataV4";

$client = new GuzzleHttp\Client();
$response = $client->get($oDataUrl . '/Company', [
    'headers' => [
        'Authorization' => 'Bearer ' . $token->getToken(),
        'Accept' => 'application/json'
    ]
]);

$data = json_decode($response->getBody(), true);
if (!isset($data['value'])) {
    throw new \Exception('No data returned from API.');
}

echo "Available companies (OData):\n";
foreach ($data['value'] as $company) {
    echo " - {$company['Name']}:\t{$company['Id']}\n";
}
```

Testing
-------

[](#testing)

```
./vendor/bin/phpunit

```

###  Health Score

34

—

LowBetter than 77% of packages

Maintenance62

Regular maintenance activity

Popularity23

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity35

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~45 days

Total

4

Last Release

241d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/411846?v=4)[Artur Jedliński](/maintainers/nataniel)[@nataniel](https://github.com/nataniel)

---

Top Contributors

[![nataniel](https://avatars.githubusercontent.com/u/411846?v=4)](https://github.com/nataniel "nataniel (13 commits)")

---

Tags

clientoauthoauth2authorizationauthorisationbusiness central

###  Code Quality

TestsPHPUnit

Code StylePHP\_CodeSniffer

### Embed Badge

![Health badge](/badges/rebelpl-oauth2-businesscentral/health.svg)

```
[![Health](https://phpackages.com/badges/rebelpl-oauth2-businesscentral/health.svg)](https://phpackages.com/packages/rebelpl-oauth2-businesscentral)
```

###  Alternatives

[stevenmaguire/oauth2-keycloak

Keycloak OAuth 2.0 Client Provider for The PHP League OAuth2-Client

2275.9M27](/packages/stevenmaguire-oauth2-keycloak)[patrickbussmann/oauth2-apple

Sign in with Apple OAuth 2.0 Client Provider for The PHP League OAuth2-Client

1132.5M6](/packages/patrickbussmann-oauth2-apple)[mollie/oauth2-mollie-php

Mollie Provider for OAuth 2.0 Client

251.7M1](/packages/mollie-oauth2-mollie-php)[omines/oauth2-gitlab

GitLab OAuth 2.0 Client Provider for The PHP League OAuth2-Client

36721.5k13](/packages/omines-oauth2-gitlab)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
