Adobe Sign for Laravelconceptlz/adobe-sign-laravel GitHub

Start here

Installation

From composer require to a verified connection in about five minutes. By the end of this page your app can call Acrobat Sign with an Integration Key, or is ready for users to connect their own accounts through OAuth.

Requirements

NeedsVersion or detail
PHP8.2 or newer
Laravel12 or 13 (illuminate/* ^12.0 || ^13.0)
Core SDKconceptlz/adobe-sign ^0.4, installed for you
HTTP clientAny PSR-18 client. Laravel already ships Guzzle, so there is nothing to add.
Database tableOnly for OAuth (adobe_sign_tokens)
Acrobat Sign accountAny plan, including a free developer account

Install in five steps

  1. Require the package
    composer require conceptlz/adobe-sign-laravel

    This also installs the core SDK at the matching version. Both packages are released together with one version number, so you never have to line them up yourself.

  2. Let auto-discovery register it

    The package's composer.json declares the service provider Conceptlz\AdobeSign\Laravel\AdobeSignServiceProvider and the facade alias AdobeSign, so Laravel picks both up with no code changes. If your app turns off discovery for this package (dont-discover), add the provider to bootstrap/providers.php yourself.

  3. Publish the config (optional)
    php artisan vendor:publish --tag=adobe-sign-config

    This copies config/adobe-sign.php into your app. You only need it to change values that have no .env variable, such as route prefixes, middleware or the retry limits. The package merges its defaults, so a key you leave out of your copy still has a value.

  4. Publish and run the migration (OAuth only)
    php artisan vendor:publish --tag=adobe-sign-migrations
    php artisan migrate

    This creates the adobe_sign_tokens table where each user's OAuth tokens are stored, encrypted with APP_KEY. The package does not load its migration automatically, so nothing touches your database until you publish it. Skip this step if you only use an Integration Key.

  5. Add credentials and verify

    Set the .env keys described below, then run:

    php artisan adobe-sign:verify

Integration Key or OAuth?

Acrobat Sign has two ways to authenticate API calls. The choice is about whose account sends the agreements, not about security level; both are fine for production.

Integration KeyOAuth 2.0
SenderOne Acrobat Sign account (yours)Each user's own Acrobat Sign account
Typical appInternal tools, a SaaS that sends from its own accountA product where customers bring their own Acrobat Sign
SetupOne .env valueAn API application at Adobe, a redirect URI, the token table
ExpiryDoes not expire; revoke it in Acrobat SignAccess tokens last about an hour and refresh automatically; refresh tokens lapse after 60 days without use
Bridge APIAdobeSign::agreements(), injected AdobeSignAdobeSign::forUser($user), or the default client with ADOBE_SIGN_AUTH=oauth

You can use both in one app: an Integration Key as the default client, and forUser() for users who connected their own account.

.env for an Integration Key

Create the key in Acrobat Sign under Account → Acrobat Sign API → API Information → Integration Key. Adobe asks which scopes the key may use; enable the ones your app needs (reading, writing and sending agreements, and webhooks if you receive them). Then:

.env
ADOBE_SIGN_INTEGRATION_KEY=3AAABLblqZhB...your-key...

# Only if you receive webhooks: the client id(s) Adobe sends in X-AdobeSign-ClientId
ADOBE_SIGN_WEBHOOK_CLIENT_IDS=

ADOBE_SIGN_AUTH defaults to integration_key, so that single line is enough to make the facade work.

.env for OAuth

Create an API application in Acrobat Sign (Account → Acrobat Sign API → API Applications), note its client id and secret, and add your callback URL as a redirect URI in the application's OAuth configuration. The package's callback route is /adobe-sign/oauth/callback.

.env
ADOBE_SIGN_CLIENT_ID=CBJCHBCAABAA...
ADOBE_SIGN_CLIENT_SECRET=your-client-secret

# Optional: defaults to route('adobe-sign.oauth.callback'), e.g. https://app.example.com/adobe-sign/oauth/callback
ADOBE_SIGN_REDIRECT_URI=

# Optional: make the facade and injected client use the signed-in user's connection
ADOBE_SIGN_AUTH=oauth

With OAuth configured, the webhook allow-list falls back to ADOBE_SIGN_CLIENT_ID, so webhooks created through your OAuth app are accepted without further settings. The full flow is on the OAuth page.

Keep the secrets out of Git

The Integration Key gives full API access to the account it belongs to, and the client secret lets anyone exchange codes for tokens. Keep both in .env or your secret manager, never in config/adobe-sign.php. The SDK redacts the Authorization header and OAuth secrets from every exception it throws.

Check the connection

adobe-sign:verify calls GET /users/me with the default client and prints who the credentials belong to. It is the quickest way to tell a bad key from a problem in your own code.

$ php artisan adobe-sign:verify

   INFO  Connected to Acrobat Sign.

  User ............................................ admin@example.com
  Account admin ................................................... yes
  Account ...................................... CBJCHBCAABAAaccount1

On failure it prints the SDK's error message, including Adobe's error code, and exits non-zero, so you can also run it in a deploy pipeline. To check one user's OAuth connection instead of the default client, pass their token key (by default the user's id):

php artisan adobe-sign:verify --user=42

The first call also discovers your account's data centre (na1, eu1, …) and stores it in your cache, so later requests skip that step.

The HTTP client (PSR-18)

The core SDK talks HTTP through the PSR-18 interface rather than a specific library. Every Laravel app already has Guzzle 7, which implements PSR-18, and php-http/discovery finds it at runtime. There is nothing to install or configure.

If you want a specific client (a proxy, custom timeouts, a client with extra middleware), bind it in the container. The bridge uses a bound Psr\Http\Client\ClientInterface before falling back to discovery:

app/Providers/AppServiceProvider.php
use GuzzleHttp\Client;
use Psr\Http\Client\ClientInterface;

public function register(): void
{
    $this->app->bind(ClientInterface::class, fn () => new Client([
        'timeout' => 60,          // large combined PDFs can take a while
        'connect_timeout' => 10,
        'proxy' => env('OUTBOUND_PROXY'),
    ]));
}

That binding is application-wide, so any other package that resolves ClientInterface gets the same client. The same mechanism is how tests swap in a fake client; see Testing.

Composer may ask about php-http/discovery

php-http/discovery is also a Composer plugin, and Composer asks whether to trust it the first time. Either answer works for a standard Laravel app: the plugin only installs missing PSR implementations, and Laravel already has them. Record your answer under config.allow-plugins in composer.json so CI doesn't ask again.

Upgrading

Update both packages together so the bridge and the core stay on the same release:

composer update conceptlz/adobe-sign-laravel conceptlz/adobe-sign

While the version is below 1.0, a minor bump (0.4 → 0.5) can contain breaking changes, and the bridge's ^0.4 constraint keeps you on 0.4.x until you change your own constraint. Read the changelog before moving to a new minor version. If you published the config file, compare it with the package's copy after upgrading, since new keys only reach your app through the merged defaults.

Common questions

Do I need the migration if I only use an Integration Key?

No. The adobe_sign_tokens table only stores OAuth tokens. With an Integration Key the package never touches the database. If you later add OAuth, publish and run the migration then.

Do I have to publish the config file?

No. The package merges its own config/adobe-sign.php, and the important values come from .env. Publish it when you need to change keys that have no environment variable, such as oauth.route_prefix, webhooks.path or retries.max. See Configuration.

adobe-sign:verify says MisconfiguredException. What is missing?

The message names the missing setting: usually ADOBE_SIGN_INTEGRATION_KEY, or OAuth client credentials when ADOBE_SIGN_AUTH=oauth. With ADOBE_SIGN_AUTH=oauth the command has no signed-in user, so check a specific connection with --user=. If you cache config, run php artisan config:clear after editing .env. More in Troubleshooting.

Do I need to install Guzzle or another HTTP library?

No. Laravel requires Guzzle, which implements PSR-18, and the SDK discovers it automatically. Bind your own Psr\Http\Client\ClientInterface only if you need custom options such as a proxy.

Does it work with Lumen or Laravel 11?

The package supports Laravel 12 and 13 only, which is what CI tests. On other frameworks, including older Laravel versions, use the framework-agnostic core SDK directly; it only needs PSR interfaces.