Pick the right VTEX auth token for your request

Explains which VTEX IO token (authToken, storeUserAuthToken, adminUserAuthToken) to use based on request context—storefront, admin, or app-level integration—and how to avoid hardcoded credentials.

Best for: VTEX developers integrating with VTEX IO endpoints from backend code.

Engineering / code-reviewatomicfor-engineersno-setupfrom-text

Skill file

Preview skill file
---
name: vtex-io-auth-tokens-and-context
description: "Apply when choosing which VTEX IO authentication token should back a request from a backend app. Covers `ctx.authToken`, `ctx.storeUserAuthToken`, `ctx.adminUserAuthToken`, `authMethod`, and how requester context should determine the identity used by VTEX clients. Use for deciding which identity talks to VTEX endpoints in storefront-backed requests, Admin actions, or app-level integrations that should avoid hardcoded VTEX credentials."
---

# Auth Tokens & Request Context

## When this skill applies

Use this skill when the main decision is which VTEX IO identity should authenticate a backend request to VTEX services.

- Choosing between `ctx.authToken`, `ctx.storeUserAuthToken`, and `ctx.adminUserAuthToken`
- Deciding whether a VTEX client call should use `AUTH_TOKEN`, `STORE_TOKEN`, or `ADMIN_TOKEN`
- Reviewing storefront and Admin integrations that should respect the current user identity
- Replacing hardcoded `appKey` and `appToken` usage inside a VTEX IO app

Do not use this skill for:
- deciding which policies belong in `manifest.json`
- modeling route-level authorization or resource-based policies
- choosing between `ExternalClient`, `JanusClient`, and other client abstractions
- browser-side login or session UX flows
- validating route input or deciding what data may cross the app boundary

## Decision rules

- Use this skill to decide which identity talks to VTEX endpoints, not what that identity is authorized to do.
- Use `AUTH_TOKEN` with `ctx.authToken` only for app-level operations that are not tied to a current shopper or Admin user.
- Use `STORE_TOKEN` with `ctx.storeUserAuthToken` whenever the action comes from storefront browsing or a shopper-triggered flow and the integration should respect shopper permissions.
- Use `ADMIN_TOKEN` with `ctx.adminUserAuthToken` whenever the action comes from an Admin interface and the integration should respect the logged-in Admin user's License Manager permissions.
- Prefer user tokens whenever they are available. The official guidance is to avoid app-token authentication when a store or Admin user token can represent the requester more accurately.
- If the corresponding user token is not present, fall back to `AUTH_TOKEN` only when the operation is truly app-scoped and does not depend on a current shopper or Admin identity.
- When using VTEX IO clients that accept `authMethod`, pass the token choice explicitly when the default app identity is not the right one for the request.
- When wrapping custom VTEX clients, propagate the matching auth token from `IOContext` at the client boundary instead of hardcoding credentials in handlers.
- Keep token choice aligned with the user journey: storefront flows should not silently escalate to app-level permissions, and Admin flows should not bypass the current Admin role context.
- `ADMIN_TOKEN` with `ctx.adminUserAuthToken` must remain server-side only and must never be exposed or proxied to browser clients.
- Treat token choice and policy design as separate concerns: this skill decides which identity is making the call, while auth-and-policies decides what that identity is allowed to do.
- Do not use `appKey` and `appToken` inside a VTEX IO app unless there is a documented exception outside the normal VTEX IO auth-token model.
- Never log raw tokens or return them in responses. Tokens are request secrets, and downstream callers should receive only business data.

Token selection at a glance:

| Token | Context field | Use when | Avoid when |
|---|---|---|---|
| `AUTH_TOKEN` | `ctx.authToken` | app-level jobs, service-to-service work, or operations not linked to a current user | a shopper or Admin user is already driving the action |
| `STORE_TOKEN` | `ctx.storeUserAuthToken` | storefront and shopper-triggered operations | backend jobs or Admin-only operations |
| `ADMIN_TOKEN` | `ctx.adminUserAuthToken` | Admin requests that must respect the current user's LM role | storefront flows or background app tasks |

## Hard constraints

### Constraint: User-driven requests must prefer user tokens over the app token

If a request is initiated by a current shopper or Admin user, the VTEX integration MUST use the corresponding user token instead of defaulting to the app token.

**Why this matters**

Using the app token for user-driven work widens permissions unnecessarily and disconnects the request from the real user context that should govern access.

**Detection**

If the code runs in a storefront or Admin request path and still uses `ctx.authToken` or implicit app-token behavior, STOP and verify whether `ctx.storeUserAuthToken` or `ctx.adminUserAuthToken` should be used instead.

**Correct**

```typescript
export class OmsClient extends JanusClient {
  constructor(ctx: IOContext, options?: InstanceOptions) {
    super(ctx, {
      ...options,
      headers: {
        ...options?.headers,
        VtexIdclientAutCookie: ctx.storeUserAuthToken,
      },
    })
  }
}
```

**Wrong**

```typescript
export class OmsClient extends JanusClient {
  constructor(ctx: IOContext, options?: InstanceOptions) {
    super(ctx, {
      ...options,
      headers: {
        ...options?.headers,
        VtexIdclientAutCookie: ctx.authToken,
      },
    })
  }
}
```

### Constraint: App tokens must be reserved for app-level operations that are not tied to a user

Use `ctx.authToken` only when the request is genuinely app-scoped and no current shopper or Admin identity should govern the action.

**Why this matters**

The app token carries the permissions declared in the app manifest. Using it for user-triggered actions can bypass the narrower shopper or Admin permission model that the platform expects.

**Detection**

