Installation
composer require diglin/oauth2-oro-provider:^1.0
Configure the Bundle
Add to config/packages/diglin_oauth2_oro.yaml:
diglin_oauth2_oro:
api:
url: "https://your-oro-app.com" # Required (no trailing slash)
client_id: "your_client_id" # Required
client_secret: "your_secret" # Required
First Use Case: Fetching an Access Token
use Diglin\OAuth2OroBundle\OAuth2\OroProvider;
$provider = new OroProvider([
'url' => 'https://your-oro-app.com',
'client_id' => 'your_client_id',
'client_secret' => 'your_secret',
]);
// For password grant (if enabled on Oro side)
$token = $provider->getAccessToken('username', 'password', 'password');
// For authorization code grant (redirect flow)
$authUrl = $provider->getAuthorizationUrl();
// Redirect user to $authUrl, then handle callback with:
$token = $provider->getAccessToken('authorization_code', ['code' => $code]);
// Step 1: Generate auth URL
$provider = new OroProvider(config());
$authUrl = $provider->getAuthorizationUrl([
'scope' => ['api', 'read', 'write'], // Customize scopes as needed
]);
// Step 2: Handle callback (e.g., in a Symfony controller)
public function callback(Request $request)
{
$provider = new OroProvider(config());
$token = $provider->getAccessToken('authorization_code', [
'code' => $request->query->get('code'),
]);
// Store token (e.g., in session or database)
$this->storeToken($token);
return redirect()->route('dashboard');
}
$provider = new OroProvider(config());
$token = $provider->getAccessToken('username', 'password', 'password');
// Use token to fetch API data
$client = $provider->getRegisteredClient();
$response = $client->get('api/rest/v1/users', [
'headers' => ['Authorization' => 'Bearer ' . $token->getToken()]
]);
$provider = new OroProvider(config());
$newToken = $provider->getAccessToken('refresh_token', [
'refresh_token' => $storedRefreshToken,
]);
use Symfony\Contracts\HttpClient\HttpClientInterface;
public function __construct(HttpClientInterface $client, OroProvider $provider)
{
$this->client = $client;
$this->provider = $provider;
}
public function fetchUserData()
{
$response = $this->client->request('GET', 'https://your-oro-app.com/api/rest/v1/users/me', [
'auth_bearer' => $this->provider->getLastAccessToken()->getToken(),
]);
return $response->toArray();
}
OroPlatform supports custom scopes. Extend the provider to add dynamic scopes:
$provider = new OroProvider(config());
$provider->setScopes(['api', 'custom_scope1', 'custom_scope2']);
$authUrl = $provider->getAuthorizationUrl();
The underlying league/oauth2-client provides additional utilities:
League\OAuth2\Client\Provider\Token\AccessToken to persist tokens.if (!$token->validate()) {
throw new \RuntimeException('Invalid token');
}
$client = $provider->getRegisteredClient();
$response = $client->post('api/rest/v1/custom-endpoint', [
'json' => ['data' => 'value'],
'headers' => ['Authorization' => 'Bearer ' . $token->getToken()]
]);
Register the provider as a service in services.yaml:
services:
App\Service\OroAuthService:
arguments:
$provider: '@diglin_oauth2_oro.provider'
Then inject it into controllers/services:
use Diglin\OAuth2OroBundle\OAuth2\OroProvider;
class OroAuthService
{
public function __construct(private OroProvider $provider) {}
}
url Config/api/rest/v1/users). If the url config has a trailing slash (e.g., https://app.com/), requests will fail.url is configured without a trailing slash:
url: "https://your-oro-app.com" # Correct
# url: "https://your-oro-app.com/" # Incorrect
password grant without enabling it on the OroPlatform side or without providing username/password in config.password grant is enabled in OroPlatform’s OAuth settings.username and password in config or use authorization_code flow.api instead of API).refresh_token alongside the access_token.try {
$token = $this->provider->getLastAccessToken();
if (!$token->hasExpired()) {
return $token;
}
} catch (\League\OAuth2\Client\Provider\Exception\ExpiredTokenException $e) {
$token = $this->provider->getAccessToken('refresh_token', [
'refresh_token' => $storedRefreshToken,
]);
}
state parameter is not handled.state parameter in the authorization flow:
$state = bin2hex(random_bytes(32));
$authUrl = $provider->getAuthorizationUrl(['state' => $state]);
// Store $state in session
$request->getSession()->set('oauth_state', $state);
// In callback, validate:
if ($request->query->get('state') !== $request->getSession()->get('oauth_state')) {
throw new \RuntimeException('CSRF state mismatch');
}
Add this to your config to log OAuth2 requests/responses:
$provider = new OroProvider(config());
$provider->getRegisteredClient()->setDebug(true);
$provider->getRegisteredClient()->setDebugFile('/tmp/oauth2.log');
client_id and client_secret match those in your config.authorization_code, password).Before integrating, test the OAuth flow manually:
curl -X POST "https://your-oro-app.com/oauth/v2/token" \
-d "grant_type=password&username=test&password=test&client_id=your_id&client_secret=your_secret"
OroPlatform may return custom error responses. Catch and parse them:
try {
$token = $provider->getAccessToken('password', ['username' => 'user', 'password' => 'pass']);
} catch (\League\OAuth2\Client\Provider\Exception\IdentityProviderException $e) {
$error = json_decode($e->getResponseBody(), true);
// Handle Oro-specific errors (e.g., $error['error'] === 'invalid_grant')
}
Extend the provider to add OroPlatform-specific logic:
How can I help you explore Laravel packages today?