Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Oauth Subscriber Laravel Package

guzzlehttp/oauth-subscriber

Guzzle middleware that signs HTTP requests with OAuth 1.0. Compatible with Guzzle 7.10+ and PHP 7.2.5+. Configure consumer/token secrets once on a HandlerStack, then enable per request (auth=oauth) or globally, with optional per-request token override.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup in Laravel

  1. Install the Package Add to composer.json:

    "require": {
        "guzzlehttp/oauth-subscriber": "^0.9"
    }
    

    Run composer update.

  2. Configure OAuth Credentials Store credentials in .env (e.g., for Twitter API):

    OAUTH_CONSUMER_KEY=your_key
    OAUTH_CONSUMER_SECRET=your_secret
    OAUTH_TOKEN=your_token
    OAUTH_TOKEN_SECRET=your_token_secret
    
  3. Create a Guzzle Client with OAuth Middleware In a service class (e.g., app/Services/OAuthClient.php):

    use GuzzleHttp\Client;
    use GuzzleHttp\HandlerStack;
    use GuzzleHttp\Subscriber\Oauth\Oauth1;
    
    class OAuthClient
    {
        public function __construct()
        {
            $stack = HandlerStack::create();
            $stack->push(new Oauth1([
                'consumer_key'    => config('oauth.consumer_key'),
                'consumer_secret' => config('oauth.consumer_secret'),
                'token'           => config('oauth.token'),
                'token_secret'    => config('oauth.token_secret'),
            ]));
    
            $this->client = new Client([
                'base_uri' => config('oauth.base_uri'),
                'handler'  => $stack,
                'auth'     => 'oauth', // Enable OAuth for all requests
            ]);
        }
    
        public function getClient(): Client
        {
            return $this->client;
        }
    }
    
  4. Register the Service in AppServiceProvider Bind the client to Laravel’s container:

    public function register()
    {
        $this->app->singleton(OAuthClient::class, function ($app) {
            return new OAuthClient();
        });
    }
    
  5. First Use Case: Fetch Data Inject the client into a controller or service:

    use App\Services\OAuthClient;
    
    class TwitterController extends Controller
    {
        public function __construct(private OAuthClient $oauthClient)
        {
        }
    
        public function homeTimeline()
        {
            $response = $this->oauthClient->getClient()->get('statuses/home_timeline.json');
            return response()->json($response->getBody());
        }
    }
    

Implementation Patterns

1. Centralized OAuth Configuration

  • Store credentials in config/oauth.php:
    return [
        'consumer_key'    => env('OAUTH_CONSUMER_KEY'),
        'consumer_secret' => env('OAUTH_CONSUMER_SECRET'),
        'token'           => env('OAUTH_TOKEN'),
        'token_secret'    => env('OAUTH_TOKEN_SECRET'),
        'base_uri'        => env('OAUTH_BASE_URI', 'https://api.twitter.com/1.1/'),
    ];
    
  • Use Laravel’s config() helper to access values.

2. Dynamic Credential Switching

Override token/secret per request (e.g., for multi-account APIs):

$response = $client->get('endpoint', [
    'auth' => 'oauth',
    'oauth' => [
        'token'        => 'temp_token',
        'token_secret' => 'temp_secret',
    ],
]);

3. RSA-SHA1 for Private Key Authentication

For APIs requiring RSA (e.g., some enterprise OAuth providers):

$stack->push(new Oauth1([
    'consumer_key'           => config('oauth.consumer_key'),
    'consumer_secret'        => config('oauth.consumer_secret'),
    'private_key_file'       => storage_path('oauth/private_key.pem'),
    'private_key_passphrase' => env('OAUTH_PRIVATE_KEY_PASSPHRASE'),
    'signature_method'       => Oauth1::SIGNATURE_METHOD_RSA,
]));

4. Retry Logic with OAuth Refresh

Use middleware to refresh tokens on failure (e.g., expired tokens):

$client->get('endpoint', [
    'on_stats' => function (TransferStats $stats) {
        if ($stats->getHandler()->getLastTransferWasSuccessful() === false) {
            // Refresh token logic here (e.g., call a token refresh endpoint)
            // Rebuild the client with new credentials
        }
    },
]);

5. Testing with Mocked Responses

