Reference
Services, events, routes & commands
Everything the Symfony bundle adds, in one place: class names, service ids, tags, event properties, routes, commands, configuration keys and error messages, exactly as they are in the code. The guides explain when to use each piece.
Classes at a glance
All classes live under Conceptlz\AdobeSign\Symfony\.
| Class | Role |
|---|---|
AdobeSignBundle | The bundle (AbstractBundle, alias adobe_sign): configuration tree and all service definitions. Constant DEFAULT_SCOPES. |
AdobeSignManager | Builds clients; OAuth, token, webhook and signature-level helpers. Implements ResetInterface. |
UserKeyResolver | Interface: keyFor(UserInterface $user): string. |
DefaultUserKeyResolver | Keys tokens by getUserIdentifier(). |
MisconfiguredException | A setting a feature needs is missing or invalid. Extends RuntimeException, implements the core's AdobeSignException. |
TokenStore\TokenEncryptor | libsodium secretbox for stored tokens: encrypt(AccessToken): string, decrypt(string): ?AccessToken. |
TokenStore\CacheTokenStore | Core TokenStore in a PSR-6 pool; adds forget(). |
TokenStore\DoctrineDbalTokenStore | Core TokenStore in a DBAL table; adds forget(), configureSchema(), createTable(), table(). |
TokenStore\DoctrineSchemaListener | Internal: adds the token table to the ORM schema on postGenerateSchema. |
Controller\OAuthController | Actions redirect() and callback(). |
Controller\WebhookController | Invokable webhook endpoint. |
Event\OAuthConnectedEvent | A user finished the OAuth flow. |
Event\WebhookReceivedEvent | A new webhook notification arrived. |
Message\AdobeSignWebhookMessage | The Messenger message for a notification. |
Command\VerifyCommand | adobe-sign:verify. |
Command\CreateTokenTableCommand | adobe-sign:create-token-table. |
Services and aliases
Registered by AdobeSignBundle::loadExtension(). Ids that are class names are autowirable by that type.
Inspect them with php bin/console debug:container adobe_sign and
debug:container 'Conceptlz\AdobeSign'.
| Id | Class | Public | Notes |
|---|---|---|---|
Conceptlz\AdobeSign\Symfony\AdobeSignManager | same | yes | Tags: monolog.logger (channel adobe_sign), kernel.reset (method reset). |
Conceptlz\AdobeSign\AdobeSign | core client | yes | Factory [AdobeSignManager, 'client'], not shared. |
Conceptlz\AdobeSign\Auth\TokenStore | alias | no | Points at the configured store. |
adobe_sign.token_store.cache | CacheTokenStore | no | Only with token_store: cache. Arguments: oauth.token_cache_pool, TokenEncryptor. |
adobe_sign.token_store.doctrine | DoctrineDbalTokenStore | no | Only with token_store: doctrine. Arguments: doctrine.dbal.<connection>_connection, TokenEncryptor, table. |
Conceptlz\AdobeSign\Symfony\TokenStore\DoctrineDbalTokenStore | alias | no | Of adobe_sign.token_store.doctrine, only with token_store: doctrine. |
Conceptlz\AdobeSign\Symfony\TokenStore\TokenEncryptor | same | no | Argument: oauth.encryption_key. |
Conceptlz\AdobeSign\Symfony\UserKeyResolver | DefaultUserKeyResolver | no | Used unless oauth.user_key_resolver names another service. |
adobe_sign.cache | Symfony\Component\Cache\Psr16Cache | no | PSR-16 view of cache_pool, given to every client for the data-centre lookup. |
Conceptlz\AdobeSign\Symfony\Controller\OAuthController | same | yes | Tag controller.service_arguments. |
Conceptlz\AdobeSign\Symfony\Controller\WebhookController | same | yes | Tags controller.service_arguments, monolog.logger (channel adobe_sign). |
Conceptlz\AdobeSign\Symfony\Command\VerifyCommand | same | no | Tag console.command. |
Conceptlz\AdobeSign\Symfony\Command\CreateTokenTableCommand | same | no | Only with token_store: doctrine. |
Conceptlz\AdobeSign\Symfony\TokenStore\DoctrineSchemaListener | same | no | Only with token_store: doctrine and doctrine/orm installed. Tag doctrine.event_listener (postGenerateSchema). |
What the manager receives
The resolved configuration, the TokenStore, the UserKeyResolver (or
oauth.user_key_resolver), adobe_sign.cache, and these optional services, each passed as
null when missing: logger, the http_client service or psr18.http_client,
router, security.token_storage and clock.
AdobeSignManager methods
| Method | Returns | Throws |
|---|---|---|
client() | AdobeSign | MisconfiguredException |
forUser(UserInterface|string|int $user) | AdobeSign | MisconfiguredException (OAuth not configured) |
isConnected(UserInterface|string|int $user) | bool | whatever the store throws |
oauth() | Conceptlz\AdobeSign\Auth\OAuthClient | MisconfiguredException |
tokens() | Conceptlz\AdobeSign\Auth\TokenStore | |
webhookHandler() | Conceptlz\AdobeSign\Webhook\WebhookHandler | MisconfiguredException |
userKey(UserInterface|string|int $user) | string | |
signatureLevel() | Conceptlz\AdobeSign\Enum\SignatureLevel | MisconfiguredException |
qualifiedIssuers() | list<string> | |
signatureShortfalls(string $agreementId, ?SignatureLevel $required = null) | list<string> | SDK exceptions; InvalidArgumentException for QES without issuers |
reset() | void |
Descriptions and examples: The manager's methods.
Events
Both extend Symfony\Contracts\EventDispatcher\Event and are dispatched under their class name, so #[AsEventListener] on an __invoke(TheEvent $e) method is enough.
OAuthConnectedEvent
| Property | Type | Content |
|---|---|---|
$user | Symfony\Component\Security\Core\User\UserInterface | The signed-in user who connected. |
$key | string | Token-store key, from userKey(). |
$apiAccessPoint | ?string | The account's API host, e.g. https://api.eu1.adobesign.com/. |
Dispatched by OAuthController::callback() after the token is stored, before the redirect.
WebhookReceivedEvent
| Property | Type | Content |
|---|---|---|
$event | Conceptlz\AdobeSign\Webhook\WebhookEvent | The typed notification: AgreementEvent, MegaSignEvent, WidgetEvent, LibraryDocumentEvent or UnknownEvent. |
Dispatched synchronously by WebhookController for each new notification (duplicates dropped), before the Messenger message.
The Messenger message
final class AdobeSignWebhookMessage
__construct(array $payload), readonly $payload: the decoded notification body.
event(): WebhookEvent rebuilds the typed event; notificationId(): ?string returns webhookNotificationId.
Dispatched on webhooks.messenger.bus after WebhookReceivedEvent, only when webhooks.messenger is enabled, without stamps. See Async with Messenger.
Routes
Import from @AdobeSignBundle/config/routes.php (all) or @AdobeSignBundle/config/routes/oauth.php / routes/webhook.php.
| Name | Methods | Path | Controller | Notes |
|---|---|---|---|---|
adobe_sign_oauth_redirect | GET | /adobe-sign/oauth/redirect | OAuthController::redirect | Needs a session. Protect with access_control. |
adobe_sign_oauth_callback | GET | /adobe-sign/oauth/callback | OAuthController::callback | Needs a session and a signed-in user. |
adobe_sign_webhook | GET, POST | /adobe-sign/webhook | WebhookController | Stateless. Must be public: no login, no session. |
Responses
| Route | Status | When |
|---|---|---|
| redirect | 302 | Always (to Adobe's consent page), unless OAuth is misconfigured (500). |
| callback | 302 | Tokens stored; to oauth.redirect_after. |
| callback | 400 | STATE_MISMATCH, MISSING_CODE, or an untrusted api_access_point. |
| callback | 401 | No signed-in user ("Sign in before connecting Acrobat Sign."). |
| callback | 403 | Adobe returned an error or refused the code. |
| callback | 502 | Adobe unreachable ("Acrobat Sign could not be reached. Please try again."). |
| webhook | 200 | Accepted (including duplicates): JSON {"xAdobeSignClientId": "<id>"} and header X-AdobeSign-ClientId. |
| webhook | 400 | POST body isn't a JSON object with an event. |
| webhook | 403 | Client id header missing or not allowed. Empty body. |
| webhook | 500 | No allow-list (MisconfiguredException), or a listener or the bus threw. |
Console commands
adobe-sign:verify
php bin/console adobe-sign:verify [--user=KEY]
Calls GET /users/me with the default client, or with
forUser(KEY) when --user is given, and prints the user's email, whether they are an account
admin, and the account id. Exit code 0 on success; 1 with the SDK's message on any AdobeSignException
(including MisconfiguredException). Always registered.
adobe-sign:create-token-table
php bin/console adobe-sign:create-token-table
Creates the token table on the configured connection if it doesn't exist ("Created table …" or "Table … already
exists."). Always exits 0. Registered only with oauth.token_store: doctrine.
Configuration keys
| Key | Type | Default |
|---|---|---|
auth | scalar | integration_key |
integration_key | scalar | null |
oauth.client_id | scalar | null |
oauth.client_secret | scalar | null |
oauth.redirect_uri | scalar | null (route adobe_sign_oauth_callback) |
oauth.scopes | list | AdobeSignBundle::DEFAULT_SCOPES |
oauth.redirect_after | scalar | / |
oauth.user_key_resolver | service id | null |
oauth.token_store | cache | doctrine | service id | cache |
oauth.token_cache_pool | service id | cache.app |
oauth.encryption_key | scalar | %kernel.secret% |
oauth.doctrine.connection | scalar | default |
oauth.doctrine.table | scalar | adobe_sign_tokens |
signature_level | scalar | ses |
qualified_issuers | list | [] |
bootstrap_url | scalar | https://api.adobesign.com |
base_uri_ttl | integer | 86400 |
retries.max | integer | 3 |
retries.max_delay_seconds | float | 60.0 |
cache_pool | service id | cache.app |
http_client | service id | null |
webhooks.client_ids | list | [] (falls back to oauth.client_id) |
webhooks.dedupe_ttl | integer | 259200 |
webhooks.messenger.enabled | boolean | false |
webhooks.messenger.bus | service id | messenger.default_bus |
Effects and examples: Configuration.
Exceptions
MisconfiguredException
The message always names the setting. The complete list:
| Message | Thrown by |
|---|---|
| Set adobe_sign.integration_key (usually "%env(ADOBE_SIGN_INTEGRATION_KEY)%"), or adobe_sign.auth: oauth. | client() |
| adobe_sign.auth is "oauth" but no user is signed in; use AdobeSignManager::forUser($user). | client() |
| adobe_sign.auth must be "integration_key" or "oauth"; got "…". | client() |
| Set adobe_sign.oauth.client_id and client_secret to use OAuth. | oauth(), so also forUser(), the OAuth routes |
| Set adobe_sign.oauth.redirect_uri: the router is not available to build it. | oauth() |
| Set adobe_sign.webhooks.client_ids (or adobe_sign.oauth.client_id) to receive webhooks. | webhookHandler(), so the webhook route |
| adobe_sign.signature_level must be ses, aes or qes; got "…". | signatureLevel(), and every client creation |
| adobe_sign.oauth.encryption_key is empty; set it or kernel.secret (APP_SECRET). | TokenEncryptor, on first encrypt or decrypt |
Core exceptions you will meet
Everything else comes from the core and implements Conceptlz\AdobeSign\Exception\AdobeSignException:
ApiException and its subclasses (AuthenticationException, OAuthException,
NotFoundException, ValidationException, AccountCapabilityException,
PreconditionFailedException, RateLimitException), plus TransportException,
InvalidArgumentException and WebhookException. See the core's
errors page.
Common questions
Can I decorate or extend AdobeSignManager?
It isn't final, so you can, and Symfony's #[AsDecorator(AdobeSignManager::class)] works. Its constructor is marked internal, though, so prefer wrapping it in your own service over subclassing; the constructor may change between minor versions.
Why can't I autowire CacheTokenStore?
It is registered under adobe_sign.token_store.cache without a class alias. Autowire Conceptlz\AdobeSign\Auth\TokenStore, or call $manager->tokens() and check instanceof CacheTokenStore when you need forget().
In which order do listeners for WebhookReceivedEvent run?
By priority, like any Symfony listener: #[AsEventListener(priority: 10)] runs before the default 0. stopPropagation() stops later listeners but not the Messenger message, which is dispatched afterwards regardless.
Can I point my own routes at the bundle's controllers?
Yes. The controllers are public services tagged controller.service_arguments; define a route with controller: Conceptlz\AdobeSign\Symfony\Controller\WebhookController (or OAuthController::callback). Keep the webhook route stateless and the default redirect URI in mind: it is generated from adobe_sign_oauth_callback, so set oauth.redirect_uri if you rename the callback.