* feat(auth0): add Vercel integration reference
* chore(auth0): drop first-party URL ignores now split into #173
The auth0.com/pricing.md, auth0-oidc-client-net, and auth0-java-mvc-common
W012 ignore entries are unrelated to the Vercel integration and are being
added separately in #173. Remove them here to keep this PR scoped to Vercel.
* fix: address PR review comments
* fix: address PR review comments
---------
Co-authored-by: Sanchit Mehta <sanchit.mehta@okta.com>
* feat(auth0): add Universal Portals guidance
* fix(auth0): preserve router activation cues
* fix(auth0): keep router within context budget
* fix(auth0): simplify design inputs checklist in Universal Portals
Collapsed items 2–4 into two items: removed the separate portal type
entry and merged component selection with its guidance, renumbering
the remaining items.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
* fix(auth0): fix markdown formatting in Universal Portals router block
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
* fix(auth0): remove /api/v2/ prefix from auth0 api CLI commands
auth0 api resolves against the Management API base automatically;
only the path after /api/v2/ is needed.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
* fix: address PR review comments
- Resolve description conflict against main: keep main's crisp phrasing, add Universal Portals mention only
- Revert unintended Step 2/3 copy-edits to match main
- Fix stale /api/v2/ prefix in Universal Portals workflow table
* fix(auth0): keep SKILL.md router under context budget
The Universal Portals intent row + Step 4 block pushed SKILL.md to 4,105
tokens, over skillsaw's 4,100 warn limit. Trim the new block to match sibling
blocks (drop the redundant beta line, already stated in the reference), tighten
the intent row, and compress duplicated first-match/Ionic/PHP notes elsewhere in
Step 2. Now 4,100, skillsaw clean.
---------
Co-authored-by: Jacobo Vidal <jacobo.vidal@okta.com>
Co-authored-by: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Sanchit Mehta <sanchit.mehta@okta.com>
* feat: package Auth0 skill for Codex plugins
* fix: use Auth0 marketplace display name
* docs: address review feedback on the Codex packaging
The Codex manifest carried a generic one-liner while the Claude and Cursor
manifests list the frameworks and features, so directory search for "Next.js"
or "MFA" would not have matched this listing. Reuse the marketplace copy for
both `description` and `interface.longDescription`.
Also drop the "Method N" numbering now that there are four install paths and
the newest one sat above the recommended path, sort `.agents/` into the
directory tree, and list both docs/ files in the tree and in AGENTS.md.
* docs: describe the Codex marketplace as tracking main, not local
The marketplace entry resolves plugins/auth0 from the published main branch, so
calling it "local testing" was wrong — an uncommitted working tree is not what
gets installed. Reword the four places that claimed it and note that changes
need pushing before reinstalling.
---------
Co-authored-by: Subhankar Maiti <35273200+subhankarmaiti@users.noreply.github.com>
Co-authored-by: Subhankar Maiti <subhankar.maiti@okta.com>
* test(evals): add skill-activation eval layer for the SKILL.md description
The `description` frontmatter is the only signal an agent uses to decide
whether to load this skill, and no existing eval layer reads it:
- scripts/check_routing_evals.py parses the SKILL.md *body* (Step 4 table)
- evals/behavioral/ loads the plugin via --plugin-dir and grades the code
produced *after* the skill is already in play
So a description edit could destroy discoverability with every other check
green. This adds evals/activation/ to close that gap.
Two stages, both manual-run (they need a live model, like behavioral/):
Stage A (default) renders a realistic skill menu — auth0 plus seven
distractor skills, name + description only — and asks which skills would
be invoked. Cheap, and the description is the only variable between runs.
The distractors matter: asking "would you invoke auth0?" in isolation
primes YES and makes negative cases meaningless. Several distractors are
auth-adjacent (kubernetes-ops, api-hardening, aws-infra) so the near-miss
negatives have a correct home to go to.
Stage B (--real) is ground truth: two temp plugin copies differing only in
the description line, run under --plugin-dir with stream-json, detecting an
actual Skill(auth0) tool call in the event stream rather than prose about
using it.
Variants resolve as `git:<ref>` or a path, so any future description edit is
testable against the same matrix with no new fixtures. Majority vote over
--trials (default 3); cases whose trials disagree report UNSTABLE rather than
being silently rounded.
The 35 cases are built to attack generalized phrasing: keyword-loss prompts,
framework-only prompts, indirect prompts naming no product or feature, and
negatives — including near-misses that deliberately reuse auth vocabulary
(Kubernetes RBAC, application-level 429s, CORS headers on Express, rotating
AWS IAM keys, express-session to Redis). Without those, a description reading
"use this always" scores 100% recall and the suite proves nothing.
README.md records the calibration honestly, including a measured limitation:
Stage A's recall axis catches an under-triggering description (a deliberately
narrow control scored 0/26) but its precision axis is insensitive (a
deliberately broad control still produced 0/9 false positives). A green Stage
A run is therefore evidence against under-triggering only.
* fix(auth0): simplify the skill description and cut keyword lists
The description had grown to 754 characters, most of it literal enumeration:
every supported framework, every named competitor, and a list of specific
error conditions (401, CORS error, callback URL mismatch, 429 rate limit).
AGENTS.md warns against exactly this — keyword dumps instead of user intent.
Replace the enumerations with the intent they were standing in for, keep
Auth0 named explicitly, and add the configuration axis the old wording
missed ("using or configuring any Auth0 feature") with a short representative
sample rather than an exhaustive list. 754 -> 503 characters.
Measured with the new evals/activation/ layer over 35 cases, comparing this
wording against the previous one:
Stage A (classifier, 3 trials): 26/26 recall and 0/9 false positives for
both variants — no regression, but a tie at ceiling, so uninformative on
its own. See the calibration section in evals/activation/README.md.
Stage B (real --plugin-dir activation, 3 trials) is where the difference
showed. The new wording was never worse on any trial, and fixed a real
over-trigger:
kw-passkeys activate old 0/3 new 1/3
indirect-node-api activate old 0/3 new 2/3
neg-cors-headers DON'T old 2/3 new 0/3
The old description fired on a plain "add CORS headers to my Express
server" request two times out of three, because it listed `CORS error` and
`Express` as literal triggers — the keyword-matching failure mode, caught
in the act.
Separately worth noting: real-path recall is low for *both* descriptions
(0-2 of 3 trials). The agent often answers an auth question without loading
the skill at all. That predates this change and is tracked as its own
discoverability problem, not addressed here.
The framework and competitor lists remain in .claude-plugin/marketplace.json
and .cursor-plugin/marketplace.json, where they serve marketplace keyword
search; only the agent-facing activation signal changed.
* refactor(auth0): simplify skill description
Drop inferable keyword lists (framework names, migration sources, error
codes) that the model already generalizes from generic auth phrasing and
that measurably cause over-triggering. Keep the tenant audit/health/plan-fit
(CheckMate) capability as a concept, since it can't be inferred. 956 -> 563
chars, still under the 1024 limit.
* fix(activation-evals): run Stage B over --trials and validate the flag
Stage B previously invoked each variant exactly once, ignoring --trials, so a
REGRESSED/IMPROVED verdict on the only discriminating layer could hinge on one
nondeterministic agent run. Wrap it in realActivationWithTrials with the same
majority-vote + UNSTABLE semantics as classifyWithTrials. Also reject
non-integer or <1 --trials up front, instead of silently running zero/garbage
trials. Addresses CodeRabbit review on PR #166.
---------
Co-authored-by: Sanchit Mehta <sanchit.mehta@okta.com>
* fix(auth0): stop teaching hardcoded credentials in the Expo skill
The Expo reference put domain/clientId literals directly into Auth0Provider
props at seven sites, so agents following it wrote the client ID into App.tsx.
Switch them to EXPO_PUBLIC_* process.env reads and add a .env step, matching
what the React Native reference already does. The app.json plugin keeps literal
values — the domain isn't a secret and the plugin is read at prebuild time.
Also make build verification proportionate. Expo prescribed a prebuild plus
run:ios/run:android with a 5-6 iteration fix loop; that's minutes of work and a
toolchain the environment may not have. Prefer a typecheck and escalate only
when asked. Android and Swift keep their builds but now skip them when no
toolchain is present.
Adds a "Files to Change" table and marks the useAuth0 surface authoritative for
both mobile references, so agents stop reading node_modules to confirm the API.
* fix(auth0): forbid literal credential fallbacks in mobile skills
An eval run showed agents writing process.env.X ?? 'real-client-id' into a
config module, which puts the credential straight back into source and fails a
secret-in-source check. The Expo reference still demonstrated that pattern in
its app.config.js example, so spell out the rule at both the .env step and the
secret-management section, and say the fallback form is the thing to avoid.
Also document how the iOS/Android callback scheme is derived from the bundle
id. Agents were reading the SDK's Swift, Kotlin and TypeScript internals to
reconstruct it — around 18 tool calls per run spent inside node_modules.
* fix(auth0): correct the Android auth0Scheme in the React Native skill
The skill told agents to set auth0Scheme to a bare ${applicationId}. The SDK
appends its own suffix (APPLICATION_ID_SUFFIX = '.auth0'), so the scheme must be
${applicationId}.auth0 — with the bare form the redirect never resolves. Fixed
in the manifestPlaceholders block, the manual RedirectActivity fallback, the
Setup Guide, and the callback-URL derivation table.
The Setup Guide also only documented the manual AndroidManifest edit; it now
leads with manifestPlaceholders to match the Quick Start.
* fix(auth0): address review feedback on the mobile skills
- Skip the Android build only when none of ANDROID_HOME, ANDROID_SDK_ROOT or an
sdk.dir entry in local.properties is present. Checking ANDROID_HOME alone
could skip a usable Gradle build.
- Pick the iOS simulator from `xcrun simctl list devices available` instead of
assuming an iPhone 16 is installed, and pass OS=latest.
- Commit to react-native-dotenv as the documented loader, since every example
reads process.env. react-native-config exposes values on a Config object, so
the previous "either loader" wording described code that would not work.
- Say plainly that `!` is erased at compile time and checks nothing at runtime;
show an explicit throw for callers who want to fail fast.
- Soften "Files to Change" to a starting scope. The paths are not universal —
expo-router roots the provider in app/_layout.tsx and the iOS target
directory name varies — so agents must confirm the entry point before editing.
- Split verification into source and native configuration. A typecheck proves
nothing about plugin application, manifest placeholders or URL schemes, so
list the native values to read back and keep only the device run optional.
Also adds the blank blockquote lines MD031 wants around the fences in the
verification blocks these changes touch.
* revert(auth0): leave the Android and Swift references unchanged
Both files are back to their state on main. The build-verification tweaks there
were incidental to this PR, which is about the Expo and React Native mobile
skills — keeping them out limits the review surface to the frameworks the
mobile quickstart evals actually exercise.
* feat(auth0): fold plan-aware health check into the unified skill
Add a 'healthcheck' intent to the unified auth0 router that assesses an
Auth0 tenant across all plans (Free/Essentials/Professional/Enterprise),
emits two scores (security & config hygiene + capability fit), and
recommends a self-service plan or an 'Enterprise - contact sales' path.
- SKILL.md: Step 1 intent row + Step 4 load block; extend the description.
- references/feature-healthcheck.md: use-case detection, two-score model,
feature-unlock matrix, plan-matching + Enterprise gate, MAU forecast,
Talk-to-Sales brief. Reuses the co-loaded audit workflow, pricing, and
remediation references (the audit runs first to supply findings/context).
- assets/healthcheck/report-template.{md,html}.
- Routing eval (healthcheck-all-plans) + README coverage.
Stacked on the audit intent.
* fix(auth0): restore fix-dependency/prerequisite ordering in remediation reference
feature-healthcheck.md points to the co-loaded remediation reference for
fix-dependency ordering, but that section was dropped in the fold from the
standalone healthcheck skill (old remediation-command-map.md). Restore it:
SMTP-before-Email-MFA, DNS-before-custom-domain, deliverable-factor-before-
MFA-enforce, and connection-before-SSO. Benefits the audit apply loop too.
* chore(auth0): keep skillsaw 0.16.0 green for the new audit/healthcheck intents
The 0.16.0 linter (pulled in from main, #139) adds two rules the folded
intents trip:
- context-budget: two new intents (table row + Step 4 loader each) push the
router body ~50 tokens over the 4000 warn limit. Trimmed the new intent rows
and description, and raised the body warn limit to 4100 (error ceiling still
6000) — routers grow as intents are added.
- content-critical-position: feature-audit.md / feature-healthcheck.md use
CRITICAL/REQUIRED/MUST as literal feature-gap severity values in scoring
tables, which the heuristic misreads as stranded mid-file instructions.
Excluded ONLY those two files; the rule stays active (warning) everywhere else.
* test(auth0): port healthcheck behavioral eval into consolidated harness
Restores the behavioral coverage that shipped with the standalone
auth0-healthcheck-all-plans skill (#127) as evals/behavioral/cases/healthcheck.json,
matching the repo-root consolidated harness. Expectations-only, like the other
interactive-flow cases (branding, cli, acul).
* test(auth0): point healthcheck skill_name at the unified skill
skill_name is the skill under test, which is now auth0 — the standalone
auth0-healthcheck-all-plans skill no longer exists. origin_skill keeps the
pre-migration name so run-evals.mjs can still print "was <origin_skill>",
matching every other case file.
Extend the no-machine-graders note to cover healthcheck (same out-of-workspace
artifact problem as audit) and refresh the case counts (18 -> 19, 5 -> 6).
* refactor(auth0): take health-check prices from the live pricing page
Follows the pricing reference no longer vendoring dollar amounts. The health
check is the workflow that actually quotes prices (the audit emits plan name
only), so it needs the live source wired through:
- Source-of-truth rules and the reference header now split feature availability
(co-loaded reference) from prices (fetched from auth0.com/pricing.md), instead
of pointing both at a file that no longer holds figures.
- Pricing-data-consistency rule now fetches once and reads every figure from
that single response, with an explicit "don't mix figures across fetches or
interpolate between MAU tiers" constraint. A4AA cost is cross-checked against
the fetched A4AA table rather than trusting the x1.5 arithmetic alone.
- Removed the two hardcoded worked examples ($300 base + $150 A4AA = $450 at 1k
MAU, and the same figures in the plan-recommendation JSON sample). Those were
the exact numbers most likely to be quoted verbatim once stale; the JSON
sample now shows <base>/<a4aa>/<total> placeholders.
- The M2M threshold no longer hardcodes "exceeds 5,000" — the included allowance
is itself a published number, so read it from the fetched table.
Also update the healthcheck eval: assert the agent fetches pricing.md and that
the cost comes from the fetched page, not "from the pricing reference".
* docs(auth0): defer to the pricing reference instead of restating its rules
Health-check side of the price-fetch change. Every remaining "from the pricing
reference" that referred to a figure now points at the fetched pricing page:
the self-service exact-cost recommendation, the A4AA 50% note, the feature
comparison preamble, the per-plan tables pointer, and the closing pitfall.
Feature availability, MAU limits, the feature->plan matrix, and plan/feature
naming still come from the co-loaded reference — those never moved.
Also drop the duplicated fetch/anti-memory wording from the source-of-truth
block and defer to the pricing reference's own quoting procedure and
fetch-failure rule. Restating a co-loaded reference's contract here is exactly
the drift the one-hop model avoids: one rule, one home.
* fix(auth0): restore three rules lost when folding the healthcheck references
Three narrow fixes from CodeRabbit's review of this PR. Each restores a
rule that #127 had, or tightens text this PR itself introduced -- none
change ported content.
MAU growth-rate unit. The formula reads `(1 + growth_rate)` while the
input spec says "15 means 15%/month". #127's mau-forecast-calculator.md
carried a `Where:` block defining growth_rate as a decimal (0.15 for
15%); collapsing ten files into one dropped it. An agent passing the
collected 15 straight into the formula forecasts 16x monthly growth
instead of 1.15x, which misreads the urgency band and can recommend an
upgrade the tenant does not need. Restored on the formula line.
No-scan hygiene path. The router's healthcheck block made the audit an
unconditional prerequisite, which reads as "stop if the scan cannot
run". Both the reference (feature-healthcheck.md) and #127 instead mark
hygiene "Not scored" and continue scoring capability fit. This router
line is new in this PR, not ported, so the fix tightens our own text.
pending_enterprise had no consumer. feature-healthcheck.md queues
plan-gated items as `pending_enterprise` when the recommendation is
"Enterprise -- contact sales", but the remediation gate only handled
`pending_upgrade` and `skipped` -- so it would ask whether the customer
had upgraded to a plan that has no self-service upgrade, and offer the
billing link for something sales has to quote. #127 had the same gap.
The gate now suppresses that question on the Enterprise path, defines
resume behavior, and states that a pending_enterprise item is never
presented as self-unlockable.
Five further issues CodeRabbit raised are real but inherited from #127
verbatim, and resolving them requires decisions #127 never wrote down
(e.g. ai_use_case is a boolean compared against "AI-Native", but #127
emits the combined string "AI-NATIVE OR AI-DIFFERENTIATED" and never
says how to choose). Those are left for the original authors rather than
re-authored here.
* style(auth0): satisfy markdownlint in the files this PR adds
feature-healthcheck.md and the healthcheck report template are new files,
so their markdownlint violations are new code rather than inherited
style. Add the blank lines MD022/MD031 want around headings and fences,
and a `text` language tag on the four bare fences MD040 flags -- the two
score formulas, the Talk-to-Sales template, and the report filename.
Whitespace and fence tags only: normalising `text` back to a bare fence
and dropping blank lines makes the file byte-identical to its previous
content, and the fence count is unchanged at 20.
SKILL.md is deliberately left alone. It has 45 violations of these rules
and 42 are already on main -- all 28 intent blocks use the same
unlanguaged-fence style, 27 of them pre-existing. Styling only the
healthcheck block would make it the odd one out, and the repo has no
markdownlint config or CI gate to align to yet.
* fix(auth0): separate growth-rate units and soften the audit prerequisite
Both of these are follow-ups on wording this PR introduced, flagged in a
second review pass.
The growth-rate note said to use the decimal "everywhere", which
overreaches: the Talk-to-Sales brief renders {{monthly_growth_rate}}%/mo
and four plan-matching branches threshold on `monthly_growth > 20%`, so
"everywhere" would print 15% as 0.15%/mo and stop those comparisons
matching. Name the conversion explicitly and keep the two units apart --
the decimal for the forecast arithmetic, the percentage for thresholds
and display.
The router's healthcheck line still opened with an unconditional "Run the
audit workflow first", which reads as a hard prerequisite even with the
no-scan clause appended. Make the condition the first thing stated, and
say plainly that capability fit, plan matching and the recommendation
still run when no scan is available.
* fix(auth0): make the health-check field names refer to fields that exist
Two field-name mismatches carried over from #127, both of which make a
condition read something nothing ever sets. Renames only -- no threshold,
formula or branch changes.
Plan matching gated on `readiness_score`, but the workflow produces
`fit_score`. These are the same metric: #127's use-case-detection-logic.md
pairs "readiness_score": 0.35 with "readiness_level": "Not Ready", and
"Not Ready" is the 0-39 band that scoring-model.md defines for fit_score.
So the mapping is grounded rather than guessed -- readiness_score was
fit_score on a 0-1 scale. Renamed to fit_score, with the thresholds moved
onto the 0-100 scale the bands already use (> 80% -> > 80), and the sample
output's paired key renamed to fit_level for consistency.
Four branches also read `monthly_growth` where the normalized fact set
defines `monthly_growth_rate`; both are the percentage, so this is the
name only.
The AI branches read `integrations.length` while the detection output
emits `ai_integrations` -- six sites, now all `ai_integrations`. Left
alone: the neighbouring `ai_use_case == "AI-Native"` comparison against a
boolean, which needs a discriminator #127 never defined.
* fix(auth0): stop routing a Custom Domain gap to a plan upgrade
Custom Domains is a Free-tier feature — the pricing page reads
`| Custom Domains* | 1 | Included | Included | Included |`, and the only
footnote is credit-card verification, not a plan gate. Neither #127 nor the
live pricing page mentions the separate "Multiple Custom Domains" concept, so
every reference here is to plain Custom Domains.
feature-audit.md already states this rule, and it is co-loaded with this file
on the healthcheck intent:
Common misconception to avoid: Custom Domains is NOT an upgrade feature —
the Free plan includes 1 custom domain (credit-card verification
required). Never place it under "After Upgrading."
The health-check logic contradicted it in four places:
- the CRITICAL-gap → minimum-unlocking-plan mapping sent Custom Domain to
"Essentials+", pushing a same-day fix into Loop B behind the upgrade gate
- both Free-plan branches listed Custom Domain as both an upgrade trigger and
an unlock, so a Free tenant was told to pay for what they already have
- the default branch's unlock list repeated it
- the feature_unlocks JSON example used it as the CRITICAL specimen
The unlock lists inherit from plan-matching-logic.md, whose flat prose lost the
`=` (already included) vs `✓` (newly unlocked) distinction that
feature-unlock-matrix.md uses to mark Custom Domain correctly.
CRITICAL severity for a missing custom domain is unchanged — scoring-model.md
is explicit that a missing required feature deducts "whether it's a free
toggle, a paid unlock, or Enterprise-only." Only the remediation route was
wrong.
* fix(auth0): pick the plan track from the business model, not the use case
The Free-plan AI and compliance branches hardcoded a B2B recommendation
regardless of the business model Phase 2 detected, so a B2C tenant with agent
integrations — or a B2C fintech — was routed onto the B2B track.
Nothing those branches offer requires B2B. The AI rows are byte-identical
across both tracks in the pricing reference:
CIBA | Not available | ADD-ON | ADD-ON | Included + ADD-ON
Token Vault | 2 | 3 + ADD-ON | 3 + ADD-ON | 4 + ADD-ON
M2M Auth | 1,000 | 1,000 | 5,000 | 5,000
as are Log Streaming and Pro MFA Factors. The B2B track is not equivalent,
though — at 500 MAU it costs $150/$800 against B2C's $35/$240 (3-4x), and its
published MAU ceiling is *lower* (B2B Professional stops at 10,000; B2C
Essentials is priced to 50,000). So the wrong track over-quotes the customer
for capability it already had and shrinks its growth headroom, eventually
manufacturing an Enterprise conversation the self-service path exists to avoid.
Changes:
- introduce `<track>` (B2B when business_model == "B2B", else B2C) and use it
in the three Free-plan branches and the shared A4AA detection logic, with the
reasoning stated so it isn't re-hardcoded later
- gate M2M Access for Organizations on the B2B track — it is the one genuine
B2B-only feature the autonomous-actions branch listed
- add the missing A4AA branches to B2C Essentials and B2C Professional. #127
had AI branches only under the B2B blocks, so a B2C tenant with agent
integrations was never offered A4AA at all
- note that Breached Password Detection is Professional+ on *both* tracks, so
the compliance branch's Essentials recommendation cannot deliver the feature
its own rationale cites
Whether a regulated vertical genuinely requires BPD (recommend Professional) or
not (drop it from the rationale) is left to the authors; the text now states the
constraint either way instead of implying Essentials covers it.
* fix(auth0): trim SKILL.md under the skillsaw context-budget limit
* fix(auth0): resolve six health-check scoring/plan-matching logic issues
Addresses CodeRabbit findings on #142 (originating in #127), all in the
consolidated feature-healthcheck reference:
1. A4AA fit bonuses were dead code (boolean compared to strings). Thread
ai_use_case as an enum end-to-end; gate on {AI-Native,AI-Differentiated}
with a flat +0.30, and stop AI-Enhanced tenants tripping the CRITICAL
Token Vault/CIBA branch.
2. B2C Essentials MAU branch no longer routes to B2C Professional (a lower
MAU ceiling); stays on Essentials + SOFT Enterprise path.
3. Regulated-vertical branch stops citing BPD (Professional-only) as a reason
for the Essentials recommendation.
4. Missing current_plan/use_case now defaults (not halts), consistent with the
confidence-scoring + graceful-degradation design.
5. MIXED is auto-reachable (both-segments check before B2B) and gets its own
B2B Essentials plan branch; final ELSE relabeled UNKNOWN.
6. Scan report normalized to the canonical flat finding array with the real
5-value severity scale; drop the stale ~50-check figure; remove the wrong
Enterprise-Connection-count tier gate.
---------
Co-authored-by: Sanchit Mehta <sanchit.mehta@okta.com>
The "Programmatic Initialization" section taught the explicit-credentials
factory form (`webAuth(clientId:domain:)`, `authentication(clientId:domain:)`)
with inline `"YOUR_CLIENT_ID"` / `"YOUR_DOMAIN"` placeholders. Lower-capability
models copy this form verbatim and hardcode credentials into source, tripping
the security graders and diverging from the recommended `Auth0.plist` path.
Remove the section so the skill teaches a single, secure configuration path
(Auth0.plist). The migration/detection references to `webAuth(domain:clientId:)`
elsewhere are unaffected — they identify existing call sites to upgrade, not
patterns to author.
The Ionic Vue logout snippet had a stray ) after the packageId assignment
(const packageId = "YOUR_PACKAGE_ID";)), producing invalid JavaScript. This
fix was originally made in #120 but was lost in the v2.0 re-architecture
(#137) when the per-skill files were consolidated into the flat reference pool.
* fix(auth0): remove hardcoded Auth0.getInstance init from Android reference
The API Reference showed `Auth0.getInstance("CLIENT_ID", "DOMAIN")` as an
equal alternative to `Auth0.getInstance(context)`. Lower-capability models
tend to copy this literal-credential variant, hardcoding client ID and domain
in .kt source instead of using strings.xml. Remove the direct variant and add
an explicit note to always initialize from strings.xml.
* fix(auth0): warn against Auth0.getInstance(clientId, domain) hardcoding
Add the explicit warning at the Quick Start initialize step and a Common
Mistakes row against passing clientId/domain to Auth0.getInstance(). Restores
guidance from #117 that was lost in the v2.0 re-architecture (#137).
Restore the guidance that runtimeConfig values should be left as empty strings
so Nuxt auto-fills them from NUXT_AUTH0_* env vars at runtime, plus a Common
Mistakes row against hardcoding credentials in nuxt.config.ts. Originally added
in #114, lost in the v2.0 re-architecture (#137) when per-skill files were
consolidated into the flat reference pool.
* fix(auth0): use SDK-native ISSUER_BASE_URL/AUDIENCE env vars in Express JWT reference
The express-oauth2-jwt-bearer reference taught AUTH0_DOMAIN/AUTH0_AUDIENCE and
constructed issuerBaseURL from a domain. Switch to the SDK's native
ISSUER_BASE_URL/AUDIENCE keys, read directly, so generated code matches the
package's documented configuration.
Update all code snippets, .env blocks, config/env tables, setup-guide wording,
and the Common Issues/Common Mistakes rows for consistency. Note that
ISSUER_BASE_URL is a full URL including https:// (unlike the bare-hostname
AUTH0_DOMAIN), and flip the "domain includes https://" mistake row accordingly.
* fix(auth0): correct ISSUER_BASE_URL format note in Express JWT reference
Verified against the express-oauth2-jwt-bearer source: the SDK's
normalizeIssuerUrl auto-prepends https:// to a bare hostname, so a missing
scheme does not error at startup (only HTTP is rejected under
NODE_ENV=production). Reword the Common Mistakes row accordingly instead of
claiming an "Invalid URL" startup error.
* refactor(auth0): call auth() with no args in Express JWT reference
Mirror the approach from #126: instead of passing issuerBaseURL/audience
explicitly, let express-oauth2-jwt-bearer read ISSUER_BASE_URL / AUDIENCE from
the environment via a zero-argument auth() call. Add .env-first guidance to the
Quick Start, an anti-hardcoding Common Mistakes row, and align the config/env
tables to "optional — defaults to env var".
* fix(auth0): warn against passing credentials in code for Swift
Restore the explicit prohibition against hardcoding clientId/domain in Swift
source or passing them as arguments to Auth0.webAuth() / Auth0.authentication()
when Auth0.plist is present, with correct/incorrect examples and a Common
Mistakes row. Originally added in #101, lost in the v2.0 re-architecture (#137)
when per-skill files were consolidated into the flat reference pool.
* fix(auth0): reword swift escape-hatch note to pair with positive guidance
The Web Auth logout examples declared `override fun onSuccess(result: Void)`
under a `Callback<Void?, AuthenticationException>` type parameter. The
nullability mismatch (Void vs Void?) fails Kotlin compilation. Align both
logout samples with the type parameter and the other correct callback
examples in the same file.
The Swift reference's "Decoding Claims" example used
IDTokenClaimsValidation().validate(idToken) to read email/name. That type
is an internal token-validation helper — it does not exist as a public
claims API and does not return a claims object, so the profile-loading
code an agent generates from it would not compile.
Replace it with the correct approach: read the profile from
credentialsManager.user (a UserInfo? exposing sub/name/email/... claims),
and add a JWTDecode example for manual ID token decoding. Add a note that
IDTokenClaimsValidation/IDTokenClaimsValidator are internal and must not be
used to read claims.
Co-authored-by: Frederik Prijck <frederik.prijck@okta.com>
Warn that user export files contain password hashes/PII (don't commit,
keep out of CI logs, delete after import) and that --json user command
output/import payloads expose profiles and password hashes.
* docs(auth0): harden API test-token examples against inline-token leaks
Mirror the framework-go.md token-isolation pattern across the API framework
references: capture test tokens into a shell variable and reference $TOKEN in curl instead of pasting raw values inline,
which leak into shell history and terminal scrollback. Also narrow the fastify
/api/profile response to return only the fields the client needs instead of the
whole decoded token (which exposes all claims, custom namespaces, and metadata).
Files: framework-fastify-api.md, framework-aspnetcore-api.md,
framework-fastapi-api.md, framework-springboot-api.md, framework-express-jwt.md
Replace lowercase-hyphen secret placeholder values with the
<YOUR_...> angle-bracket convention used elsewhere in the skill so
naive secret scanners don't flag them as exposed literals.
- framework-java-mvc.md: AUTH0_CLIENT_SECRET placeholders -> <YOUR_CLIENT_SECRET>
- tooling-terraform.md: auth0_client_secret -> <YOUR_M2M_CLIENT_SECRET>
Env-read and variable-reference lines untouched.
* fix(auth0): harden against security-scan false positives
The v2.0 re-architecture (#137) triggered a critical finding on the
Agent Trust Hub / Socket / Snyk scans. This addresses the actionable,
scan-scoped surface without removing legitimate behavior.
Placeholder URLs
- Replace registrable placeholder hostnames (your-api.com,
your-production-domain.com, your-app.com, your-spa-domain.com,
your-web-app.com, your-domain.com) with RFC-2606 example.com forms
across references/*.md. Kills the "malicious URL" finding
(your-production-domain.com) and pre-empts future URL-reputation hits.
Matches the skill's already-dominant `api.example.com` convention.
.auth0.com domain placeholders and client-id/secret tokens are left
as-is: not registrable / not URLs, so not a scanner surface.
Move the behavioral eval harness out of the skill dir
- Socket flagged tests/behavioral/graders.mjs (reads .env, pipes source
into the local `claude` CLI via execa). That's a dev-only test grader,
but it sits inside per-skill scan scope. Move tests/ -> repo-root
evals/ so the executable harness is no longer bundled with the skill
consumers install. Fix run-evals.mjs path resolution, the routing
checker's routing-cases.json lookup, the README, and the AGENTS.md
layout doc.
skillsaw: exempt template-routed reference families
- framework-*.md / tooling-*.md are routed only via the
`references/framework-{framework}.md` / `tooling-{tooling}.md`
placeholder templates, which skillsaw's literal-scan
agentskill-unreferenced-files rule can't resolve. Co-located tests
were previously (accidentally) satisfying that reachability; moving
them out exposed it. Their reachability is properly enforced by
scripts/check_router_reachability.py, so exempt the two template-routed
families in .skillsaw.yaml. feature-*/pattern-* orphan detection stays.
Verified: skillsaw --strict (0/0, grade A), check_router_reachability,
check_routing_evals, and run-evals --dry-run (17 case files) all pass.
* fix(auth0): keep load_cases skill-dir-relative for unit tests
The previous commit hardcoded routing-cases.json to repo-root evals/,
which broke scripts/test_check_routing_evals.py — the unit tests build a
self-contained temp skill with its own tests/routing-cases.json and rely
on load_cases(skill_dir) reading from that dir.
Prefer a skill-local tests/routing-cases.json when present (unit tests),
fall back to repo-root evals/routing-cases.json otherwise (production,
after the harness move). Both the pytest suite (10/10) and the real
check pass.
* chore(auth0): bump plugin + skill version to 2.0.1
Patch bump for the security-scan hardening: placeholder-URL cleanup,
eval harness move out of the skill dir, and the skillsaw template-route
exemption. No new routes or breaking changes. Updates all six plugin/
marketplace manifests and SKILL.md frontmatter in lockstep.
* fix(auth0): use `formula` for brew installs, not `package`
The brew install entries declare the Homebrew formula under a `package`
key. OpenClaw's skill installer reads `formula` (or `cask`) for a
`kind: brew` entry and ignores `package`, so an entry with only `package`
is missing its required field and is silently dropped — the installer
never appears in `openclaw skills info`, leaving these skills with no
working install path on a fresh machine.
`package` is the field for `kind: node`/`uv` installs, not `brew`.
Renames `package` -> `formula` in the brew entries of 9 skills (the
values are already valid Homebrew tap/formula names).
* chore: update custom linter rule for clawhub
---------
Co-authored-by: Frederik Prijck <frederik.prijck@okta.com>
* fix(auth0-mfa): correct Vue step-up pattern to use idTokenClaims reactive ref
Replaces getIdTokenClaims() (React API) with idTokenClaims reactive ref,
which is how auth0-vue exposes token claims. Also adds acr_values/amr
step-up pattern back alongside the popup and custom MFA UI approaches.
* fix(auth0-mfa): remove popup step-up section from Vue examples
* fix(auth0-mfa): make amr check explicit in Vue transfer handler
* fix(auth0-mfa): document both Vue step-up approaches with acr_values first
* fix(auth0-mfa): clarify step-up vs policy-driven MFA distinction in Vue section
* fix(auth0-mfa): remove policy-driven MFA section from Vue examples
* fix(auth0-mfa): remove extra Vue custom MFA UI example
The Vue section only needs to cover the common step-up flow
(acr_values + amr check). The custom challenge flow example was
out of scope for this skill.
Rewrites description field in all 44 SKILL.md files to follow the
optimizing-descriptions guidelines:
- Imperative "Use when..." phrasing throughout
- Focused on user intent, not implementation details
- Explicit scope hints ("even if the user says X without naming Y")
- Removed keyword lists and "Triggers on:" patterns
- All descriptions under 1024 characters
skillsaw --strict passes with 0 errors.
* feat(android): add auth0-android-major-migration skill
Adds a spec-driven skill that upgrades an existing com.auth0.android:auth0
(v3) integration to the next major version (v4), the Android counterpart to
auth0-swift-major-migration.
The skill is source-driven and grep-gated: it fetches the v4 SDK's actual
Kotlin source to confirm signatures, audits which Auth0 APIs the project
actually calls, and applies only the breaking changes that affect real call
sites — then builds until green and emits a migration summary.
Target version is argument-based: an optional version argument is validated
(must be a published tag, within the next major, and not a downgrade) and the
skill stops and asks on failure; when omitted it auto-resolves the latest v4
release (including pre-releases). Covers the v4 prerequisite gate (minSdk 26,
Java 17, Gradle/AGP/Kotlin) and the documented breaking and behavioral changes.
Includes references (process, security), an eval suite, and registers the
skill across the plugin manifests and READMEs.
* fix(android): address markdownlint nits in migration skill docs
Add blank lines around fenced code blocks (MD031) and language
specifiers on checklist/diagram fences (MD040) in SKILL.md, process.md,
and security.md. Docs-only; no behavioral change.
* docs(android): note expires_in JSON key is unchanged; renumber §9 subsections
* Adds support swift sdk for migrating to major version releases
* Updates README.md PLUGIN.md plugin.json files
* Updates README.md, SKILL.md to have latest major version
* Migration is based on SDK code. Rather than migration guide
* Remove sequential migration
* Updates skill with code examples
* Updates requestable and mfa client related code examples. README.md and other docs updated
* Removes v1 or v2 to v3. Prompts user to specify v3 version to migrate. Removes grep based file search
* refers to latest tag on v3 instead of hardcoded tag
* Skill version set to 1.0.0
* fixes new error surface with all errors covered in skill.md
* Skill takes version as argument
* Resolve PR #104 review comments
- license: Proprietary → Apache-2.0 (CodeRabbit critical)
- Step 2: replace version prompt with arg-validation (3-check gate) + auto-resolve latest v3 when no arg; use find instead of globstar for Package.resolved
- Step 1/7/8: replace hardcoded iPhone 16 simulator with dynamic xcrun simctl lookup
- graders.json: regex [3-9] → ([3-9]|[1-9][0-9]+) to support v10+ (CodeRabbit)
- graders.ts: expand contains_any/not_contains_any to one grader per value (CodeRabbit data-loss fix)
- security.md: cat **/Auth0.plist → find . -name Auth0.plist (globstar fix)
- cursor-plugin/plugin.json: add missing comma after "major comma after" major version upgrades"
- process.md: add plaintext language tag to signature confirmation code block
* Add run-evals.mjs and PROMPT.md for swift migration eval runner
CodeRabbit flagged that package.json scripts referenced run-evals.mjs which
didn't exist in the tests directory. Copy the shared runner and add PROMPT.md
with the task prompt used for live evaluation runs.
* Rename PROMPT.md to prompt.md (kebab-case lint fix)
CI requires markdown files to be kebab-case. Update run-evals.mjs to
match the new filename.
* Fix unlabeled code block fences in security.md, process.md, SKILL.md
- security.md: add plaintext language tag to all 4 checklist blocks (lines 13, 27, 40, 48)
- process.md: add plaintext tag to backend pattern block
- SKILL.md: add plaintext tag to Carthage Cartfile block
* fix(auth0-express): clarify authorizationParams required for API access tokens
* fix(auth0-express): correct accessToken object shape in Quick Reference
`expires_at` → `expires_in` (seconds remaining, per context.js lines 231–249).
Also surface `isExpired()` and `refresh()` methods which the SDK exposes on
the returned object.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix the anti pattern
* address feedback
* address coderabbit
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Some agents were hardcoding credentials directly in nuxt.config.ts because
the empty string placeholders didn't explain Nuxt's automatic env var
mapping. Added inline comment and a Critical Mistakes row.