Skip to content

Step 2. OAuth2 Setup

If your integration platform requires OAuth2 (redirecting users to their site to grant permission), you need to implement the authorization flow using the AuthorizationServiceTrait.

The Gateway handles the OAuth2 handshake. You need to configure the specialized methods in your integration class or in a dedicated trait if the logic is complex.

The AuthorizationServiceTrait provides the core logic for:

  • Generating the authorization URL
  • Handling the callback
  • Swapping code for token

File: app/Model/YourIntegration.php (or Trait)

use App\Traits\AuthorizationServiceTrait;
class YourIntegration
{
use AuthorizationServiceTrait;
// ...
}

You must implement two specific methods to customize the OAuth2 flow for your platform.

Determines if the integration is missing required authentication data (like access_token).

public function missingParameters($integration)
{
// Check if configuration has access_token
if (empty($integration->configuration['access_token'])) {
return true;
}
// Check if token is expired (if applicable)
if (isset($integration->configuration['expires_at'])) {
return now()->gte($integration->configuration['expires_at']);
}
return false;
}

Generates the authorization URL where the user will be redirected.

public function addParametersRequest($integration)
{
$clientId = config('services.myplatform.client_id');
$redirectUri = route('api.v2.callback', ['service' => 'myplatform']);
$scope = 'read_orders,write_inventory';
// Build the authorization URL
$url = "https://platform.com/oauth/authorize?" . http_build_query([
'client_id' => $clientId,
'redirect_uri' => $redirectUri,
'response_type' => 'code',
'scope' => $scope,
'state' => $integration->gateway_key // Important: Pass gateway_key as state
]);
return [
'type' => 'oauth2',
'url' => $url
];
}

When the platform redirects back to the Gateway, the AuthorizationController handles the request. It looks for a method named authorize{ServiceType} in the controller or associated service.

Naming Convention: authorize + PascalCase(service_type)

Example: For service type shopifyv2, the method is authorizeShopifyv2.

public function authorizeMyplatform(Request $request)
{
$code = $request->input('code');
$gatewayKey = $request->input('state');
// 1. Find the integration
$integration = Integration::where('gateway_key', $gatewayKey)->firstOrFail();
// 2. Exchange code for access token
$response = Http::post('https://platform.com/oauth/token', [
'client_id' => config('services.myplatform.client_id'),
'client_secret' => config('services.myplatform.client_secret'),
'code' => $code,
'grant_type' => 'authorization_code'
]);
$data = $response->json();
// 3. Save token to integration configuration
$config = $integration->configuration;
$config['access_token'] = $data['access_token'];
$config['refresh_token'] = $data['refresh_token'] ?? null;
$config['expires_at'] = now()->addSeconds($data['expires_in'])->toIso8601String();
$integration->configuration = $config;
$integration->save();
return redirect()->to(config('app.frontend_url') . '/integrations');
}

Implement token refreshing logic inside your main IntegrationClass methods.

protected function getClient()
{
// Check expiration
if (now()->gte($this->config['expires_at'])) {
$this->refreshToken();
}
return Http::withToken($this->config['access_token']);
}
protected function refreshToken()
{
$response = Http::post('https://platform.com/oauth/token', [
'grant_type' => 'refresh_token',
'refresh_token' => $this->config['refresh_token'],
'client_id' => config('services.myplatform.client_id'),
'client_secret' => config('services.myplatform.client_secret'),
]);
// Update configuration in database...
}

With authentication handled, you can now build the core integration logic.