Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Install and configure Adobe Developer Console OAuth Server-to-Server credentials. Use when setting up a new Adobe integration, configuring API credentials, or initializing Adobe SDKs (Firefly Services, PDF Services, I/O Runtime). Trigger with phrases like "install adobe", "setup adobe", "adobe auth", "configure adobe credentials", "adobe developer console".
.claude/skills/jeremylongshore-adobe-install-auth/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 1% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 58% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 27% | 0% |
| case-05 | ✗→✓ | ▲ Improved | 124% | 0% |
| case-07 | ✗→✓ | ▲ Improved | 32% | 0% |
Set up Adobe Developer Console OAuth Server-to-Server credentials and install the appropriate SDK for your use case. As of January 2025, JWT (Service Account) credentials are deprecated -- all new integrations must use OAuth Server-to-Server.
client_id, client_secret, and scopesbash# Firefly Services (Photoshop API, Lightroom API, Firefly API) npm install @adobe/firefly-apis @adobe/photoshop-apis @adobe/lightroom-apis # PDF Services (create, extract, convert, generate documents) npm install @adobe/pdfservices-node-sdk # Adobe I/O Events (webhooks, event-driven) npm install @adobe/aio-lib-events # Adobe I/O SDK (App Builder, Runtime actions) npm install @adobe/aio-sdk # Adobe I/O CLI (global install for aio commands) npm install -g @adobe/aio-cli # Python — PDF Services pip install pdfservices-sdk
bash# .env (NEVER commit — add to .gitignore) ADOBE_CLIENT_ID=your_client_id_from_console ADOBE_CLIENT_SECRET=your_client_secret_from_console ADOBE_SCOPES=openid,AdobeID,read_organizations,firefly_api,ff_apis ADOBE_IMS_ORG_ID=your_org_id@AdobeOrg
typescript// src/adobe/auth.ts import 'dotenv/config'; interface AdobeTokenResponse { access_token: string; token_type: string; expires_in: number; // seconds, typically 86400 (24h) } let cachedToken: { token: string; expiresAt: number } | null = null; export async function getAdobeAccessToken(): Promise<string> { // Return cached token if still valid (with 5min buffer) if (cachedToken && cachedToken.expiresAt > Date.now() + 300_000) { return cachedToken.token; } const response = await fetch('https://ims-na1.adobelogin.com/ims/token/v3', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: new URLSearchParams({ client_id: process.env.ADOBE_CLIENT_ID!, client_secret: process.env.ADOBE_CLIENT_SECRET!, grant_type: 'client_credentials', scope: process.env.ADOBE_SCOPES!, }), }); if (!response.ok) { const error = await response.text(); throw new Error(`Adobe auth failed (${response.status}): ${error}`); } const data: AdobeTokenResponse = await response.json(); cachedToken = { token: data.access_token, expiresAt: Date.now() + data.expires_in * 1000, }; return cachedToken.token; }
bash# Quick verification with curl curl -X POST 'https://ims-na1.adobelogin.com/ims/token/v3' \ -H 'Content-Type: application/x-www-form-urlencoded' \ -d "client_id=${ADOBE_CLIENT_ID}&client_secret=${ADOBE_CLIENT_SECRET}&grant_type=client_credentials&scope=${ADOBE_SCOPES}"
node_modules or Python site-packages.env file with credentials (git-ignored)getAdobeAccessToken() function with token caching| Error | Cause | Solution | |-------|-------|----------| | invalid_client | Wrong client_id or client_secret | Verify credentials in Developer Console | | invalid_scope | Scopes not entitled to your org | Check product profile assignments in Admin Console | | 401 Unauthorized | Expired or revoked credentials | Regenerate client_secret in Developer Console | | ENOTFOUND ims-na1.adobelogin.com | Network/DNS issue | Check firewall allows outbound HTTPS to *.adobelogin.com | | JWT credentials deprecated | Using old Service Account (JWT) | Migrate to OAuth Server-to-Server (JWT EOL was June 2025) |
typescriptimport { ServicePrincipalCredentials, PDFServices } from '@adobe/pdfservices-node-sdk'; const credentials = new ServicePrincipalCredentials({ clientId: process.env.ADOBE_CLIENT_ID!, clientSecret: process.env.ADOBE_CLIENT_SECRET!, }); const pdfServices = new PDFServices({ credentials });
typescriptimport { FireflyClient } from '@adobe/firefly-apis'; const firefly = new FireflyClient({ clientId: process.env.ADOBE_CLIENT_ID!, accessToken: await getAdobeAccessToken(), });
pythonfrom adobe.pdfservices.operation.auth.service_principal_credentials import ServicePrincipalCredentials from adobe.pdfservices.operation.pdf_services import PDFServices credentials = ServicePrincipalCredentials( client_id=os.environ["ADOBE_CLIENT_ID"], client_secret=os.environ["ADOBE_CLIENT_SECRET"] ) pdf_services = PDFServices(credentials=credentials)
After successful auth, proceed to adobe-hello-world for your first API call.
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | 15,225 | 7,347 | -52% | 1 | 1 | 0% | 3,353 | 3,373 | +1% | 0 | 0 | — |
case-02 | fail→pass | 10,901 | 9,393 | -14% | 1 | 1 | 0% | 2,284 | 3,604 | +58% | 0 | 0 | — |
case-03 | fail→pass | 14,548 | 10,046 | -31% | 1 | 1 | 0% | 3,046 | 3,879 | +27% | 0 | 0 | — |
case-04 | pass→pass | 7,763 | 5,786 | -25% | 1 | 1 | 0% | 1,526 | 2,832 | +86% | 0 | 0 | — |
case-05 | fail→pass | 4,891 | 2,033 | -58% | 1 | 1 | 0% | 906 | 2,028 | +124% | 0 | 0 | — |
case-06 | pass→pass | 2,852 | 2,307 | -19% | 1 | 1 | 0% | 458 | 2,092 | +357% | 0 | 0 | — |
case-07 | fail→pass | 8,682 | 3,363 | -61% | 1 | 1 | 0% | 1,764 | 2,322 | +32% | 0 | 0 | — |
case-08 | pass→pass | 3,471 | 2,209 | -36% | 1 | 1 | 0% | 523 | 2,098 | +301% | 0 | 0 | — |
case-09 | pass→pass | 8,162 | 3,304 | -60% | 1 | 1 | 0% | 1,633 | 2,247 | +38% | 0 | 0 | — |
case-10 | pass→pass | 6,698 | 2,546 | -62% | 1 | 1 | 0% | 1,171 | 2,124 | +81% | 0 | 0 | — |
case-15 | pass→pass | 10,727 | 9,225 | -14% | 1 | 1 | 0% | 2,201 | 3,529 | +60% | 0 | 0 | — |
case-11 | pass→pass | 3,719 | 1,789 | -52% | 1 | 1 | 0% | 602 | 1,904 | +216% | 0 | 0 | — |
case-12 | pass→pass | 1,968 | 1,469 | -25% | 1 | 1 | 0% | 296 | 1,886 | +537% | 0 | 0 | — |
case-13 | fail→pass | 7,499 | 2,808 | -63% | 1 | 1 | 0% | 1,450 | 2,150 | +48% | 0 | 0 | — |
case-14 | pass→pass | 6,885 | 3,845 | -44% | 1 | 1 | 0% | 1,420 | 2,497 | +76% | 0 | 0 | — |
case-16 | fail→pass | 10,440 | 7,644 | -27% | 1 | 1 | 0% | 1,929 | 3,161 | +64% | 0 | 0 | — |
case-17 | fail→pass | 11,379 | 6,656 | -42% | 1 | 1 | 0% | 2,050 | 2,919 | +42% | 0 | 0 | — |
case-18 | pass→pass | 11,393 | 7,641 | -33% | 1 | 1 | 0% | 2,318 | 3,209 | +38% | 0 | 0 | — |
case-19 | fail→fail | 7,225 | 5,541 | -23% | 1 | 1 | 0% | 1,381 | 2,664 | +93% | 0 | 0 | — |
case-20 | fail→fail | 9,599 | 11,920 | +24% | 1 | 1 | 0% | 2,029 | 4,200 | +107% | 0 | 0 | — |
case-21 | pass→pass | 16,688 | 15,430 | -8% | 1 | 1 | 0% | 3,719 | 5,251 | +41% | 0 | 0 | — |
case-22 | pass→pass | 11,469 | 11,861 | +3% | 1 | 1 | 0% | 2,296 | 4,078 | +78% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +36 percentage points is the difference between those two pass rates over the 22 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.