Skip to main content
adobe-known-pitfalls Identify and avoid Adobe-specific anti-patterns: using deprecated JWT auth,
not caching IMS tokens, ignoring Firefly content policy, missing async job
polling, and leaking p8_ secrets. Real code examples with fixes.
Trigger with phrases like "adobe mistakes", "adobe anti-patterns",
"adobe pitfalls", "adobe what not to do", "adobe code review".
설치로 이동 Skills Marketplace 커뮤니티가 만든 AI 스킬을 발견하고 탐색하세요.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
직접 명령은 검토 Prompt를 거치지 않습니다. 실행하기 전에 소스를 확인하세요.
npx skills add https://github.com/jeremylongshore/claude-code-plugins-plus-skills --skill adobe-known-pitfalls명령은 한 줄로 유지됩니다. 복사하기 전에 가로로 스크롤해 전체 내용을 확인하세요.
로컬 사본을 원하시나요? SkillsMP에서 현재 제공할 수 있는 파일을 다운로드하세요.
Zip 다운로드 다운로드 중... 이 저장소의 다른 Skills Implement user sign-up and sign-in flows with Clerk.
Use when building authentication UI, customizing sign-in experience,
or implementing OAuth social login.
Trigger with phrases like "clerk sign-in", "clerk sign-up",
"clerk login flow", "clerk OAuth", "clerk social login".
Implement session management and middleware with Clerk.
Use when managing user sessions, configuring route protection,
or implementing token refresh and custom JWT templates.
Trigger with phrases like "clerk session", "clerk middleware",
"clerk route protection", "clerk token", "clerk JWT".
Configure enterprise SSO, role-based access control, and organization management.
Use when implementing SSO integration, configuring role-based permissions,
or setting up organization-level controls.
Trigger with phrases like "clerk SSO", "clerk RBAC",
"clerk enterprise", "clerk roles", "clerk permissions", "clerk organizations".
name adobe-known-pitfalls description Identify and avoid Adobe-specific anti-patterns: using deprecated JWT auth,
not caching IMS tokens, ignoring Firefly content policy, missing async job
polling, and leaking p8_ secrets. Real code examples with fixes.
Trigger with phrases like "adobe mistakes", "adobe anti-patterns",
"adobe pitfalls", "adobe what not to do", "adobe code review".
allowed-tools Read, Grep version 1.6.0 license MIT author Jeremy Longshore <jeremy@intentsolutions.io> tags ["saas","design","adobe"] compatibility Designed for Claude Code
Adobe Known Pitfalls
Overview
The 10 most common mistakes when integrating with Adobe APIs, based on real production issues. Each pitfall includes the anti-pattern, why it fails, and the correct approach.
Prerequisites
Access to your Adobe integration codebase
Understanding of Adobe API architecture (OAuth, async jobs, rate limits)
Instructions
Pitfall 1: Still Using JWT (Service Account) Credentials
Status: CRITICAL — JWT credentials reached End of Life June 2025.
import jwt from 'jsonwebtoken' ;
import fs from 'fs' ;
const privateKey = fs.readFileSync ('private.key' );
const jwtToken = jwt.sign ({
exp : Math .round (Date .now () / 1000 ) + 86400 ,
iss : orgId,
sub : technicalAccountId,
aud : `https://ims-na1.adobelogin.com/c/${clientId} ` ,
}, privateKey, { algorithm : 'RS256' });
const res = await fetch ('https://ims-na1.adobelogin.com/ims/token/v3' , {
method : 'POST' ,
headers : { 'Content-Type' : 'application/x-www-form-urlencoded' },
body : new URLSearchParams ({
: process. . !,
: process. . !,
: ,
: process. . !,
}),
});
client_id
env
ADOBE_CLIENT_ID
client_secret
env
ADOBE_CLIENT_SECRET
grant_type
'client_credentials'
scope
env
ADOBE_SCOPES
Pitfall 2: Not Caching IMS Access Tokens IMS tokens are valid for 24 hours. Generating a new token per request wastes 200-500ms:
async function callFirefly (prompt : string ) {
const tokenRes = await fetch ('https://ims-na1.adobelogin.com/ims/token/v3' , { ... });
const { access_token } = await tokenRes.json ();
}
let cached : { token : string ; expiresAt : number } | null = null ;
async function getToken ( ): Promise <string > {
if (cached && cached.expiresAt > Date .now () + 300_000 ) return cached.token ;
const res = await fetch ('https://ims-na1.adobelogin.com/ims/token/v3' , { ... });
const data = await res.json ();
cached = { token : data.access_token , expiresAt : Date .now () + data.expires_in * 1000 };
return cached.token ;
}
Pitfall 3: Using Firefly Sync Endpoint for Batch Operations
for (const prompt of prompts) {
const result = await fetch ('https://firefly-api.adobe.io/v3/images/generate' , {
method : 'POST' , ...
});
results.push (await result.json ());
}
const jobs = await Promise .all (
prompts.map (prompt =>
fetch ('https://firefly-api.adobe.io/v3/images/generate-async' , {
method : 'POST' , ...
}).then (r => r.json ())
)
);
const results = await Promise .all (jobs.map (j => pollJob (j.statusUrl )));
Pitfall 4: Ignoring Firefly Content Policy Errors
try {
const result = await generateImage ({ prompt : 'Photo of Nike shoes' });
} catch (e) {
console .log ('Generation failed' );
}
try {
const result = await generateImage ({ prompt });
} catch (e : any ) {
if (e.status === 400 && e.message ?.includes ('content policy' )) {
throw new Error (
'Firefly content policy violation. ' +
'Remove trademarks, real people, or explicit content from prompt.'
);
}
throw e;
}
Pitfall 5: Uploading Files Directly to Photoshop/Lightroom API
const formData = new FormData ();
formData.append ('image' , fs.readFileSync ('photo.jpg' ));
await fetch ('https://image.adobe.io/v2/remove-background' , {
method : 'POST' ,
body : formData,
});
const inputUrl = await s3.getSignedUrl ('getObject' , {
Bucket : 'my-bucket' , Key : 'photo.jpg' , Expires : 3600 ,
});
const outputUrl = await s3.getSignedUrl ('putObject' , {
Bucket : 'my-bucket' , Key : 'output.png' , Expires : 3600 ,
});
await fetch ('https://image.adobe.io/v2/remove-background' , {
method : 'POST' ,
headers : { Authorization : `Bearer ${token} ` , 'x-api-key' : clientId, 'Content-Type' : 'application/json' },
body : JSON .stringify ({
input : { href : inputUrl, storage : 'external' },
output : { href : outputUrl, storage : 'external' , type : 'image/png' },
}),
});
Pitfall 6: Not Polling Async Job Status Photoshop and Lightroom APIs return immediately with a job ID. You must poll for results:
const res = await fetch ('https://image.adobe.io/v2/remove-background' , { ... });
const result = await res.json ();
console .log ('Done!' , result);
const submission = await res.json ();
let job;
do {
await new Promise (r => setTimeout (r, 2000 ));
const pollRes = await fetch (submission._links .self .href , {
headers : { Authorization : `Bearer ${token} ` , 'x-api-key' : clientId },
});
job = await pollRes.json ();
} while (job.status !== 'succeeded' && job.status !== 'failed' );
if (job.status === 'failed' ) throw new Error (job.error ?.message );
Pitfall 7: Leaking Adobe Credentials in Source Code
const client_secret = 'p8_XYZ_your_actual_secret_here_do_not_do_this' ;
const client_secret = process.env .ADOBE_CLIENT_SECRET !;
Pitfall 8: Not Handling PDF Services Quota
async function extractAllPdfs (paths : string [] ) {
for (const path of paths) {
await extractPdf (path);
}
}
let txCount = 0 ;
async function trackedExtract (path : string ) {
if (txCount >= 490 ) {
throw new Error ('Approaching PDF Services monthly limit. 10 transactions remaining.' );
}
const result = await extractPdf (path);
txCount++;
return result;
}
Pitfall 9: Using Deprecated Photoshop Endpoints
await fetch ('https://image.adobe.io/sensei/cutout' , { ... });
await fetch ('https://image.adobe.io/v2/remove-background' , { ... });
Pitfall 10: Missing Webhook Signature Verification
app.post ('/webhooks/adobe' , (req, res ) => {
processEvent (req.body );
res.sendStatus (200 );
});
app.post ('/webhooks/adobe' , express.raw ({ type : 'application/json' }), async (req, res) => {
const sig = req.headers ['x-adobe-digital-signature-1' ];
const keyPath = req.headers ['x-adobe-public-key1-path' ];
const publicKey = await fetch (`https://static.adobeioevents.com${keyPath} ` ).then (r => r.text ());
const verifier = crypto.createVerify ('RSA-SHA256' );
verifier.update (req.body );
if (!verifier.verify (publicKey, sig, 'base64' )) {
return res.sendStatus (401 );
}
processEvent (JSON .parse (req.body .toString ()));
res.sendStatus (200 );
});
Quick Pitfall Scanner
echo "=== Adobe Pitfall Scan ==="
grep -rn "jsonwebtoken\|jwt\.sign\|RS256" --include="*.ts" --include="*.js" src/ && echo "FOUND: JWT auth (deprecated)" || echo "OK: No JWT"
grep -rn "ims/token/v3" --include="*.ts" src/ | wc -l | xargs -I{} echo "Token endpoint calls: {} (should be 1 — in auth.ts only)"
grep -rn "p8_" --include="*.ts" --include="*.js" src/ && echo "FOUND: Hardcoded Adobe secret" || echo "OK: No hardcoded secrets"
grep -rn "sensei/cutout" --include="*.ts" src/ && echo "FOUND: Deprecated Photoshop endpoint" || echo "OK: No deprecated endpoints"
grep -rn "webhooks/adobe" --include="*.ts" src/ | grep -v "digital-signature\|verify\|RSA" && echo "WARNING: Webhook handler may lack signature verification"
Quick Reference Card Pitfall Risk Detection Fix JWT auth Broken auth Grep for jwt.sign Migrate to OAuth S2S No token cache Perf (-500ms/req) Multiple ims/token calls Cache with expiry Sync Firefly for batch Slow (N*20s) Sequential generate calls Use async endpoint Ignore content policy Wasted credits Catch 400 without reason Pre-screen prompts Direct file upload 400 errors FormData to Photoshop Pre-signed URLs No job polling Missing results No poll loop after submit Poll _links.self Leaked p8_ secret Credential compromise Grep for p8_ Env vars + .gitignore No quota tracking Silent failures No counter Track per-month usage Old PS endpoint 404 errors /sensei/cutout/v2/remove-backgroundNo webhook verify Security hole No signature check RSA-SHA256 verification
Resources