Weave 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

Twitter Bundle Laravel Package

friendsofsymfony/twitter-bundle

Symfony bundle that integrates the Twitter API into your application, providing services for OAuth authentication, posting tweets, and API calls, plus simple YAML configuration and Twig helpers for rendering tweets.

View on GitHub
Deep Wiki
Context7

Getting Started

1. Install the package (expect pinning). The bundle is archived and targets Symfony 2.x-era APIs, so on a modern app Composer will fight you:

composer require friendsofsymfony/twitter-bundle

You will typically need to allow the abandoned dependency and may have to constrain abraham/twitteroauth manually. If composer why-not shows a Symfony version conflict, do not try to patch the bundle — evaluate this as a legacy-only install.

2. Register the bundle. Symfony 3 and earlier: add to AppKernel::registerBundles():

new FOSTwitterBundle\FOSTwitterBundle(),

Symfony 4+: add to config/bundles.php (may work, but the bundle's service definitions and controller signatures are old).

3. Create a Twitter app and get credentials. At developer.twitter.com, create a project/app, then copy the API key and API secret (OAuth 1.0a consumer key/secret). Set the app's Callback URL to the exact URL you will use, e.g. https://example.com/twitter/callback. Set app permissions to Read and write if you intend to post.

4. Configure the bundle. Read DependencyInjection/Configuration.php first — it is the authoritative list of keys for the version you installed. The shape is roughly:

# config/packages/fos_twitter.yaml
fos_twitter:
    consumer_key:    "%env(TWITTER_CONSUMER_KEY)%"
    consumer_secret: "%env(TWITTER_CONSUMER_SECRET)%"
    callback_url:    "https://example.com/twitter/callback"

5. Wire the routes and firewall. Import the bundle routing if you want its built-in login/callback controller:

# config/routes.yaml
fos_twitter:
    resource: "@FOSTwitterBundle/Resources/config/routing.yml"

Make sure the login and callback paths are reachable by anonymous users in security.yaml (anonymous: true / PUBLIC_ACCESS), otherwise the OAuth redirect loop never completes.

Where to look first, in order:

  1. README.md — shortest path to a working flow.
  2. DependencyInjection/Configuration.php — the config keys your installed tag actually accepts.
  3. Resources/config/services.xml (or .yml) — the service IDs you inject.
  4. Controller/TwitterController.php — the reference implementation of the three-legged OAuth handshake.
  5. vendor/abraham/twitteroauth/src/TwitterOAuth.php — the real workhorse; everything the bundle does passes through it.

First use case: "Sign in with Twitter." Hit the bundle's login route, get redirected to Twitter, come back to the callback, and in the callback action call account/verify_credentials to prove the token works and read the screen name. Get that green before attempting any write operations.

Implementation Patterns

Inject the API service, not the controller. The bundle exposes an OAuth client (commonly fos_twitter.api) that is a configured TwitterOAuth instance. In a controller:

public function profileAction(TwitterOAuth $twitter): Response
{
    $me = $twitter->get('account/verify_credentials');

    if ($twitter->getLastHttpCode() !== 200) {
        throw new \RuntimeException('Twitter call failed: '.$twitter->getLastHttpCode());
    }

    return $this->render('twitter/profile.html.twig', ['user' => $me]);
}

Alias the service ID to the TwitterOAuth class in your service config to keep autowiring clean, or define a thin wrapper of your own so you can swap implementations later.

Three-legged OAuth flow (what the bundled controller does). Understand it even if you don't use their controller, because you will almost certainly reimplement it:

// 1. login
$requestToken = $twitter->oauth('oauth/request_token', ['oauth_callback' => $callbackUrl]);
$session->set('twitter_request_token', $requestToken);
return $this->redirect($twitter->url('oauth/authorize', ['oauth_token' => $requestToken['oauth_token']]));

// 2. callback
$stored = $session->get('twitter_request_token');
if (!$request->query->get('oauth_token') || $request->query->get('oauth_token') !== $stored['oauth_token']) {
    throw new BadRequestHttpException('OAuth token mismatch');
}

$accessToken = $twitter->oauth('oauth/access_token', ['oauth_verifier' => $request->query->get('oauth_verifier')]);
$session->set('twitter_access_token', $accessToken); // oauth_token + oauth_token_secret + screen_name + user_id

Persist tokens per user, don't rely on the session. The session is fine for a demo; for anything real, store oauth_token, oauth_token_secret, screen_name, user_id on your User entity (or a TwitterAccount table) and rebuild the client per request:

$twitter->setOAuthToken($user->getTwitterToken());
$twitter->setOAuthTokenSecret($user->getTwitterSecret());

This is what makes background jobs, console commands, and webhooks possible — a session-backed client cannot act outside a browser request.

Posting / interacting. Any v1.1 endpoint is reachable through the generic methods:

$twitter->post('statuses/update', ['status' => $message]);
$twitter->get('statuses/home_timeline', ['count' => 50]);
$twitter->post('friendships/create', ['screen_name' => $handle]);

Upload media is a two-step (media/upload then reference media_ids in statuses/update). Keep media under the size limits or the upload silently fails with an HTTP 400 whose body you must read.

Wrap calls in a domain service. Controllers should not know about getLastHttpCode(). Put a TwitterClient service around TwitterOAuth that returns DTOs, translates HTTP codes into exceptions, and normalizes the inconsistent stdClass vs. array responses. This is the single highest-value refactor when adopting the bundle — it isolates the archived code into one file.

Testing. Never hit the network in tests. Because the bundle's service is just TwitterOAuth, inject a stub or bind a fake TwitterClient interface; assert your domain logic (which tokens get saved, what happens on 401) rather than the OAuth plumbing.

FOSUserBundle integration. If the app uses FOSUserBundle, the bundle ships glue for registering/logging in users from a Twitter identity. Use it only if you are already on FOSUserBundle; otherwise implement the identity mapping yourself — it is about 30 lines and far more debuggable.

Gotchas and Tips

This package is archived and the API under it has moved on. FOSTwitterBundle speaks OAuth 1.0a against Twitter API v1.1. Twitter's v2 API, OAuth 2.0 with PKCE, and the current access-tier rules are not supported, and no fixes are coming. Treat this as maintenance-only: budget a migration to abraham/twitteroauth v4+ (OAuth 1.0a still works) or a v2/OAuth2 client before you build anything new on it.

Free-tier access is the real blocker, not the code. Even a perfectly working install will return 403 on most v1.1 endpoints unless the app has been granted an appropriate access level. When a call "mysteriously fails," check the developer portal's access level before you debug a single line of PHP.

Errors are values, not exceptions. TwitterOAuth returns whatever the API returned and sets getLastHttpCode(). A failed call looks like a successful method call. Always check the code, and log getLastBody() — the error payload is where the actual reason lives (code: 89 = bad token, code: 88 = rate limit, code: 187 = duplicate status).

Callback URL matching is exact. The URL in the developer portal must byte-match the oauth_callback you send, including scheme, trailing slash, and port. Mismatch produces an unhelpful 401 on the callback. https is required outside localhost.

Session state is mandatory and easy to lose. The request token must survive the round trip. If the callback lands on a different domain, or session_start hasn't run, or the user's cookie drops (SameSite/secure misconfiguration), you get a token mismatch or a fresh empty session. Verify oauth_token from the query string matches the stored one — the bundle's controller may check this, your own implementation must.

Signature failures usually mean clock skew. OAuth 1.0a signatures embed a timestamp. A VM with drifting time returns 401 Unauthorized with code 32. Keep NTP running; this failure looks like a credential problem and wastes hours.

Rate limits are per-app and per-user, and they will bite you. v1.1 limits are low (15 requests per 15-minute window on many read endpoints). Cache account/verify_credentials and timelines in your own store, and back off on HTTP 429. Do not call Twitter from a Twig template or a loop.

Never log secrets or tokens. The consumer secret, oauth_token_secret, and full request headers should be excluded from Monolog processors and from exception context. Symfony's var_dump-in-template habit has leaked more tokens than any exploit.

Extension points worth knowing:

  • Decorate the service. fos_twitter.api can be decorated with your own class implementing the same surface, giving you logging, retries, and caching without touching the bundle.
  • Override the controller. Replace the bundled controller with your own route pointing at your own action; you keep the service config and discard the flow.
  • Custom user provider. The FOSUserBundle glue is a provider + listener pair; substituting your own is straightforward and preferable to fighting the original.
  • Templates live under Resources/views/ and can be overridden by the standard bundle override path for your Symfony version.

Version-pinning advice. Since the bundle is archived, pin an exact tag in composer.json and commit composer.lock. Any composer update that floats the bundle or abraham/twitteroauth can break signature behavior or the service definitions with no upstream fix available.

Console and cron jobs need tokens from the database, not the session. This is the most common architectural mistake with this bundle: developers get the browser flow working and then discover they cannot schedule a tweet. Design the token storage as an entity from day one.

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.
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route