If a request originates from an Admin page, storefront interaction, or another user-facing workflow, STOP before using `ctx.authToken` and confirm that the action is truly app-level rather than user-scoped.

**Correct**

```typescript
export class RatesAndBenefitsClient extends JanusClient {
  constructor(ctx: IOContext, options?: InstanceOptions) {
    super(ctx, {
      ...options,
      headers: {
        ...options?.headers,
        VtexIdclientAutCookie: ctx.authToken,
      },
    })
  }
}
```

**Wrong**

```typescript
export class AdminOrdersClient extends JanusClient {
  constructor(ctx: IOContext, options?: InstanceOptions) {
    super(ctx, {
      ...options,
      headers: {
        ...options?.headers,
        VtexIdclientAutCookie: ctx.authToken,
      },
    })
  }
}
```

This is wrong when the client is used from an Admin flow that should respect the logged-in user's role.

### Constraint: VTEX IO apps must not hardcode VTEX API credentials when auth tokens are available

A VTEX IO app MUST use tokens from `IOContext` or `authMethod` instead of embedding `appKey`, `appToken`, or static VTEX credentials in source code or routine runtime configuration.

**Why this matters**

Hardcoded VTEX credentials are harder to rotate, easier to leak, and bypass the request-context model that VTEX IO clients already support.

**Detection**

If you see `X-VTEX-API-AppKey`, `X-VTEX-API-AppToken`, raw VTEX API credentials, or environment variables carrying permanent VTEX credentials inside a normal IO app integration, STOP and replace them with the correct auth-token flow unless there is a documented exception.

**Correct**

```typescript
await ctx.clients.catalog.getSkuById(id, {
  authMethod: 'ADMIN_TOKEN',
})
```

**Wrong**

```typescript
await fetch(`https://${ctx.vtex.account}.myvtex.com/api/catalog/pvt/stockkeepingunit/${id}`, {
  headers: {
    'X-VTEX-API-AppKey': process.env.VTEX_APP_KEY!,
    'X-VTEX-API-AppToken': process.env.VTEX_APP_TOKEN!,
  },
})
```

## Preferred pattern

Start from the requester context, choose the token identity that matches that requester, and keep the token propagation inside the client layer.

Minimal selection guide:

```text
storefront request -> STORE_TOKEN / ctx.storeUserAuthToken
admin request -> ADMIN_TOKEN / ctx.adminUserAuthToken
background app work -> AUTH_TOKEN / ctx.authToken
```

Pass the token explicitly when the client supports `authMethod`:

```typescript
await ctx.clients.orders.listOrders({
  authMethod: 'ADMIN_TOKEN',
})
```

```typescript
await ctx.clients.orders.listOrders({
  authMethod: 'STORE_TOKEN',
})
```

Or inject the matching token in a custom VTEX client:

```typescript
import type { IOContext, InstanceOptions } from '@vtex/api'
import { JanusClient } from '@vtex/api'

export class OmsClient extends JanusClient {
  constructor(ctx: IOContext, options?: InstanceOptions) {
    super(ctx, {
      ...options,
      headers: {
        ...options?.headers,
        VtexIdclientAutCookie: ctx.adminUserAuthToken,
      },
    })
  }
}
```

Keep the decision close to the request boundary, then let downstream handlers and services depend on the correctly configured client rather than choosing tokens ad hoc in many places.

## Common failure modes

- Defaulting every VTEX request to `ctx.authToken`, even when a shopper or Admin user initiated the action.
- Using `ctx.authToken` in Admin pages and accidentally bypassing the current Admin user's License Manager role context.
- Using `ctx.authToken` in storefront flows that should be limited by shopper permissions.
- Hardcoding `appKey` and `appToken` in an IO app instead of using auth tokens from `IOContext`.
- Choosing the right token in one client method but forgetting to apply the same identity consistently across related calls.
- Mixing token choice with policy modeling and treating them as the same decision.
- Logging `ctx.authToken`, `ctx.storeUserAuthToken`, or `ctx.adminUserAuthToken` in plain text, or forwarding raw tokens to downstream services that do not need them.

## Review checklist

- [ ] Does each VTEX integration use the correct requester identity: shopper, Admin user, or app?
- [ ] Are `ctx.storeUserAuthToken` and `ctx.adminUserAuthToken` preferred when a user is actually driving the action?
- [ ] Is `ctx.authToken` used only for app-level operations that are not tied to a current user?
- [ ] Are hardcoded VTEX credentials absent from normal IO app integrations?
- [ ] Is token propagation centralized in the client layer or explicit `authMethod` usage rather than scattered across handlers?

## Related skills

- [`vtex-io-auth-and-policies`](../vtex-io-auth-and-policies/SKILL.md) - Use when the main choice is which permissions and policies the chosen identity should carry

## Reference

- [App authentication using auth tokens](https://developers.vtex.com/docs/guides/app-authentication-using-auth-tokens) - Official token model for `AUTH_TOKEN`, `STORE_TOKEN`, and `ADMIN_TOKEN`
- [Using VTEX IO clients](https://developers.vtex.com/docs/guides/calling-commerce-apis-3-using-vtex-io-clients) - Client usage patterns that complement token selection
- [Policies](https://developers.vtex.com/docs/guides/vtex-io-documentation-policies) - How app-token permissions relate to manifest-declared policies

Source

Creator's repository · vtex/skills

View on GitHub

Security

Security checks in progress
Results will appear here once audits complete
Checked by 3 independent security firms
Does it try to trick the AI?Not yet checkedPending · Gen Agent Trust Hub
Does it sneak in hidden code?Not yet checkedPending · Socket
Does it have known bugs?Not yet checkedPending · Snyk