/auth
Authenticate with AEM Edge Delivery Services. Opens browser for login and captures token. Works for admin.hlx.page and Config Service APIs regardless of content source (Document Authoring, SharePoint, or Google Drive).
$ npx -y skills add adobe/skills --skill auth --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/auth
Context preview
The summary Claude sees to decide when to auto-load this skill.
Authenticate with AEM Edge Delivery Services. Opens browser for login and captures token. Works for admin.hlx.page and Config Service APIs regardless of content source (Document Authoring, SharePoint, or Google Drive).
SKILL.md
auth.SKILL.mdname: auth
description: Authenticate with AEM Edge Delivery Services. Opens browser for login and captures token. Works for admin.hlx.page and Config Service APIs regardless of content source (Document Authoring, SharePoint, or Google Drive).
license: Apache-2.0
allowed-tools: Read, Write, Edit, Bash, AskUserQuestion
metadata:
version: "2.0.0"
AEM Edge Delivery Services Authentication
Authenticate to obtain a token for all Edge Delivery Services admin operations. Auto-detects identity provider from org+site — no content source question needed. Opens the user's default browser for login and receives the token via a local callback server.
Token Usage
The `authToken` works for admin APIs:
| API | Header | Usage | |-----|--------|-------| | `admin.hlx.page` | `x-auth-token: ${AUTH_TOKEN}` | Preview, publish, status, code sync, jobs, logs, config | | Config Service | `x-auth-token: ${AUTH_TOKEN}` | Sites, config, secrets, API keys, profiles |
> **Note:** `admin.da.live` uses a separate Adobe IMS token with `Authorization: Bearer` header. See the DA-specific login flow in `ops/resources/da.md`.
When to Use This Skill
- API returns 401 Unauthorized
- User says "login", "authenticate", "auth"
- Before any admin operation when token is missing/expired
- Before generating guides that need API access
Prerequisites
- Node.js installed
---
Authentication Flow
Step 1: Check Existing Token
Tokens are cached at the **user level** (`~/.aem/ims-token.json`), shared across all projects.
mkdir -p "${HOME}/.aem"
AUTH_TOKEN=$(node -e "
const fs = require('fs');
try {
const t = JSON.parse(fs.readFileSync(process.env.HOME + '/.aem/ims-token.json', 'utf8'));
if (t.authToken && t.authTokenExpiry > Math.floor(Date.now()/1000) + 60) {
process.stdout.write(t.authToken);
}
} catch (e) {}
")
if [ -n "$AUTH_TOKEN" ]; then
echo "Token valid"
exit 0
fi
echo "Token missing or expired. Starting login..."Step 2: Resolve Org and Site
The auto-login endpoint `/login/{org}/{site}/main` redirects to the correct identity provider automatically — no need to know the content source.
**Resolve org and site from available sources (project-config, ops-config, git remote):**
# Try project-config first (handover context)
ORG=$(cat .claude-plugin/project-config.json 2>/dev/null | node -e "
const d = require('fs').readFileSync(0,'utf8');
try { process.stdout.write(JSON.parse(d).org || ''); } catch(e) {}
")
# Fallback to ops-config (ops context)
if [ -z "$ORG" ]; then
ORG=$(node -e "
const fs = require('fs');
try {
const c = JSON.parse(fs.readFileSync(process.env.HOME + '/.aem/ops-config.json', 'utf8'));
process.stdout.write(c.org || '');
} catch(e) {}
")
fi
# Site: try git remote first, then ops-config
SITE=$(basename -s .git $(git remote get-url origin 2>/dev/null) 2>/dev/null)
if [ -z "$SITE" ]; then
SITE=$(node -e "
const fs = require('fs');
try {
const c = JSON.parse(fs.readFileSync(process.env.HOME + '/.aem/ops-config.json', 'utf8'));
process.stdout.write(c.site || '');
} catch(e) {}
")
fi
echo "org=${ORG:-NOT SET} site=${SITE:-NOT SET}"**If `ORG` is empty**, ask the user:
> "I need your organization name to authenticate. You can provide either: > - The org name (the `{org}` in `https://main--site--{org}.aem.page`) > - A preview/live URL like `https://main--mysite--myorg.aem.page/`"
**If user provides a URL**, parse org and site from it:
URL="$USER_INPUT"
if echo "$URL" | grep -q '\.aem\.page\|\.aem\.live'; then
HOST_PART=$(echo "$URL" | cut -d'/' -f3 | cut -d'.' -f1)
ORG=$(echo "$HOST_PART" | awk -F'--' '{print $NF}')
SITE=$(echo "$HOST_PART" | awk -F'--' '{print $(NF-1)}')
echo "Parsed from URL: org=$ORG site=$SITE"
fi**If `SITE` is still empty** (not in a git repo and no URL provided), ask the user:
> "I also need a site name to auto-detect your login provider. What is your site name? (the `{site}` part of `https://main--{site}--{org}.aem.page`)"
**Do NOT proceed until both org and site are available.**
Step 3: Capture Token via Loopback Redirect
Opens the user's default browser for login. A temporary local HTTP server receives the token callback after login completes. The user must click "Send" on the confirmation page to deliver the token. Works with all identity providers (Adobe IMS, Google, Microsoft).
**User-facing message (display BEFORE running the script below):**
> **Browser opened for login to `{org}/{site}`. Click "Send" after authenticating — you can close the tab once done.**
Use bold/highlighted formatting so the instruction stands out clearly.
mkdir -p "${HOME}/.aem"
node -e "
const http = require('http');
const { execSync } = require('child_process');
const fs = require('fs');
const path = require('path');
const crypto = require('crypto');
const TOKEN_PATH = path.join(process.env.HOME, '.aem', 'ims-token.json');
const ORG = '${ORG}';
const SITE = '${SITE}';
const STATE = crypto.randomUUID();
const server = http.createServer((req, res) => {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'POST, GET, OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
if (req.method === 'OPTIONS') {
res.writeHead(204);
res.end();
return;
}
if (req.method === 'POST') {
let body = '';
req.on('data', (chunk) => { body += chunk; });
req.on('end', () => {
try {
const parsed = JSON.parse(body);
if (parsed.state !== STATE) {
console.error('State mismatch — ignoring callback');
res.writeHead(403);
res.end('State mismatch');
return;
}
const authToken = parsed.authToken;
if (authToken) {
const expiresAt = Math.floor(Date.now() / 1000) + 86400;
fs.writeFileSync(TOKEN_PATH, JSON.stringify({
authToken,Read more
name: auth description: Authenticate with AEM Edge Delivery Services. Opens browser for login and captures token. Works for admin.hlx.page and Config Service APIs regardless of content source (Document Authoring, SharePoint, or Google Drive). license: Apache-2.0 allowed-tools: Read, Write, Edit, Bash, AskUserQuestion metadata: version: "2.0.0"
AEM Edge Delivery Services Authentication
Authenticate to obtain a token for all Edge Delivery Services admin operations. Auto-detects identity provider from org+site — no content source question needed. Opens the user's default browser for login and receives the token via a local callback server.
Token Usage
The `authToken` works for admin APIs:
| API | Header | Usage | |-----|--------|-------| | `admin.hlx.page` | `x-auth-token: ${AUTH_TOKEN}` | Preview, publish, status, code sync, jobs, logs, config | | Config Service | `x-auth-token: ${AUTH_TOKEN}` | Sites, config, secrets, API keys, profiles |
> **Note:** `admin.da.live` uses a separate Adobe IMS token with `Authorization: Bearer` header. See the DA-specific login flow in `ops/resources/da.md`.
When to Use This Skill
- API returns 401 Unauthorized
- User says "login", "authenticate", "auth"
- Before any admin operation when token is missing/expired
- Before generating guides that need API access
Prerequisites
- Node.js installed
---
Authentication Flow
Step 1: Check Existing Token
Tokens are cached at the **user level** (`~/.aem/ims-token.json`), shared across all projects.
mkdir -p "${HOME}/.aem"
AUTH_TOKEN=$(node -e "
const fs = require('fs');
try {
const t = JSON.parse(fs.readFileSync(process.env.HOME + '/.aem/ims-token.json', 'utf8'));
if (t.authToken && t.authTokenExpiry > Math.floor(Date.now()/1000) + 60) {
process.stdout.write(t.authToken);
}
} catch (e) {}
")
if [ -n "$AUTH_TOKEN" ]; then
echo "Token valid"
exit 0
fi
echo "Token missing or expired. Starting login..."Step 2: Resolve Org and Site
The auto-login endpoint `/login/{org}/{site}/main` redirects to the correct identity provider automatically — no need to know the content source.
**Resolve org and site from available sources (project-config, ops-config, git remote):**
# Try project-config first (handover context)
ORG=$(cat .claude-plugin/project-config.json 2>/dev/null | node -e "
const d = require('fs').readFileSync(0,'utf8');
try { process.stdout.write(JSON.parse(d).org || ''); } catch(e) {}
")
# Fallback to ops-config (ops context)
if [ -z "$ORG" ]; then
ORG=$(node -e "
const fs = require('fs');
try {
const c = JSON.parse(fs.readFileSync(process.env.HOME + '/.aem/ops-config.json', 'utf8'));
process.stdout.write(c.org || '');
} catch(e) {}
")
fi
# Site: try git remote first, then ops-config
SITE=$(basename -s .git $(git remote get-url origin 2>/dev/null) 2>/dev/null)
if [ -z "$SITE" ]; then
SITE=$(node -e "
const fs = require('fs');
try {
const c = JSON.parse(fs.readFileSync(process.env.HOME + '/.aem/ops-config.json', 'utf8'));
process.stdout.write(c.site || '');
} catch(e) {}
")
fi
echo "org=${ORG:-NOT SET} site=${SITE:-NOT SET}"**If `ORG` is empty**, ask the user:
> "I need your organization name to authenticate. You can provide either: > - The org name (the `{org}` in `https://main--site--{org}.aem.page`) > - A preview/live URL like `https://main--mysite--myorg.aem.page/`"
**If user provides a URL**, parse org and site from it:
URL="$USER_INPUT"
if echo "$URL" | grep -q '\.aem\.page\|\.aem\.live'; then
HOST_PART=$(echo "$URL" | cut -d'/' -f3 | cut -d'.' -f1)
ORG=$(echo "$HOST_PART" | awk -F'--' '{print $NF}')
SITE=$(echo "$HOST_PART" | awk -F'--' '{print $(NF-1)}')
echo "Parsed from URL: org=$ORG site=$SITE"
fi**If `SITE` is still empty** (not in a git repo and no URL provided), ask the user:
> "I also need a site name to auto-detect your login provider. What is your site name? (the `{site}` part of `https://main--{site}--{org}.aem.page`)"
**Do NOT proceed until both org and site are available.**
Step 3: Capture Token via Loopback Redirect
Opens the user's default browser for login. A temporary local HTTP server receives the token callback after login completes. The user must click "Send" on the confirmation page to deliver the token. Works with all identity providers (Adobe IMS, Google, Microsoft).
**User-facing message (display BEFORE running the script below):**
> **Browser opened for login to `{org}/{site}`. Click "Send" after authenticating — you can close the tab once done.**
Use bold/highlighted formatting so the instruction stands out clearly.
mkdir -p "${HOME}/.aem"
node -e "
const http = require('http');
const { execSync } = require('child_process');
const fs = require('fs');
const path = require('path');
const crypto = require('crypto');
const TOKEN_PATH = path.join(process.env.HOME, '.aem', 'ims-token.json');
const ORG = '${ORG}';
const SITE = '${SITE}';
const STATE = crypto.randomUUID();
const server = http.createServer((req, res) => {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'POST, GET, OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
if (req.method === 'OPTIONS') {
res.writeHead(204);
res.end();
return;
}
if (req.method === 'POST') {
let body = '';
req.on('data', (chunk) => { body += chunk; });
req.on('end', () => {
try {
const parsed = JSON.parse(body);
if (parsed.state !== STATE) {
console.error('State mismatch — ignoring callback');
res.writeHead(403);
res.end('State mismatch');
return;
}
const authToken = parsed.authToken;
if (authToken) {
const expiresAt = Math.floor(Date.now() / 1000) + 86400;
fs.writeFileSync(TOKEN_PATH, JSON.stringify({
authToken,Repo: adobe/skills
Other skills on adobe-skills.
- /aa-conversion-funnel-analysis
Analyzes a multi-step conversion funnel to find where visitors drop off and which steps have the worst leakage. Use this skill when someone describes a journey and asks about conversion rates, drop-off, fallout, or step completion. Trigger for "analyze our checkout funnel,"
Open skill - /aa-executive-briefing
Generates a concise, executive-ready performance summary covering key metrics, trends, and what's driving movement. Use this skill when someone needs to produce a briefing, executive summary, performance narrative, or stakeholder readout — for example, "write an exec summary of
Open skill - /aa-kpi-pulse
Produces a compact KPI digest showing how key metrics changed over a period and what's driving the movement. Use this skill when someone asks for a performance summary, a weekly recap, a morning briefing, a KPI update, or any variation of "how did we do this week/month." Also
Open skill - /aa-segment-performance-comparator
Compares the performance of two or more audience segments across key metrics side by side. Use this skill when someone wants to compare audiences or visitor groups — for example, "how do mobile visitors compare to desktop on conversion," "compare new vs. returning visitors,"
Open skill - /aa-top-movers-watchlist
Identifies which items (pages, campaigns, products, channels, regions) had the biggest increases or decreases for a key metric between two time periods. Use this skill when someone asks "what's up and what's down," "which campaigns moved the most," "top gainers and losers,"
Open skill - /cja-dimension-analysis
Comprehensive dimension analysis and reporting for CJA. Use this skill whenever the user wants to analyze one or more dimensions — including cardinality, distribution/skew, trends, anomalies, data quality errors, comparisons, and forecasting. Also trigger when someone asks "what
Open skill

