stack/docs/code-examples/concepts/jwt.ts
promptless[bot] 59b834ae4b
docs: Document isRestricted and restrictedReason JWT claims (#1136)
[Open this suggestion in Promptless to view citations and reasoning
process](https://app.gopromptless.ai/change-history/ea7c7471-778d-42ea-9845-fa380f013560)

Documents the new `is_restricted` and `restricted_reason` JWT claims
introduced for the onboarding/restricted users feature. Updates the JWT
documentation to explain these fields in the claims section, adds them
to the example payload, documents the restricted user token structure,
and adds the `include_restricted` JWKS parameter for manual token
verification.

### Trigger Events

<details>
<summary><a
href="e400985754...de0f937f46">stack-auth/stack-auth
commit (dev): de0f937 [CHANGELOG] - 2026.01.21</a></summary>
<br>

**Promptless Research** (1 webpage, 1 GitHub PR)

- [Read webpage from
github.com](e400985754...de0f937f46)
- [Reviewed
stack-auth/stack-auth#1069](https://github.com/stack-auth/stack-auth/pull/1069)

**Agent Response**

> I've completed my analysis of the changelog entry and created the
necessary documentation update.
> 
> ## Summary
> 
> After reviewing the changelog entry for **2026.01.21**, I identified:
> 
> ### Already Covered by Existing Suggestions
> The payment-related items were already documented by existing
suggestions:
> - **Payments Settings page** → covered by the "Document payment
settings" suggestion
> - **Subscription renewal emails** → covered by the "Document payment
email templates" suggestion
> - **Invoice visibility** → covered by the "Document invoice listing
feature" suggestion
> 
> ### New Documentation Created
> I created a new suggestion to address the remaining item: **"Updated
JWT documentation to include `isRestricted` and `restrictedReason`"**
> 
> The suggestion updates the JWT Tokens documentation with:
> - **New claims documentation**: Added `is_restricted` (boolean) and
`restricted_reason` (nullable object with `type` field) to the Stack
Auth Specific Claims section
> - **Updated example payload**: Added the new fields to the example JWT
payload
> - **Restricted user tokens**: Documented how restricted user tokens
differ (`:restricted` audience suffix)
> - **JWKS parameter**: Added documentation for the
`include_restricted=true` parameter in the Manual JWT Verification
section
> 
> These fields were introduced in PR #1069 "Onboarding app & restricted
users" to support the new onboarding flow where users who haven't
completed requirements (like email verification) are marked as
"restricted."

</details>



---

**Help us improve Promptless** — If this suggestion missed the mark,
please [share quick
feedback](https://app.gopromptless.ai/change-history/ea7c7471-778d-42ea-9845-fa380f013560?openFeedback=1).

*If you want Promptless to make further changes on this PR, feel free to
leave a comment tagging Promptless (It won't show up in the user drop
down but Promptless will get it!)*

---------

Co-authored-by: promptless[bot] <179508745+promptless[bot]@users.noreply.github.com>
Co-authored-by: Madison <madison.w.kennedy@gmail.com>
2026-02-24 10:45:01 -06:00

141 lines
3.8 KiB
TypeScript

import { CodeExample } from '../../lib/code-examples';
export const jwtExamples = {
'client-side-usage': [
{
language: 'JavaScript',
framework: 'Next.js',
code: `import { useUser } from '@stackframe/stack';
export function UserProfile() {
const user = useUser();
if (!user) {
return <div>Please sign in</div>;
}
return <div>Welcome, {user.displayName}!</div>;
}`,
highlightLanguage: 'tsx',
filename: 'app/components/user-profile.tsx'
},
{
language: 'JavaScript',
framework: 'React',
code: `import { useUser } from '@stackframe/react';
export function UserProfile() {
const user = useUser();
if (!user) {
return <div>Please sign in</div>;
}
return <div>Welcome, {user.displayName}!</div>;
}`,
highlightLanguage: 'tsx',
filename: 'components/UserProfile.tsx'
},
] as CodeExample[],
'server-side-usage': [
{
language: 'JavaScript',
framework: 'Next.js',
code: `import { stackServerApp } from '@/stack';
export async function GET() {
const user = await stackServerApp.getUser();
if (!user) {
return new Response('Unauthorized', { status: 401 });
}
// Access user information from the JWT
return Response.json({
id: user.id,
displayName: user.displayName,
primaryEmail: user.primaryEmail,
selectedTeamId: user.selectedTeamId,
// Other user properties...
});
}`,
highlightLanguage: 'typescript',
filename: 'app/api/user/route.ts'
},
] as CodeExample[],
'manual-jwt-verification': [
{
language: 'JavaScript',
framework: 'Node.js',
code: `import * as jose from 'jose';
// Get the public key set from Stack Auth
const jwks = jose.createRemoteJWKSet(
new URL('https://api.stack-auth.com/api/v1/projects/YOUR_PROJECT_ID/.well-known/jwks.json')
);
// Verify a regular (non-anonymous) access token
try {
const { payload } = await jose.jwtVerify(token, jwks, {
issuer: 'https://api.stack-auth.com/api/v1/projects/YOUR_PROJECT_ID',
audience: 'YOUR_PROJECT_ID',
});
console.log('JWT is valid:', payload);
} catch (error) {
console.error('JWT verification failed:', error);
}`,
highlightLanguage: 'typescript',
filename: 'verify-jwt.ts'
},
] as CodeExample[],
'manual-jwt-verification-anonymous': [
{
language: 'JavaScript',
framework: 'Node.js',
code: `import * as jose from 'jose';
const jwks = jose.createRemoteJWKSet(
new URL('https://api.stack-auth.com/api/v1/projects/YOUR_PROJECT_ID/.well-known/jwks.json?include_anonymous=true')
);
const { payload } = await jose.jwtVerify(token, jwks, {
issuer: [
'https://api.stack-auth.com/api/v1/projects/YOUR_PROJECT_ID',
'https://api.stack-auth.com/api/v1/projects-anonymous-users/YOUR_PROJECT_ID',
],
audience: ['YOUR_PROJECT_ID', 'YOUR_PROJECT_ID:anon'],
});`,
highlightLanguage: 'typescript',
filename: 'verify-jwt.ts'
},
] as CodeExample[],
'manual-jwt-verification-restricted': [
{
language: 'JavaScript',
framework: 'Node.js',
code: `import * as jose from 'jose';
const jwks = jose.createRemoteJWKSet(
new URL('https://api.stack-auth.com/api/v1/projects/YOUR_PROJECT_ID/.well-known/jwks.json?include_anonymous=true&include_restricted=true')
);
// All three user types have different issuers
const { payload } = await jose.jwtVerify(token, jwks, {
issuer: [
'https://api.stack-auth.com/api/v1/projects/YOUR_PROJECT_ID',
'https://api.stack-auth.com/api/v1/projects-anonymous-users/YOUR_PROJECT_ID',
'https://api.stack-auth.com/api/v1/projects-restricted-users/YOUR_PROJECT_ID',
],
audience: ['YOUR_PROJECT_ID', 'YOUR_PROJECT_ID:anon', 'YOUR_PROJECT_ID:restricted'],
});`,
highlightLanguage: 'typescript',
filename: 'verify-jwt.ts'
},
] as CodeExample[],
};