Use Laravel’s HTTP testing tools to mock OAuth responses:

$response = $this->get('/api/twitter/timeline')
    ->assertStatus(200)
    ->assertJsonStructure(['data' => []]);

6. Logging OAuth Headers

Inspect signed requests for debugging:

$client->get('endpoint', [
    'debug' => true,
    'on_request' => function (RequestInterface $request) {
        \Log::debug('OAuth Headers:', $request->getHeaders());
    },
]);

Gotchas and Tips

Pitfalls

  1. Nonce Entropy Issues

    • Problem: Weak nonce generation can cause OAuth failures (fixed in v0.8.1).
    • Fix: Ensure your PHP environment has sufficient entropy (e.g., /dev/urandom on Linux).
    • Workaround: Manually set a nonce if needed (not recommended for production):
      $stack->push(new Oauth1([
          'nonce' => 'custom_nonce_' . time(),
          // ... other config
      ]));
      
  2. Duplicate Query Parameters

    • Problem: OAuth 1.0 requires sorted, deduplicated parameters. Guzzle may not handle this automatically.
    • Fix: Pre-process query strings or use Oauth1::SIGNATURE_METHOD_HMAC_SHA256 (more forgiving).
  3. Private Key File Permissions

    • Problem: RSA-SHA1 requires a private key file. Laravel may not have read permissions.
    • Fix: Set correct permissions:
      chmod 600 storage/oauth/private_key.pem
      
  4. Token Secret Not Required for 2-Legged OAuth

    • Gotcha: Omit token_secret for 2-legged OAuth (no user token):
      $stack->push(new Oauth1([
          'consumer_key'    => 'key',
          'consumer_secret' => 'secret',
          'token'           => '', // Empty for 2-legged
          'token_secret'    => '', // Empty for 2-legged
      ]));
      
  5. Middleware Order Matters

    • Problem: If other middleware modifies the request (e.g., adds query params), OAuth signing may break.
    • Fix: Push Oauth1 last in the stack to ensure it signs the final request.
  6. Logging Secrets

    • Problem: Accidentally logging oauth request options can expose secrets.
    • Fix: Avoid logging the entire request options array. Use:
      \Log::debug('Request URL:', $request->getUri());
      

Debugging Tips

  1. Inspect Raw Headers Use Guzzle’s debug handler to see signed requests:

    $client = new Client([
        'handler' => HandlerStack::create([
            new \GuzzleHttp\Handler\CurlHandler(),
            new \GuzzleHttp\Middleware::tap(function (RequestInterface $request) {
                \Log::debug('Request Headers:', $request->getHeaders());
            }),
        ]),
    ]);
    
  2. Validate Signatures Manually Use tools like OAuth 1.0 Playground to test your credentials and signature method.

  3. Check for oauth_signature in Payload

    • Error: If your request body/query includes oauth_signature, the package will throw an error (fixed in v0.8.2).
    • Fix: Remove or encode the parameter before signing.
  4. Timezone Mismatches

    • Problem: OAuth requires timestamps in UTC. Laravel’s default timezone may cause issues.
    • Fix: Set timezone explicitly:
      date_default_timezone_set('UTC');
      

Extension Points

  1. Custom Signature Methods Extend Oauth1 to support non-standard methods (e.g., PLAINTEXT for testing):

    class CustomOauth1 extends Oauth1
    {
        public const SIGNATURE_METHOD_PLAINTEXT = 'PLAINTEXT';
    
        protected function getSignatureMethod(): string
        {
            return self::SIGNATURE_METHOD_PLAINTEXT;
        }
    
        protected function getSignature(string $baseString, string $key): string
        {
            return $key . '&' . $baseString; // PLAINTEXT example
        }
    }
    
  2. Nonce Generation Hook Override nonce logic for custom entropy sources:

    $stack->push(new Oauth1([
        'nonce' => function () {
            return bin2hex(random_bytes(
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
cuci/prototurk-sdk-symfony
clementtalleu/easyadmin-markdown-bundle
codeflextech/permission-manager
karnoweb/livewire-datepicker
sayedenam/sayed-dashboard
milito/query-filter
apiboxsym/user-bundle
apiboxsym/health-check-bundle
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui
babelqueue/php-sdk
facebook/capi-param-builder-php
babelqueue/symfony
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager