Skip to content

Comments

POC: Cookbook style listing in the docs#397

Open
saif-at-scalekit wants to merge 6 commits intomainfrom
poc-blog-as-cookbooks
Open

POC: Cookbook style listing in the docs#397
saif-at-scalekit wants to merge 6 commits intomainfrom
poc-blog-as-cookbooks

Conversation

@saif-at-scalekit
Copy link
Collaborator

@saif-at-scalekit saif-at-scalekit commented Jan 21, 2026

State: Proof of Concept

Adds a blog-style content surface to docs.scalekit.com dedicated to P.A.T.-driven technical stories (Problem → Angle → Teach). This space is for problem‑first, opinionated, and educational articles that sit alongside reference docs, helping developers discover real-world use cases, understand Scalekit’s unique point of view, and learn concrete implementation patterns without wading through product‑only documentation.

Example we current have

  • Build a your own organization switcher

Summary by CodeRabbit

  • New Features

    • Cookbooks now use a blog plugin that provides reading-time and total-word metrics and has its own navigation behavior.
  • Documentation

    • Added cookbooks: a guide for building custom organization switchers (multi-language examples), a Next.js passwordless-auth integration guide, and a Spring Boot JWT timeout configuration guide.

…on switcher

- Integrated the starlight-blog package into the project, enabling blog functionality with metrics for reading time and total words.
- Updated the Astro configuration to include the starlight-blog plugin.
- Added a new blog post titled "Building a Custom Organization Switcher," detailing how to create a custom organization switcher UI for enhanced user experiences in multi-tenant applications.
- Updated sidebar configuration to exclude the blog from navigation and ensure a cleaner user experience.
- Included a new author image for the blog post to enhance visual appeal.
@coderabbitai
Copy link

coderabbitai bot commented Jan 21, 2026

📝 Walkthrough

Walkthrough

Registers a cookbooks blog via starlight-blog, adds the dependency, excludes /cookbooks from topic sidebar, refactors docs content schema to extend from blogSchema, and adds multiple new cookbook docs (including organization switcher, Next.js auth, Java JWT timeout).

Changes

Cohort / File(s) Summary
Blog plugin & dependency
astro.config.mjs, package.json
Imported and registered starlightBlog({ prefix: 'cookbooks', metrics: { readingTime: true, words: 'total' } }) and added dependency "starlight-blog": "^0.25.2".
Sidebar/navigation
src/configs/sidebar.config.ts
Added '/cookbooks' to exclude and added a Cookbooks entry in the sidebar navigation.
Content schema
src/content.config.ts
Reworked docs schema composition to use extend(context) starting from blogSchema(context), then merging topicSchema, videosSchema, and additional fields (overviewTitle, seeAlso, browseCentral).
Cookbook docs (new)
src/content/docs/cookbooks/...
src/content/docs/cookbooks/building-custom-org-switcher.mdx, .../implement-nextjs-auth.mdx, .../java-spring-boot-jwt-timeout.mdx
Added several cookbook MDX pages with multi-language examples and implementation guidance (organization switcher, Next.js passwordless auth, Spring Boot JWT timeout).

Sequence Diagram(s)

(omitted — changes are configuration/content additions and schema refactor, not multi-component runtime flow requiring a sequence diagram)

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • ravibits
  • amitash1912

Poem

"I'm a rabbit in the docs, nibbling new lines, 🐇
Cookbooks sprout where starlight shines,
Schemas weave together, plugins take flight,
Pages bloom with code in morning light,
Hooray — small hops, big docs tonight!"

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'POC: Cookbook style listing in the docs' directly describes the main change—adding a proof-of-concept blog-style cookbook content surface to the documentation site, which aligns with the core objective of the PR.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch poc-blog-as-cookbooks

Tip

Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord.


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Fix all issues with AI agents
In `@astro.config.mjs`:
- Around line 94-99: Remove the invalid metrics option from the starlightBlog()
call: open the configuration where starlightBlog(...) is invoked and delete the
entire metrics: { readingTime: true, words: 'total' } object so the plugin
options only use supported keys (prefix, title, postCount, recentPostCount,
authors, navigation, frontmatter); ensure no other code relies on that removed
option since reading time and word count are provided automatically via post
metadata/frontmatter.

In `@src/configs/sidebar.config.ts`:
- Around line 511-515: The exclude array (export const exclude) currently lists
'/blog' which may not match nested blog pages; update the pattern in the exclude
array to use a recursive glob (e.g., replace '/blog' with '/blog/**') so the
entire blog subtree is excluded by the glob matcher, and keep the existing
'/apis/**/*' style consistent with other entries.

In `@src/content/docs/blog/building-custom-org-switcher.mdx`:
- Around line 107-116: The "Add domain context" block currently contains only a
JavaScript example; replace it with a Tabs block containing Node.js, Python, Go,
and Java examples that each call the Domains API to list domains for an
organization and show how to display a domain (e.g., "@acme.com") next to the
org name. Specifically, update the block that references scalekit.domains.list
and organizationId: 'org_123' so it includes a Node.js/JavaScript snippet (same
call pattern), a Python snippet calling scalekit.domains.list or equivalent
client method with organization_id='org_123', a Go snippet using the
Domains.List method with OrganizationID: "org_123", and a Java snippet using the
domains().list(...) call with organizationId "org_123"; keep the examples
minimal and consistent (fetch domains, iterate or access first domain, and show
"@acme.com" display note).
- Around line 47-103: Add the required syncKey attribute to the Tabs components
so language selection remains consistent: locate the Tabs elements (the
top-level Tabs component wrapping the TabItem blocks in this file) and add
syncKey="tech-stack" to each Tabs instance (the TabItem components remain
unchanged); ensure both Tabs blocks on the page use the identical syncKey value
"tech-stack" so multi-language examples stay synchronized across pages.
- Around line 1-16: Update the MDX frontmatter: change the Title field to
sentence case (update 'title'), confirm and update the publish `date` to the
intended current date if needed, and add the required navigation metadata by
adding `sidebar_label` (a short label) and `sidebar_position` or `order` to
place it in the docs navigation; also add `tableOfContents: true` to enable TOC
for multi-section pages and ensure the existing `authors`, `tags`, `excerpt`,
`featured`, and `cover` fields remain intact (look for the frontmatter block
beginning with `---` and the keys `title`, `date`, `authors` to locate where to
add these fields).
📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 19063c3 and 3533e7a.

⛔ Files ignored due to path filters (3)
  • assets/blog/covers/custom-org-switcher.jpg is excluded by !**/*.jpg
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • public/images/blog/authors/hashirr-lukmahn.jpg is excluded by !**/*.jpg
📒 Files selected for processing (5)
  • astro.config.mjs
  • package.json
  • src/configs/sidebar.config.ts
  • src/content.config.ts
  • src/content/docs/blog/building-custom-org-switcher.mdx
🧰 Additional context used
📓 Path-based instructions (8)
astro.config.mjs

📄 CodeRabbit inference engine (.cursorrules)

astro.config.mjs: Expressive Code is configured in astro.config.mjs with themes 'tokyo-night' (dark) and 'light-plus' (light), JetBrains Mono font, and border radius 0.375rem
Expressive Code collapsible sections plugin must be enabled in astro.config.mjs

Files:

  • astro.config.mjs
**/*.{js,ts,tsx,jsx,py,java,cs,go,cpp,c,rb,php,swift,kt,scala,rs,m,mm,groovy,gradle,xml,json}

📄 CodeRabbit inference engine (.cursor/rules/comment-standards.mdc)

Comments should not duplicate the code - avoid comments that simply restate what the code does; comments should add value beyond what's obvious from reading the code

Files:

  • package.json
  • src/configs/sidebar.config.ts
  • src/content.config.ts
**/*.{js,ts,py,go,java,tsx,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

SDK variable names must follow language-specific conventions: Node.js uses scalekit, Python uses scalekit_client, Go uses scalekitClient, Java uses scalekitClient

Files:

  • src/configs/sidebar.config.ts
  • src/content.config.ts
**/*.{js,ts,tsx,jsx,py,java,cs,go,cpp,c,rb,php,swift,kt,scala,rs,m,mm,groovy}

📄 CodeRabbit inference engine (.cursor/rules/comment-standards.mdc)

**/*.{js,ts,tsx,jsx,py,java,cs,go,cpp,c,rb,php,swift,kt,scala,rs,m,mm,groovy}: Good comments do not excuse unclear code - refactor the code to be self-explanatory instead of using comments to explain poorly written code; use better variable names, function names, and code structure
Comments should dispel confusion, not cause it - ensure comments clarify rather than obscure the code's purpose; avoid cryptic or joke comments
Explain unidiomatic code in comments - comment on code that might seem unnecessary or redundant and document why you chose a specific pattern over more common alternatives, especially when it deviates from team conventions
Provide links to the original source of copied code - always attribute code copied from external sources with URLs to Stack Overflow answers, GitHub repositories, or documentation
Include links to external references where helpful - reference standards, RFCs, and official documentation; link to relevant specifications when implementing protocols
Add comments when fixing bugs - document bug fixes with context about the issue, reference issue trackers and bug reports, and explain workarounds and their limitations
Use comments to mark incomplete implementations - use standard formats for TODO, FIXME, and NOTE comments with context about what needs to be done and reference issue trackers when possible
Always document public APIs with function/class comments - explain the purpose, parameters, return values, and exceptions; include usage examples for complex functions
Include file headers with copyright information, license, and authorship - provide a brief description of the file's purpose and document dependencies and requirements

Files:

  • src/configs/sidebar.config.ts
  • src/content.config.ts
**/*.{js,ts,tsx,jsx}

📄 CodeRabbit inference engine (.cursor/rules/comment-standards.mdc)

Use JSDoc standards for all function, class, and complex logic comments in JavaScript/TypeScript - include parameter descriptions (@param), return values (@returns), types (@type), and descriptions; document exceptions and edge cases

Files:

  • src/configs/sidebar.config.ts
  • src/content.config.ts
**/*.mdx

📄 CodeRabbit inference engine (.cursorrules)

**/*.mdx: Use clear, descriptive titles that explain the purpose of the document
Include comprehensive descriptions in frontmatter metadata
Organize content with logical heading hierarchy (H2, H3, H4)
Use tableOfContents property in frontmatter when content has multiple sections
Set appropriate sidebar labels for navigation in frontmatter
Use direct instruction writing style with phrases like 'This guide shows you how to...' and 'Create an authorization URL to...'
Use second person perspective ('your application', 'you receive', 'you must') in documentation
Keep sentences concise, aiming for under 25 words per sentence
Explain the 'why' in documentation with phrases like 'This prevents CSRF attacks by...' or 'Use this to validate that...'
Use action verbs in section headings: 'Store session tokens securely', 'Validate the state parameter', 'Exchange authorization code for tokens'
Use present tense for descriptions: 'Scalekit handles the complex authentication flow', 'The SDK provides methods to refresh tokens'
Use future tense for results: 'This will redirect users to...', 'You'll receive a JWT containing...', 'Scalekit returns an authorization code'
Use transition phrases between sections: 'After the user authenticates...', 'Once the state is validated...', 'Let's take a look at how to...'
Write 1-3 opening paragraphs that explain what users will accomplish, provide context about when/why, preview key concepts, and use direct instructional language
Begin introduction sections with a clear statement of what the guide covers and explain the problem being solved
Use collapsible sections in introduction for sequence diagrams, video demonstrations, data models, and JSON examples with appropriate icons
Use numbered format within Steps component: 1. ## Title with all step content indented with exactly 3 spaces
Use action-oriented headings in step-by-step guides within Steps components
Include code examples in all 4 languages (Node.js, Python, Go, Java) within Steps co...

Files:

  • src/content/docs/blog/building-custom-org-switcher.mdx
**/*.{md,mdx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{md,mdx}: All code examples must include implementations in all 4 languages: Node.js, Python, Go, and Java
Include security comments in code examples explaining security threats and implications
Code examples must demonstrate both success and error paths
Frontmatter must include: title (≤60 characters), description (≤160 characters), sidebar label, order number, and tags array
Use second person ('you', 'your application') for writing voice in documentation
Use present tense for descriptions and imperative mood for instructions in documentation

**/*.{md,mdx}: Use sentence case for all titles and headings in MD/MDX documentation
Keep page titles short and descriptive (3–7 words when possible) in MD/MDX documentation
Use outcome-focused headings that describe results, not categories (e.g., 'Run a script' not 'Scripts')
Avoid gerunds in headings when an imperative works - prefer 'Configure proxies' over 'Configuring proxies'
Keep sidebar labels concise (1–3 words), use sentence case, and focus on outcomes or objects
Use sentence case in sidebar labels without punctuation
Set frontmatter title in sentence case with a clear outcome; description in one sentence (≤160 chars); sidebar.label as shorter form of title; enable tableOfContents on longer pages
Start documentation pages with a one-paragraph overview explaining what the page covers and when to use it
Present the primary use case (80% path) first in documentation, with edge cases later
Use numbered steps for task-focused sections in documentation, with each step beginning with a verb
Break up long documentation sections with subheadings every 3–6 paragraphs
Use asides for important notes, tips, cautions, and references in documentation
Provide runnable, minimal code examples that work as-is in documentation
Prefer CLI-first examples and show file layout when helpful in documentation
Label code blocks with titles for context (e.g., 'Terminal', 'main.ts') in documentation
Keep code block annotations brief and...

Files:

  • src/content/docs/blog/building-custom-org-switcher.mdx
**/*.{yml,yaml,md,mdx}

📄 CodeRabbit inference engine (.cursor/rules/browsecentral-labels.mdc)

**/*.{yml,yaml,md,mdx}: BrowseCentral labels should be maximum 3-5 words - keep concise but add context when needed
BrowseCentral labels should be action-oriented - start with verbs when possible
BrowseCentral labels should be specific and clear - add context when simple labels are ambiguous
BrowseCentral labels should be outcome-focused - describe what users accomplish and the context
BrowseCentral labels should use 'Action + Object' pattern (e.g., 'Invite users', 'Restrict sign-up', 'Set up SCIM')
BrowseCentral labels should use feature names (e.g., 'Enterprise SSO', 'Passwordless quickstart')
BrowseCentral labels should describe task completion (e.g., 'Run migrations', 'Migrate auth', 'Merge identities')
BrowseCentral labels should include specific context when needed (e.g., 'Configure Scalekit MCP server', 'Validate incoming API requests')
BrowseCentral labels should use integration context when applicable (e.g., 'Build MCP auth with your existing auth system')
BrowseCentral labels should avoid instructional prefixes: 'How to', 'Guide to', 'Implement', 'Configure', 'Learn', 'Understand'
BrowseCentral labels should avoid verbose phrases: 'Step-by-step guide', 'Complete tutorial', 'Detailed documentation'
BrowseCentral labels should avoid weak verbs: 'Enable', 'Allow', 'Provide', 'Support'

Files:

  • src/content/docs/blog/building-custom-org-switcher.mdx
🧠 Learnings (12)
📓 Common learnings
Learnt from: CR
Repo: scalekit-inc/developer-docs PR: 0
File: .cursorrules:0-0
Timestamp: 2026-01-13T12:46:55.260Z
Learning: Applies to astro.config.mjs : Expressive Code collapsible sections plugin must be enabled in `astro.config.mjs`
Learnt from: CR
Repo: scalekit-inc/developer-docs PR: 0
File: .cursorrules:0-0
Timestamp: 2026-01-13T12:46:55.260Z
Learning: Applies to astro.config.mjs : Expressive Code is configured in `astro.config.mjs` with themes 'tokyo-night' (dark) and 'light-plus' (light), JetBrains Mono font, and border radius 0.375rem
📚 Learning: 2026-01-13T12:46:55.260Z
Learnt from: CR
Repo: scalekit-inc/developer-docs PR: 0
File: .cursorrules:0-0
Timestamp: 2026-01-13T12:46:55.260Z
Learning: Applies to astro.config.mjs : Expressive Code collapsible sections plugin must be enabled in `astro.config.mjs`

Applied to files:

  • astro.config.mjs
📚 Learning: 2026-01-13T12:46:55.260Z
Learnt from: CR
Repo: scalekit-inc/developer-docs PR: 0
File: .cursorrules:0-0
Timestamp: 2026-01-13T12:46:55.260Z
Learning: Applies to astro.config.mjs : Expressive Code is configured in `astro.config.mjs` with themes 'tokyo-night' (dark) and 'light-plus' (light), JetBrains Mono font, and border radius 0.375rem

Applied to files:

  • astro.config.mjs
📚 Learning: 2026-01-13T12:48:19.565Z
Learnt from: CR
Repo: scalekit-inc/developer-docs PR: 0
File: .cursor/rules/expressive-code.mdc:0-0
Timestamp: 2026-01-13T12:48:19.565Z
Learning: Applies to **/*.mdx : Import `{ Code }` from `astrojs/starlight/components` once per `.mdx` file, placing the import below frontmatter

Applied to files:

  • astro.config.mjs
📚 Learning: 2026-01-13T12:48:11.566Z
Learnt from: CR
Repo: scalekit-inc/developer-docs PR: 0
File: .cursor/rules/documentation-guide.mdc:0-0
Timestamp: 2026-01-13T12:48:11.566Z
Learning: Applies to **/*.{md,mdx} : Set concise sidebar labels that match user vocabulary in navigation metadata

Applied to files:

  • src/configs/sidebar.config.ts
📚 Learning: 2026-01-13T12:46:55.260Z
Learnt from: CR
Repo: scalekit-inc/developer-docs PR: 0
File: .cursorrules:0-0
Timestamp: 2026-01-13T12:46:55.260Z
Learning: Applies to **/*.mdx : Set appropriate sidebar labels for navigation in frontmatter

Applied to files:

  • src/configs/sidebar.config.ts
📚 Learning: 2026-01-13T12:48:11.566Z
Learnt from: CR
Repo: scalekit-inc/developer-docs PR: 0
File: .cursor/rules/documentation-guide.mdc:0-0
Timestamp: 2026-01-13T12:48:11.566Z
Learning: Applies to **/*.{md,mdx} : Keep documentation synchronized with product changes

Applied to files:

  • src/content/docs/blog/building-custom-org-switcher.mdx
📚 Learning: 2026-01-13T12:46:55.260Z
Learnt from: CR
Repo: scalekit-inc/developer-docs PR: 0
File: .cursorrules:0-0
Timestamp: 2026-01-13T12:46:55.260Z
Learning: Applies to **/*.mdx : Use `<Tabs syncKey="tech-stack">` to synchronize multi-language code selection across documentation pages

Applied to files:

  • src/content/docs/blog/building-custom-org-switcher.mdx
📚 Learning: 2026-01-13T12:48:11.566Z
Learnt from: CR
Repo: scalekit-inc/developer-docs PR: 0
File: .cursor/rules/documentation-guide.mdc:0-0
Timestamp: 2026-01-13T12:48:11.566Z
Learning: Applies to **/*.mdx : Use Tabs/TabItem components for multi-language or multi-framework examples in MDX documentation

Applied to files:

  • src/content/docs/blog/building-custom-org-switcher.mdx
📚 Learning: 2026-01-13T12:48:11.566Z
Learnt from: CR
Repo: scalekit-inc/developer-docs PR: 0
File: .cursor/rules/documentation-guide.mdc:0-0
Timestamp: 2026-01-13T12:48:11.566Z
Learning: Applies to **/*.{md,mdx} : Structure documentation content with clear headings for better search understanding

Applied to files:

  • src/content/docs/blog/building-custom-org-switcher.mdx
📚 Learning: 2026-01-13T12:48:11.566Z
Learnt from: CR
Repo: scalekit-inc/developer-docs PR: 0
File: .cursor/rules/documentation-guide.mdc:0-0
Timestamp: 2026-01-13T12:48:11.566Z
Learning: Applies to **/*.{md,mdx} : Update code examples when APIs or behaviors change

Applied to files:

  • src/content/docs/blog/building-custom-org-switcher.mdx
📚 Learning: 2026-01-13T12:47:52.148Z
Learnt from: CR
Repo: scalekit-inc/developer-docs PR: 0
File: .cursor/rules/deno-docs-style.mdc:0-0
Timestamp: 2026-01-13T12:47:52.148Z
Learning: Applies to **/*.{md,mdx} : Start documentation pages with a one-paragraph overview explaining what the page covers and when to use it

Applied to files:

  • src/content/docs/blog/building-custom-org-switcher.mdx
🔇 Additional comments (2)
package.json (1)

51-51: No issues found. The dependency starlight-blog at version ^0.25.2 is the current release on npm and is designed as a Starlight plugin for Astro. Compatibility is appropriate for standard Astro/Starlight setups.

src/content.config.ts (1)

12-42: No validation concern: blogSchema fields are optional by design.

blogSchema(context) returns a .partial() schema from starlight-blog, making all blog-specific fields (date, authors, excerpt, cover, tags, featured) optional by default. Regular docs will validate correctly without providing blog metadata.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment on lines 94 to 99
starlightBlog({
metrics: {
readingTime: true,
words: 'total',
},
}),
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

starlight-blog plugin metrics options readingTime words configuration

💡 Result:

Do you want (A) how to enable/configure reading-time & word-count in the starlight-blog plugin, (B) the frontmatter fields the plugin exposes (e.g., readingTime / words), or (C) an example astro.config.mjs snippet?


🌐 Web query:

starlight-blog plugin documentation github npm metrics configuration

💡 Result:

Found the main resources and basic metrics/config notes for the starlight-blog plugin:

  • GitHub repo (source, README, issues): HiDeoo/starlight-blog. [1]
  • Official plugin docs / getting‑started (installation, usage, configuration notes — e.g. add starlightBlog to your Starlight plugins and configure in astro.config.mjs): Starlight Blog docs. [2]
  • Starlight ecosystem pages that list/describe the plugin and show example configuration behavior. [3][4]
  • npm / package metrics and versions: package published on npm (seen on CDN/registry listings); recent published versions reported (examples: 0.24.x → 0.25.x across registries); weekly download counts shown on registry/analysis pages. Use the npm/jsDelivr/registry pages for exact current version and download numbers. [5][6]

If you want, I can:

  • paste the exact installation + astro.config.mjs example from the docs,
  • fetch the current npm version and weekly downloads,
  • or open the GitHub README/issue list and extract configuration options (frontmatter fields, sidebar settings, authors/tags, RSS). Which would you like?

🌐 Web query:

starlight-blog astro.config.mjs configuration example metrics readingTime words

💡 Result:

Below is a concise astro.config.mjs example that enables Starlight with the starlight-blog plugin. The plugin automatically adds blog features (including UI labels like "Reading time" and word/reading-time metadata exposed by the blog components). Replace values as needed.

astro.config.mjs example

import { defineConfig } from 'astro/config';
import starlight from '@astrojs/starlight';
import starlightBlog from 'starlight-blog';

export default defineConfig({
  site: 'https://example.com', // required for RSS / feeds
  integrations: [
    starlight({
      title: 'My Docs + Blog',
      plugins: [
        starlightBlog({
          // optional blog options (authors, prefix, etc.)
          // authors: { alice: { name: 'Alice', picture:'/a.png' } },
          // prefix: '/blog'
        }),
      ],
      // other starlight options (sidebar, social, i18n, ...)
    }),
  ],
});

Notes

  • The plugin registers blog pages under your content folder (e.g. src/content/docs/blog/) and exposes post metadata such as word count and reading time through the blog components and localized UI strings (e.g. starlight-blog.readingTime). See the Starlight Blog docs and Starlight configuration reference for details and available plugin options. [1][2]

Sources

  • Starlight Blog docs (plugin usage & config). [1]
  • Starlight configuration / project structure reference. [2]

References
[1] Starlight Blog docs — starlight-blog.
[2] Starlight — Configuration & Project Structure.


🌐 Web query:

starlight-blog HiDeoo github plugin options configuration schema metrics

💡 Result:

Here are the authoritative places for starlight-blog plugin options, configuration schema (blogSchema) and related details (including RSS/metrics-related behavior):

  • GitHub repository (source, code, package): HiDeoo/starlight-blog. [1]
  • Official plugin docs — Getting Started (shows installation, how to configure in astro.config.mjs and how to use blogSchema in src/content.config.ts). [2]
  • RSS guide (explains RSS generation and the prefix/site options that affect feeds). [3]
  • HiDeoo Starlight plugin notes — guides on adding user configuration and extending Starlight frontmatter schema (Zod-based schemas) which the plugin uses (how to expose/extend blogSchema and validate options). [4][5]

References

  1. HiDeoo/starlight-blog (GitHub). [1]
  2. Starlight Blog — Getting Started (starlight-blog docs). [2]
  3. Starlight Blog — RSS guide. [3]
  4. HiDeoo — Add support for user configuration in a Starlight plugin. [4]
  5. HiDeoo — Extend Starlight’s frontmatter schema in a Starlight plugin. [5]

If you want, I can fetch the exact option names and the blogSchema shape from the repo/docs and show the configuration example and available metric-related options (RSS, pagination, sidebar settings, etc.). Which would you prefer?


🌐 Web query:

"starlight-blog" plugin configuration options "metrics" OR "readingTime" OR "words"

💡 Result:

Short answer: starlight-blog exposes/uses a readingTime value (with words) for posts; there’s an i18n key "starlight-blog.readingTime" and the plugin/page data includes readingTime/words (as typical reading-time plugins do). See the starlight-blog docs and repo. [1][2]

Sources:

  • starlight-blog docs / repo (plugin overview). [1]
  • Example i18n / component references showing "starlight-blog.readingTime" and words label. [2]

🌐 Web query:

starlight-blog plugin configuration options authors prefix site complete list

💡 Result:

Main starlight-blog plugin config options (common/explicitly documented):

  • title — blog title shown in UI. [1][2]
  • postCount — number of posts per blog page (pagination). [3]
  • recentPostCount — number of recent posts shown in sidebar. [3]
  • authors — object of author profiles (keyed IDs with name, title, picture, url, etc.). [3][4]
  • prefix — path prefix used for RSS/blog assets (RSS feed path can be customized with this). [2]
  • RSS/site integration — plugin generates RSS when Astro site is set; RSS placed at /blog/rss.xml by default (overridable via prefix). [2]

Sources / docs: Starlight Blog docs and examples, Starlight Starter reference, and the starlight-blog GitHub repo. [1][2][3][4]

Would you like the exact TypeScript/schema for every option (I can fetch and paste the plugin’s schema file)?

References:
[1] https://starlight-blog-docs.vercel.app/
[2] https://starlight-blog-docs.vercel.app/guides/rss/
[3] https://30daysof.github.io/astro-starlight-ghpages/ (example usage / config snippets)
[4] https://github.com/HiDeoo/starlight-blog


🌐 Web query:

"starlightBlog" configuration plugin options complete list github source code

💡 Result:

Here are the sources with the plugin configuration/options and the plugin source code:

  • GitHub repository (source code): HiDeoo/starlight-blog. [1]
  • Official plugin documentation (configuration/options reference and examples): Starlight Blog docs. [2]

References

  1. HiDeoo / starlight-blog — GitHub repository. [https://github.com/HiDeoo/starlight-blog]
  2. Starlight Blog documentation — Configuration / Options. [https://www.starlightstarter.com/documentation/options/blog/ ]

🏁 Script executed:

#!/bin/bash
# Search for starlight-blog configuration schema or type definitions
curl -s https://raw.githubusercontent.com/HiDeoo/starlight-blog/main/package.json | head -20

Repository: scalekit-inc/developer-docs

Length of output: 794


🏁 Script executed:

#!/bin/bash
# Search for configuration options in starlight-blog source
curl -s https://raw.githubusercontent.com/HiDeoo/starlight-blog/main/packages/starlight-blog/src/index.ts | head -100

Repository: scalekit-inc/developer-docs

Length of output: 85


🏁 Script executed:

#!/bin/bash
# Try to find the starlight-blog plugin schema from the GitHub repo
curl -s https://api.github.com/repos/HiDeoo/starlight-blog/contents/packages/starlight-blog/src | jq -r '.[] | select(.name | contains("config") or contains("schema")) | .download_url' | head -5

Repository: scalekit-inc/developer-docs

Length of output: 135


🏁 Script executed:

#!/bin/bash
# Search for starlight-blog configuration schema in the repo
curl -s https://api.github.com/repos/HiDeoo/starlight-blog/contents/packages/starlight-blog/src | head -50

Repository: scalekit-inc/developer-docs

Length of output: 211


🌐 Web query:

starlight-blog plugin starlightBlog function parameters options interface

💡 Result:

Summary — API surface

  • Function signature: starlightBlog(userConfig?: StarlightBlogUserConfig): StarlightPlugin. [1][2]

Main user-config (options) you can pass (names used in docs / source):

  • prefix: string — URL prefix for the blog (e.g. "blog"). [1]
  • title: string | Record<string,string> — blog title (string or localized map). [1][2]
  • postCount: number — posts per page (default shown as 5 in docs). [1][4]
  • recentPostCount: number — number of recent posts shown in sidebar. [4]
  • authors: Record<id, { name, title?, picture?, url? }> — global author definitions. [1][4]
  • navigation: 'header-start' | 'header-end' | other — controls where blog modifies header/navigation and whether custom CSS is injected. [2]
  • prefix (RSS/paths) and related path controls are used to generate RSS and routes. [2]
  • frontmatter: object — global defaults / overrides for per-post frontmatter (examples: prev/next booleans to disable prev/next links). [4]
  • featured / featuredPost handling, tags, cover, excerpt, draft — handled via post frontmatter (see schema). [3]

Schema / per-post frontmatter fields (via exported blogSchema / types):

  • authors (string | author object | array), date (Date), excerpt (string), tags (string[]), cover ({ image, alt } or { light, dark, alt }), featured (boolean), draft (boolean). See blogSchema and blogAuthorSchema. [3]

Notes from source code:

  • The plugin validates userConfig via validateConfig and returns a StarlightPlugin that registers routes (Blog, Tags, Authors), RSS (when astro site is set), remark plugin, component overrides and Vite plugin. Exported types StarlightBlogConfig and StarlightBlogUserConfig are re-exported. [2]

Primary references

  • Starlight Blog docs (Getting Started / options). [1]
  • starlight-blog source (index.ts on unpkg) — function signature, route/integration behavior and config handling. [2]
  • starlight-blog schema.ts — blogSchema and frontmatter field types. [3]
  • Community/how-to examples describing postCount, authors, frontmatter usage. [4]

If you want, I can paste the exact TypeScript type for StarlightBlogUserConfig (from the lib/config file) or open the specific version of the package you use and extract the precise interface. Which version are you using?


🌐 Web query:

starlight-blog starlightBlog function parameters do not include metrics configuration

💡 Result:

You're seeing that error because starlightBlog() (the Starlight Blog plugin) does not accept a top-level "metrics" configuration — blog-specific options are handled by the plugin, while site-wide integrations (analytics/metrics) are configured on the Starlight integration or via a separate analytics plugin. See the plugin docs which show starlightBlog is added under starlight(...) plugins, and the Starlight integration docs for global config; PostHog is an example of an analytics option added at the Starlight/integration level. [1][2][3]

What to do

  • Remove any metrics option passed directly to starlightBlog(...). Configure metrics/analytics at the starlight(...) integration level or using a dedicated analytics plugin (e.g., PostHog via Starlight’s integration). [1][2][3]

References

  • Starlight Blog (plugin) docs — installation/config pattern (plugins live inside starlight({... plugins: [starlightBlog()] })). [1]
  • Starlight Blog getting-started / configuration details. [2]
  • Example analytics (PostHog) added via Starlight integration. [3]

Remove invalid metrics configuration from starlightBlog() plugin options.

The starlightBlog() function does not accept a metrics configuration option. Reading time and word count are automatically computed and exposed as post metadata through the plugin's frontmatter schema and blog components. Remove the entire metrics object from the configuration.

The valid starlightBlog() options are: prefix, title, postCount, recentPostCount, authors, navigation, and frontmatter.

🤖 Prompt for AI Agents
In `@astro.config.mjs` around lines 94 - 99, Remove the invalid metrics option
from the starlightBlog() call: open the configuration where starlightBlog(...)
is invoked and delete the entire metrics: { readingTime: true, words: 'total' }
object so the plugin options only use supported keys (prefix, title, postCount,
recentPostCount, authors, navigation, frontmatter); ensure no other code relies
on that removed option since reading time and word count are provided
automatically via post metadata/frontmatter.

Comment on lines 511 to 515
export const exclude = [
'/', // Home page
'/blog',
'/404', // Error page
'/apis/**/*', // REST API reference has Scalar-powered navigation
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Exclude the entire blog subtree, not just /blog.

/blog alone may not match /blog/... pages in glob-based matching. Consider using /blog/** to ensure all blog posts are excluded from topic navigation.

🔧 Suggested fix
 export const exclude = [
   '/', // Home page
-  '/blog',
+  '/blog/**',
   '/404', // Error page
   '/apis/**/*', // REST API reference has Scalar-powered navigation
 ]
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const exclude = [
'/', // Home page
'/blog',
'/404', // Error page
'/apis/**/*', // REST API reference has Scalar-powered navigation
export const exclude = [
'/', // Home page
'/blog/**',
'/404', // Error page
'/apis/**/*', // REST API reference has Scalar-powered navigation
]
🤖 Prompt for AI Agents
In `@src/configs/sidebar.config.ts` around lines 511 - 515, The exclude array
(export const exclude) currently lists '/blog' which may not match nested blog
pages; update the pattern in the exclude array to use a recursive glob (e.g.,
replace '/blog' with '/blog/**') so the entire blog subtree is excluded by the
glob matcher, and keep the existing '/apis/**/*' style consistent with other
entries.

Comment on lines +47 to +103
<Tabs>
<TabItem value="node" label="Node.js">
```javascript title="Express.js"
// Use case: Get user's organizations for your switcher UI
// Security: Always validate session ownership before returning org data
const session = await scalekit.session.getSession(sessionId);

// Extract organizations from the session response
const organizations = session.authenticated_organizations || [];

// Render your organization switcher with this data
res.json({ organizations });
```
</TabItem>
<TabItem value="python" label="Python">
```python title="Flask"
# Use case: Get user's organizations for your switcher UI
# Security: Always validate session ownership before returning org data
session = scalekit_client.session.get_session(session_id)

# Extract organizations from the session response
organizations = session.get('authenticated_organizations', [])

# Render your organization switcher with this data
return jsonify({'organizations': organizations})
```
</TabItem>
<TabItem value="go" label="Go">
```go title="Gin"
// Use case: Get user's organizations for your switcher UI
// Security: Always validate session ownership before returning org data
session, err := scalekitClient.Session().GetSession(ctx, sessionId)
if err != nil {
return err
}

// Extract organizations from the session response
organizations := session.AuthenticatedOrganizations

// Render your organization switcher with this data
c.JSON(http.StatusOK, gin.H{"organizations": organizations})
```
</TabItem>
<TabItem value="java" label="Java">
```java title="Spring"
// Use case: Get user's organizations for your switcher UI
// Security: Always validate session ownership before returning org data
Session session = scalekitClient.sessions().getSession(sessionId);

// Extract organizations from the session response
List<Organization> organizations = session.getAuthenticatedOrganizations();

// Render your organization switcher with this data
return ResponseEntity.ok(Map.of("organizations", organizations));
```
</TabItem>
</Tabs>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Use <Tabs syncKey="tech-stack"> for multi-language examples.

Both Tabs blocks should include syncKey="tech-stack" so language selection stays consistent across pages. This is required for MDX multi-language examples. Based on learnings, ...

🔧 Suggested update
-<Tabs>
+<Tabs syncKey="tech-stack">

Also applies to: 124-243

🤖 Prompt for AI Agents
In `@src/content/docs/blog/building-custom-org-switcher.mdx` around lines 47 -
103, Add the required syncKey attribute to the Tabs components so language
selection remains consistent: locate the Tabs elements (the top-level Tabs
component wrapping the TabItem blocks in this file) and add syncKey="tech-stack"
to each Tabs instance (the TabItem components remain unchanged); ensure both
Tabs blocks on the page use the identical syncKey value "tech-stack" so
multi-language examples stay synchronized across pages.

- Updated the Astro configuration to include a prefix for the starlight-blog integration, enhancing the organization of blog content under the 'cookbooks' category. This change aims to improve navigation and content discoverability for users.
- Changed the sidebar configuration to exclude the '/blog' path and include '/cookbooks' for improved navigation.
- Introduced a new guide titled "Building a Custom Organization Switcher," detailing how to create a custom organization switcher UI using Scalekit's APIs, enhancing user experience for multi-tenant applications.
- The guide includes step-by-step instructions, code examples in multiple languages, and best practices for managing organization context.
@saif-at-scalekit saif-at-scalekit changed the title POC: Blog style listing in the docs POC: Cookbook style listing in the docs Jan 22, 2026
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

♻️ Duplicate comments (1)
src/configs/sidebar.config.ts (1)

522-527: ⚠️ Potential issue | 🟡 Minor

/cookbooks won't match sub-pages — same glob issue as the prior /blog comment.

The entry /cookbooks will only exclude the exact path /cookbooks; any article page like /cookbooks/building-custom-org-switcher will still be picked up by the topic sidebar. The fix is the same as suggested for /blog:

🔧 Proposed fix
 export const exclude = [
   '/', // Home page
-  '/cookbooks',
+  '/cookbooks/**',
   '/404', // Error page
   '/apis/**/*', // REST API reference has Scalar-powered navigation
 ]
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/configs/sidebar.config.ts` around lines 522 - 527, The exclude array
entry for cookbooks currently only matches the exact path '/cookbooks' so nested
pages (e.g., '/cookbooks/building-custom-org-switcher') still appear; update the
exclude entry in the exclude constant (in src/configs/sidebar.config.ts) to use
a glob that matches subpaths (for example change '/cookbooks' to a recursive
glob like '/cookbooks/**/*') so all cookbook sub-pages are excluded from the
topic sidebar.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/content/docs/cookbooks/implement-nextjs-auth.mdx`:
- Line 2: Update the title frontmatter string "Implementing Passwordless Auth in
Next.js 15" to sentence case by lowercasing non-proper nouns—e.g., change it to
"Implementing passwordless auth in Next.js 15" (or "Implementing passwordless
authentication in Next.js 15" if you prefer the full word) so the title follows
the sentence-case guideline; modify the title value where it's defined in the
document header.
- Around line 280-295: The middleware currently only checks for the presence of
a 'session' cookie in middleware(req) which allows expired or tampered JWTs;
update middleware to validate the JWT before allowing access by calling the
existing readSessionEmail utility (or invoking jwt.verify) with the cookie value
and rejecting if verification fails or token is expired; keep the same redirect
behavior (create URL('/login', req.url) and set next param) when verification
fails, and return NextResponse.next() only when readSessionEmail/jwt.verify
confirms a valid session; reference middleware, readSessionEmail, jwt.verify,
NextRequest, and NextResponse in your changes.
- Around line 88-121: The three session helper functions (createSession,
readSessionEmail, clearSession) must be converted to async functions and call
await cookies() (since cookies() returns a Promise in Next.js 15); update
createSession to await cookies() before .set, update readSessionEmail to await
cookies() before .get and keep the jwt.verify try/catch, and update clearSession
to await cookies() before .delete. Also update any route handlers or callers to
await createSession and clearSession (and await readSessionEmail where used) so
callers handle the async nature.

In `@src/content/docs/cookbooks/java-spring-boot-jwt-timeout.mdx`:
- Line 52: The sentence uses "timeout" as a verb; update the phrase "If these
initial requests timeout, authentication fails completely." to use the phrasal
verb "time out" by replacing "timeout" with "time out" so it reads "If these
initial requests time out, authentication fails completely."; locate this text
in the Java Spring Boot JWT timeout cookbook (the line containing that sentence)
and make the single-word replacement.
- Line 2: The document title uses Title Case; change it to sentence case so
non-proper nouns are lowercase—update the title string "Configuring JWT
Validation Timeouts in Spring Boot 4.0+" to "Configuring JWT validation timeouts
in Spring Boot 4.0+" (modify the frontmatter/title line that currently contains
the title).
- Around line 73-97: Remove the misleading YAML/properties timeout entries under
spring.security.oauth2.resourceserver.jwt (the application.yml and
application.properties TabItems) and add a clear caveat noting these properties
are ignored in Spring Boot 4 / Spring Security 7; instead, reference and
recommend the programmatic approach shown in the doc (the NimbusJwtDecoder +
custom RestOperations example around the existing "NimbusJwtDecoder" /
"RestOperations" code in lines ~112–138) and instruct readers to configure
timeouts via a custom RestTemplate/HttpClient or WebClient passed into
NimbusJwtDecoder rather than via declarative properties.

---

Duplicate comments:
In `@src/configs/sidebar.config.ts`:
- Around line 522-527: The exclude array entry for cookbooks currently only
matches the exact path '/cookbooks' so nested pages (e.g.,
'/cookbooks/building-custom-org-switcher') still appear; update the exclude
entry in the exclude constant (in src/configs/sidebar.config.ts) to use a glob
that matches subpaths (for example change '/cookbooks' to a recursive glob like
'/cookbooks/**/*') so all cookbook sub-pages are excluded from the topic
sidebar.

ℹ️ Review info

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ad5b7c7 and 6902c35.

📒 Files selected for processing (4)
  • src/configs/sidebar.config.ts
  • src/content/docs/cookbooks/building-custom-org-switcher.mdx
  • src/content/docs/cookbooks/implement-nextjs-auth.mdx
  • src/content/docs/cookbooks/java-spring-boot-jwt-timeout.mdx
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/content/docs/cookbooks/building-custom-org-switcher.mdx
📜 Review details
🧰 Additional context used
📓 Path-based instructions (6)
**/*.mdx

📄 CodeRabbit inference engine (.cursorrules)

**/*.mdx: Use clear, descriptive titles that explain the purpose of the document
Include comprehensive descriptions in frontmatter metadata
Organize content with logical heading hierarchy (H2, H3, H4)
Use tableOfContents property in frontmatter when content has multiple sections
Set appropriate sidebar labels for navigation in frontmatter
Use direct instruction writing style with phrases like 'This guide shows you how to...' and 'Create an authorization URL to...'
Use second person perspective ('your application', 'you receive', 'you must') in documentation
Keep sentences concise, aiming for under 25 words per sentence
Explain the 'why' in documentation with phrases like 'This prevents CSRF attacks by...' or 'Use this to validate that...'
Use action verbs in section headings: 'Store session tokens securely', 'Validate the state parameter', 'Exchange authorization code for tokens'
Use present tense for descriptions: 'Scalekit handles the complex authentication flow', 'The SDK provides methods to refresh tokens'
Use future tense for results: 'This will redirect users to...', 'You'll receive a JWT containing...', 'Scalekit returns an authorization code'
Use transition phrases between sections: 'After the user authenticates...', 'Once the state is validated...', 'Let's take a look at how to...'
Write 1-3 opening paragraphs that explain what users will accomplish, provide context about when/why, preview key concepts, and use direct instructional language
Begin introduction sections with a clear statement of what the guide covers and explain the problem being solved
Use collapsible sections in introduction for sequence diagrams, video demonstrations, data models, and JSON examples with appropriate icons
Use numbered format within Steps component: 1. ## Title with all step content indented with exactly 3 spaces
Use action-oriented headings in step-by-step guides within Steps components
Include code examples in all 4 languages (Node.js, Python, Go, Java) within Steps co...

Files:

  • src/content/docs/cookbooks/java-spring-boot-jwt-timeout.mdx
  • src/content/docs/cookbooks/implement-nextjs-auth.mdx
**/*.{yml,yaml,md,mdx}

📄 CodeRabbit inference engine (.cursor/rules/browsecentral-labels.mdc)

**/*.{yml,yaml,md,mdx}: BrowseCentral labels should be maximum 3-5 words - keep concise but add context when needed
BrowseCentral labels should be action-oriented - start with verbs when possible
BrowseCentral labels should be specific and clear - add context when simple labels are ambiguous
BrowseCentral labels should be outcome-focused - describe what users accomplish and the context
BrowseCentral labels should use 'Action + Object' pattern (e.g., 'Invite users', 'Restrict sign-up', 'Set up SCIM')
BrowseCentral labels should use feature names (e.g., 'Enterprise SSO', 'Passwordless quickstart')
BrowseCentral labels should describe task completion (e.g., 'Run migrations', 'Migrate auth', 'Merge identities')
BrowseCentral labels should include specific context when needed (e.g., 'Configure Scalekit MCP server', 'Validate incoming API requests')
BrowseCentral labels should use integration context when applicable (e.g., 'Build MCP auth with your existing auth system')
BrowseCentral labels should avoid instructional prefixes: 'How to', 'Guide to', 'Implement', 'Configure', 'Learn', 'Understand'
BrowseCentral labels should avoid verbose phrases: 'Step-by-step guide', 'Complete tutorial', 'Detailed documentation'
BrowseCentral labels should avoid weak verbs: 'Enable', 'Allow', 'Provide', 'Support'

Files:

  • src/content/docs/cookbooks/java-spring-boot-jwt-timeout.mdx
  • src/content/docs/cookbooks/implement-nextjs-auth.mdx
**/*.{md,mdx}

📄 CodeRabbit inference engine (.cursor/rules/deno-docs-style.mdc)

**/*.{md,mdx}: Use sentence case for all titles and headings in MD/MDX documentation
Keep page titles short and descriptive (3–7 words when possible) in MD/MDX documentation
Use outcome-focused headings that describe results, not categories (e.g., 'Run a script' not 'Scripts')
Avoid gerunds in headings when an imperative works - prefer 'Configure proxies' over 'Configuring proxies'
Keep sidebar labels concise (1–3 words), use sentence case, and focus on outcomes or objects
Use sentence case in sidebar labels without punctuation
Set frontmatter title in sentence case with a clear outcome; description in one sentence (≤160 chars); sidebar.label as shorter form of title; enable tableOfContents on longer pages
Start documentation pages with a one-paragraph overview explaining what the page covers and when to use it
Present the primary use case (80% path) first in documentation, with edge cases later
Use numbered steps for task-focused sections in documentation, with each step beginning with a verb
Break up long documentation sections with subheadings every 3–6 paragraphs
Use asides for important notes, tips, cautions, and references in documentation
Provide runnable, minimal code examples that work as-is in documentation
Prefer CLI-first examples and show file layout when helpful in documentation
Label code blocks with titles for context (e.g., 'Terminal', 'main.ts') in documentation
Keep code block annotations brief and purposeful - annotate only what matters
Use consistent variable and file names across a documentation page
Use descriptive link text in documentation (e.g., 'See permission flags' not 'click here')
Prefer relative links for internal documentation pages and include anchors for section references
Reference APIs consistently using backticks for code, file names, CLI flags, and endpoints
Use backticks for code, file names, CLI flags, and endpoints in documentation
Use lists for options and features in documentation; tables only when comparisons are cleare...

Files:

  • src/content/docs/cookbooks/java-spring-boot-jwt-timeout.mdx
  • src/content/docs/cookbooks/implement-nextjs-auth.mdx
**/*.{js,ts,tsx,jsx,py,java,cs,go,cpp,c,rb,php,swift,kt,scala,rs,m,mm,groovy,gradle,xml,json}

📄 CodeRabbit inference engine (.cursor/rules/comment-standards.mdc)

Comments should not duplicate the code - avoid comments that simply restate what the code does; comments should add value beyond what's obvious from reading the code

Files:

  • src/configs/sidebar.config.ts
**/*.{js,ts,tsx,jsx,py,java,cs,go,cpp,c,rb,php,swift,kt,scala,rs,m,mm,groovy}

📄 CodeRabbit inference engine (.cursor/rules/comment-standards.mdc)

**/*.{js,ts,tsx,jsx,py,java,cs,go,cpp,c,rb,php,swift,kt,scala,rs,m,mm,groovy}: Good comments do not excuse unclear code - refactor the code to be self-explanatory instead of using comments to explain poorly written code; use better variable names, function names, and code structure
Comments should dispel confusion, not cause it - ensure comments clarify rather than obscure the code's purpose; avoid cryptic or joke comments
Explain unidiomatic code in comments - comment on code that might seem unnecessary or redundant and document why you chose a specific pattern over more common alternatives, especially when it deviates from team conventions
Provide links to the original source of copied code - always attribute code copied from external sources with URLs to Stack Overflow answers, GitHub repositories, or documentation
Include links to external references where helpful - reference standards, RFCs, and official documentation; link to relevant specifications when implementing protocols
Add comments when fixing bugs - document bug fixes with context about the issue, reference issue trackers and bug reports, and explain workarounds and their limitations
Use comments to mark incomplete implementations - use standard formats for TODO, FIXME, and NOTE comments with context about what needs to be done and reference issue trackers when possible
Always document public APIs with function/class comments - explain the purpose, parameters, return values, and exceptions; include usage examples for complex functions
Include file headers with copyright information, license, and authorship - provide a brief description of the file's purpose and document dependencies and requirements

Files:

  • src/configs/sidebar.config.ts
**/*.{js,ts,tsx,jsx}

📄 CodeRabbit inference engine (.cursor/rules/comment-standards.mdc)

Use JSDoc standards for all function, class, and complex logic comments in JavaScript/TypeScript - include parameter descriptions (@param), return values (@returns), types (@type), and descriptions; document exceptions and edge cases

Files:

  • src/configs/sidebar.config.ts
🧠 Learnings (17)
📚 Learning: 2026-01-30T18:18:50.883Z
Learnt from: AkshayParihar33
Repo: scalekit-inc/developer-docs PR: 415
File: src/content/docs/authenticate/fsa/multiapp/manage-apps.mdx:31-49
Timestamp: 2026-01-30T18:18:50.883Z
Learning: In all Scalekit documentation files (MDX), treat the terms 'Applications', 'Single Page Application (SPA)', 'Native Application', and 'Web Application' as proper nouns and preserve their capitalization in headings and body text. Ensure these terms remain capitalized even when used in sentence case or within prose.

Applied to files:

  • src/content/docs/cookbooks/java-spring-boot-jwt-timeout.mdx
  • src/content/docs/cookbooks/implement-nextjs-auth.mdx
📚 Learning: 2026-02-04T12:47:16.544Z
Learnt from: saif-at-scalekit
Repo: scalekit-inc/developer-docs PR: 412
File: src/content/docs/dev-kit/tools/scalekit-dryrun.mdx:1-23
Timestamp: 2026-02-04T12:47:16.544Z
Learning: In scalekit-inc/developer-docs, the MDX frontmatter field order is required only when the sidebar configuration points to a directory (for auto-generation). If the sidebar.config.ts references a specific file path, the order field is not required. Apply this check to all MDX files under src/content/docs: if a file contributes to an auto-generated sidebar (directory path), ensure order is present; if it’s linked to a concrete file, order can be omitted. Use sidebar.config.ts to determine whether a given MDX file falls under directory-based vs file-specific sidebar references.

Applied to files:

  • src/content/docs/cookbooks/java-spring-boot-jwt-timeout.mdx
  • src/content/docs/cookbooks/implement-nextjs-auth.mdx
📚 Learning: 2026-02-02T05:55:51.251Z
Learnt from: AkshayParihar33
Repo: scalekit-inc/developer-docs PR: 415
File: src/content/docs/authenticate/fsa/multiapp/native-app.mdx:72-179
Timestamp: 2026-02-02T05:55:51.251Z
Learning: In the `src/content/docs/authenticate/fsa/multiapp/` directory, the multi-app authentication documentation (native-app.mdx, single-page-app.mdx, web-app.mdx, overview.mdx) currently uses conceptual shell/curl examples instead of multi-language SDK code examples because the Scalekit SDKs have not yet been built/updated for multi-app functionality. Once the SDKs are ready, these files should be updated to include all 4 languages (Node.js, Python, Go, Java) using `<Tabs syncKey="tech-stack">`.

Applied to files:

  • src/content/docs/cookbooks/implement-nextjs-auth.mdx
📚 Learning: 2026-01-13T12:46:55.260Z
Learnt from: CR
Repo: scalekit-inc/developer-docs PR: 0
File: .cursorrules:0-0
Timestamp: 2026-01-13T12:46:55.260Z
Learning: Applies to **/*.mdx : Use present tense for descriptions: 'Scalekit handles the complex authentication flow', 'The SDK provides methods to refresh tokens'

Applied to files:

  • src/content/docs/cookbooks/implement-nextjs-auth.mdx
📚 Learning: 2026-01-30T18:20:07.851Z
Learnt from: AkshayParihar33
Repo: scalekit-inc/developer-docs PR: 415
File: src/content/docs/authenticate/fsa/multiapp/native-app.mdx:1-6
Timestamp: 2026-01-30T18:20:07.851Z
Learning: In the scalekit-inc/developer-docs repository, MDX files under `src/content/docs/authenticate/fsa/multiapp/` do not use `order` or `tags` fields in their frontmatter. Ordering and grouping are managed centrally in `src/configs/sidebar.config.ts`.

Applied to files:

  • src/content/docs/cookbooks/implement-nextjs-auth.mdx
📚 Learning: 2026-01-13T12:46:55.260Z
Learnt from: CR
Repo: scalekit-inc/developer-docs PR: 0
File: .cursorrules:0-0
Timestamp: 2026-01-13T12:46:55.260Z
Learning: Applies to **/*.mdx : Include context comments explaining what's happening in code: '// Extract encrypted tokens from request cookies', '// Decrypt the access token before validation'

Applied to files:

  • src/content/docs/cookbooks/implement-nextjs-auth.mdx
📚 Learning: 2026-01-13T12:46:55.260Z
Learnt from: CR
Repo: scalekit-inc/developer-docs PR: 0
File: .cursorrules:0-0
Timestamp: 2026-01-13T12:46:55.260Z
Learning: Applies to **/*.mdx : Include configuration comments in code examples: '// Get the signing secret from Scalekit dashboard > Interceptors tab'

Applied to files:

  • src/content/docs/cookbooks/implement-nextjs-auth.mdx
📚 Learning: 2026-01-13T12:46:55.260Z
Learnt from: CR
Repo: scalekit-inc/developer-docs PR: 0
File: .cursorrules:0-0
Timestamp: 2026-01-13T12:46:55.260Z
Learning: Applies to **/*.mdx : Use future tense for results: 'This will redirect users to...', 'You'll receive a JWT containing...', 'Scalekit returns an authorization code'

Applied to files:

  • src/content/docs/cookbooks/implement-nextjs-auth.mdx
📚 Learning: 2026-01-13T12:46:55.260Z
Learnt from: CR
Repo: scalekit-inc/developer-docs PR: 0
File: .cursorrules:0-0
Timestamp: 2026-01-13T12:46:55.260Z
Learning: Applies to **/*.mdx : Include todo/next step comments in code examples: '// TODO: Store user session (next guide covers this)', '// Next step: Create a session and log in the user'

Applied to files:

  • src/content/docs/cookbooks/implement-nextjs-auth.mdx
📚 Learning: 2026-01-13T12:46:55.260Z
Learnt from: CR
Repo: scalekit-inc/developer-docs PR: 0
File: .cursorrules:0-0
Timestamp: 2026-01-13T12:46:55.260Z
Learning: Applies to **/*.mdx : Always include security comments in security-related code with pattern: '// Security: ALWAYS verify requests are from Scalekit before processing'

Applied to files:

  • src/content/docs/cookbooks/implement-nextjs-auth.mdx
📚 Learning: 2026-01-13T12:46:55.260Z
Learnt from: CR
Repo: scalekit-inc/developer-docs PR: 0
File: .cursorrules:0-0
Timestamp: 2026-01-13T12:46:55.260Z
Learning: Applies to **/*.mdx : Use transition phrases between sections: 'After the user authenticates...', 'Once the state is validated...', 'Let's take a look at how to...'

Applied to files:

  • src/content/docs/cookbooks/implement-nextjs-auth.mdx
📚 Learning: 2026-01-13T12:47:52.148Z
Learnt from: CR
Repo: scalekit-inc/developer-docs PR: 0
File: .cursor/rules/deno-docs-style.mdc:0-0
Timestamp: 2026-01-13T12:47:52.148Z
Learning: Applies to **/*.{md,mdx} : Avoid trailing punctuation in navigation labels and avoid emojis and exclamation marks

Applied to files:

  • src/configs/sidebar.config.ts
📚 Learning: 2026-01-13T12:48:11.566Z
Learnt from: CR
Repo: scalekit-inc/developer-docs PR: 0
File: .cursor/rules/documentation-guide.mdc:0-0
Timestamp: 2026-01-13T12:48:11.566Z
Learning: Applies to **/*.{md,mdx} : Set concise sidebar labels that match user vocabulary in navigation metadata

Applied to files:

  • src/configs/sidebar.config.ts
📚 Learning: 2026-01-13T12:48:11.566Z
Learnt from: CR
Repo: scalekit-inc/developer-docs PR: 0
File: .cursor/rules/documentation-guide.mdc:0-0
Timestamp: 2026-01-13T12:48:11.566Z
Learning: Applies to **/*.{md,mdx} : Don't skip important context or prerequisites in documentation

Applied to files:

  • src/configs/sidebar.config.ts
📚 Learning: 2026-01-13T12:48:11.566Z
Learnt from: CR
Repo: scalekit-inc/developer-docs PR: 0
File: .cursor/rules/documentation-guide.mdc:0-0
Timestamp: 2026-01-13T12:48:11.566Z
Learning: Applies to **/*.mdx : Use consistent import paths with the `@/` prefix in MDX files

Applied to files:

  • src/configs/sidebar.config.ts
📚 Learning: 2026-01-13T12:47:52.148Z
Learnt from: CR
Repo: scalekit-inc/developer-docs PR: 0
File: .cursor/rules/deno-docs-style.mdc:0-0
Timestamp: 2026-01-13T12:47:52.148Z
Learning: Applies to **/*.{md,mdx} : Keep sidebar labels concise (1–3 words), use sentence case, and focus on outcomes or objects

Applied to files:

  • src/configs/sidebar.config.ts
📚 Learning: 2026-01-13T12:48:11.566Z
Learnt from: CR
Repo: scalekit-inc/developer-docs PR: 0
File: .cursor/rules/documentation-guide.mdc:0-0
Timestamp: 2026-01-13T12:48:11.566Z
Learning: Applies to **/*.{md,mdx} : Don't use inconsistent terminology across documentation pages

Applied to files:

  • src/configs/sidebar.config.ts
🪛 LanguageTool
src/content/docs/cookbooks/java-spring-boot-jwt-timeout.mdx

[grammar] ~52-~52: Ensure spelling is correct
Context: ... validations If these initial requests timeout, authentication fails completely. ## W...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

@@ -0,0 +1,431 @@
---
title: 'Implementing Passwordless Auth in Next.js 15'
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Title violates sentence-case guideline.

"Passwordless" and "Auth" are not proper nouns and should be lowercase.

🔧 Proposed fix
-title: 'Implementing Passwordless Auth in Next.js 15'
+title: 'Implementing passwordless auth in Next.js 15'
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
title: 'Implementing Passwordless Auth in Next.js 15'
title: 'Implementing passwordless auth in Next.js 15'
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/content/docs/cookbooks/implement-nextjs-auth.mdx` at line 2, Update the
title frontmatter string "Implementing Passwordless Auth in Next.js 15" to
sentence case by lowercasing non-proper nouns—e.g., change it to "Implementing
passwordless auth in Next.js 15" (or "Implementing passwordless authentication
in Next.js 15" if you prefer the full word) so the title follows the
sentence-case guideline; modify the title value where it's defined in the
document header.

Comment on lines +88 to +121
```typescript
import jwt from 'jsonwebtoken';
import { cookies } from 'next/headers';

const COOKIE = 'session';
const SECRET = process.env.JWT_SECRET!;

export function createSession(email: string) {
const token = jwt.sign({ email }, SECRET, { expiresIn: '7d' });
cookies().set(COOKIE, token, {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
sameSite: 'lax',
path: '/',
maxAge: 60 * 60 * 24 * 7,
});
}

export function readSessionEmail(): string | null {
const token = cookies().get(COOKIE)?.value;
if (!token) return null;

try {
const decoded = jwt.verify(token, SECRET) as { email: string };
return decoded.email;
} catch {
return null;
}
}

export function clearSession() {
cookies().delete(COOKIE);
}
```
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

Next.js 15 cookies() async API breaking changes

💡 Result:

Next.js 15 cookies() async API — breaking changes

  • cookies() is now async and returns a Promise (it used to be synchronous in Next.js ≤14). You must await cookies() (or use React’s use() in Server Components). [1][3][2]

    // Before (<=14)
    const cookieStore = cookies()
    const token = cookieStore.get('token')
    
    // After (15)
    const cookieStore = await cookies()
    const token = cookieStore.get('token')
  • Transitional compatibility exists in Next.js 15, but it’s temporary: you can still access cookies synchronously by casting to UnsafeUnwrappedCookies, but it warns in dev and is meant only to ease migration. [1][3]

    import { cookies, type UnsafeUnwrappedCookies } from 'next/headers'
    
    const cookieStore = cookies() as unknown as UnsafeUnwrappedCookies // warns in dev
  • Synchronous access can become an error in some modes: Next.js 15 may throw when request APIs are used synchronously (notably when cacheComponents is enabled), even though the promise-proxy exists for migration. [4]

  • Migration support: the upgrade codemod can auto-convert many call sites (and leaves @next-codemod-error markers where it can’t). [1][4]

  • Heads-up: Next.js 16 fully removes synchronous compatibilitycookies() (and similar request APIs) are async-only. [5]

Sources: Next.js v15 upgrade guide [1], Next.js 15 announcement [2], cookies() API docs [3], Next.js error reference [4], Next.js v16 upgrade guide [5].


🏁 Script executed:

cat -n src/content/docs/cookbooks/implement-nextjs-auth.mdx | sed -n '85,125p'

Repository: scalekit-inc/developer-docs

Length of output: 1296


cookies() is async in Next.js 15—update all three session utilities to use await.

cookies() returns a Promise in Next.js 15 (it was synchronous in v14 and earlier). The current code will warn in development and fail in production, especially when cacheComponents is enabled. Since this cookbook targets Next.js 15, update createSession, readSessionEmail, and clearSession to be async functions with await cookies(). Call sites in route handlers must also await these functions.

Proposed fix for `lib/session-store.ts`
-export function createSession(email: string) {
-  const token = jwt.sign({ email }, SECRET, { expiresIn: '7d' });
-  cookies().set(COOKIE, token, {
+export async function createSession(email: string) {
+  const token = jwt.sign({ email }, SECRET, { expiresIn: '7d' });
+  const cookieStore = await cookies();
+  cookieStore.set(COOKIE, token, {
     httpOnly: true,
     secure: process.env.NODE_ENV === 'production',
     sameSite: 'lax',
     path: '/',
     maxAge: 60 * 60 * 24 * 7,
   });
 }

-export function readSessionEmail(): string | null {
-  const token = cookies().get(COOKIE)?.value;
+export async function readSessionEmail(): Promise<string | null> {
+  const cookieStore = await cookies();
+  const token = cookieStore.get(COOKIE)?.value;
   if (!token) return null;
   try {
     const decoded = jwt.verify(token, SECRET) as { email: string };
     return decoded.email;
   } catch {
     return null;
   }
 }

-export function clearSession() {
-  cookies().delete(COOKIE);
+export async function clearSession() {
+  const cookieStore = await cookies();
+  cookieStore.delete(COOKIE);
 }

Update the route handlers that call createSession and clearSession to await them.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/content/docs/cookbooks/implement-nextjs-auth.mdx` around lines 88 - 121,
The three session helper functions (createSession, readSessionEmail,
clearSession) must be converted to async functions and call await cookies()
(since cookies() returns a Promise in Next.js 15); update createSession to await
cookies() before .set, update readSessionEmail to await cookies() before .get
and keep the jwt.verify try/catch, and update clearSession to await cookies()
before .delete. Also update any route handlers or callers to await createSession
and clearSession (and await readSessionEmail where used) so callers handle the
async nature.

Comment on lines +280 to +295
export function middleware(req: NextRequest) {
const protectedPath = req.nextUrl.pathname.startsWith('/dashboard');
const hasSession = Boolean(req.cookies.get('session')?.value);

if (protectedPath && !hasSession) {
const url = new URL('/login', req.url);
url.searchParams.set('next', req.nextUrl.pathname);
return NextResponse.redirect(url);
}

return NextResponse.next();
}

export const config = {
matcher: ['/dashboard/:path*'],
};
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Middleware validates cookie presence only — not JWT signature or expiry.

The check Boolean(req.cookies.get('session')?.value) passes for any non-empty cookie value, including expired or maliciously crafted tokens. A user whose session JWT has expired can still access protected routes indefinitely.

The middleware should verify the JWT before granting access. The simplest approach is to reuse the readSessionEmail utility (which calls jwt.verify), or inline the decode inline:

🔧 Proposed fix
-import { NextRequest, NextResponse } from 'next/server';
+import { NextRequest, NextResponse } from 'next/server';
+import jwt from 'jsonwebtoken';

 export function middleware(req: NextRequest) {
   const protectedPath = req.nextUrl.pathname.startsWith('/dashboard');
-  const hasSession = Boolean(req.cookies.get('session')?.value);
+  const token = req.cookies.get('session')?.value;
+  let hasValidSession = false;
+  if (token) {
+    try {
+      jwt.verify(token, process.env.JWT_SECRET!);
+      hasValidSession = true;
+    } catch {
+      hasValidSession = false;
+    }
+  }

-  if (protectedPath && !hasSession) {
+  if (protectedPath && !hasValidSession) {
     const url = new URL('/login', req.url);
     url.searchParams.set('next', req.nextUrl.pathname);
     return NextResponse.redirect(url);
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/content/docs/cookbooks/implement-nextjs-auth.mdx` around lines 280 - 295,
The middleware currently only checks for the presence of a 'session' cookie in
middleware(req) which allows expired or tampered JWTs; update middleware to
validate the JWT before allowing access by calling the existing readSessionEmail
utility (or invoking jwt.verify) with the cookie value and rejecting if
verification fails or token is expired; keep the same redirect behavior (create
URL('/login', req.url) and set next param) when verification fails, and return
NextResponse.next() only when readSessionEmail/jwt.verify confirms a valid
session; reference middleware, readSessionEmail, jwt.verify, NextRequest, and
NextResponse in your changes.

@@ -0,0 +1,175 @@
---
title: 'Configuring JWT Validation Timeouts in Spring Boot 4.0+'
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Title violates sentence-case guideline.

"Validation" and "Timeouts" are not proper nouns and should be lowercase.

🔧 Proposed fix
-title: 'Configuring JWT Validation Timeouts in Spring Boot 4.0+'
+title: 'Configuring JWT validation timeouts in Spring Boot 4.0+'
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/content/docs/cookbooks/java-spring-boot-jwt-timeout.mdx` at line 2, The
document title uses Title Case; change it to sentence case so non-proper nouns
are lowercase—update the title string "Configuring JWT Validation Timeouts in
Spring Boot 4.0+" to "Configuring JWT validation timeouts in Spring Boot 4.0+"
(modify the frontmatter/title line that currently contains the title).

2. Retrieves the JWKS (JSON Web Key Set) to verify token signatures
3. Caches these for future validations

If these initial requests timeout, authentication fails completely.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Grammar: "timeout" here is a verb — should be written "time out".

The static analysis tool's flag is valid. "Timeout" (noun/adjective) vs. "time out" (phrasal verb).

🔧 Proposed fix
-If these initial requests timeout, authentication fails completely.
+If these initial requests time out, authentication fails completely.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
If these initial requests timeout, authentication fails completely.
If these initial requests time out, authentication fails completely.
🧰 Tools
🪛 LanguageTool

[grammar] ~52-~52: Ensure spelling is correct
Context: ... validations If these initial requests timeout, authentication fails completely. ## W...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/content/docs/cookbooks/java-spring-boot-jwt-timeout.mdx` at line 52, The
sentence uses "timeout" as a verb; update the phrase "If these initial requests
timeout, authentication fails completely." to use the phrasal verb "time out" by
replacing "timeout" with "time out" so it reads "If these initial requests time
out, authentication fails completely."; locate this text in the Java Spring Boot
JWT timeout cookbook (the line containing that sentence) and make the
single-word replacement.

Comment on lines +73 to +97
<Tabs>
<TabItem value="yaml" label="application.yml">
```yaml
spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: https://auth.scalekit.com
# Configure timeouts for JWKS and discovery endpoints
client:
registration:
connect-timeout: 10000 # 10 seconds for connection
read-timeout: 10000 # 10 seconds for reading response
```
</TabItem>
<TabItem value="properties" label="application.properties">
```properties
spring.security.oauth2.resourceserver.jwt.issuer-uri=https://auth.scalekit.com
# Configure timeouts for JWKS and discovery endpoints
spring.security.oauth2.resourceserver.jwt.client.registration.connect-timeout=10000
spring.security.oauth2.resourceserver.jwt.client.registration.read-timeout=10000
```
</TabItem>
</Tabs>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

Spring Boot 4.0 spring.security.oauth2.resourceserver.jwt timeout configuration properties

💡 Result:

Spring Boot 4.0 (Spring Security 7.x) does not expose any spring.security.oauth2.resourceserver.jwt.* configuration properties for HTTP timeouts (connect/read) when the resource server fetches OIDC metadata / JWK set keys. Boot’s JWT resource-server properties cover things like issuer-uri, jwk-set-uri, audiences, etc., but not timeouts. [1]

Servlet (Spring MVC): configure via a JwtDecoder bean

Spring Security documents that the resource server uses 30s connect + 30s socket/read timeouts by default, and shows customizing them by supplying a RestOperations (e.g., RestTemplate) to NimbusJwtDecoder: [2]

`@Bean`
JwtDecoder jwtDecoder(RestTemplateBuilder builder) {
  RestOperations rest = builder
      .setConnectTimeout(Duration.ofSeconds(5))
      .setReadTimeout(Duration.ofSeconds(5))
      .build();

  return NimbusJwtDecoder.withIssuerLocation(issuerUri)
      .restOperations(rest)
      .build();
}

Reactive (WebFlux): configure via a ReactiveJwtDecoder bean

For reactive apps, NimbusReactiveJwtDecoder lets you supply a custom WebClient (where you set Reactor Netty timeouts, proxy, etc.) via the builder’s webClient(WebClient) method. [3]

Sources:
[1] Spring Boot reference (resource server JWT properties) (docs.enterprise.spring.io)
[2] Spring Security reference (JWT “Configuring Timeouts” with RestOperations) (docs.spring.io)
[3] Spring Security Javadoc (NimbusReactiveJwtDecoder...Builder.webClient(WebClient)) (docs.spring.io)

Citations:


🌐 Web query:

Spring Security ResourceServer JWT decoder client timeout configuration

💡 Result:

Spring Security’s OAuth2 Resource Server JWT support uses 30s connect + 30s read/socket timeouts by default when fetching the JWK Set. You change this by providing your own HTTP client to the decoder builder. [1]

Servlet (Spring MVC) — NimbusJwtDecoder (uses RestOperations)

Expose a custom JwtDecoder bean and pass a RestOperations (typically a RestTemplate) with your desired timeouts:

`@Bean`
JwtDecoder jwtDecoder(RestTemplateBuilder builder) {
  RestOperations rest = builder
      .setConnectTimeout(Duration.ofSeconds(5))
      .setReadTimeout(Duration.ofSeconds(5))
      .build();

  return NimbusJwtDecoder.withJwkSetUri(jwkSetUri)
      .restOperations(rest)
      .build();
}

Spring Security supports injecting RestOperations via NimbusJwtDecoder.withJwkSetUri(...).restOperations(...). [1][2]

Reactive (WebFlux) — NimbusReactiveJwtDecoder (uses WebClient)

Provide a WebClient configured with timeouts, then:

`@Bean`
ReactiveJwtDecoder jwtDecoder(WebClient webClient) {
  return NimbusReactiveJwtDecoder.withJwkSetUri(jwkSetUri)
      .webClient(webClient)
      .build();
}

The reactive builder explicitly supports supplying a WebClient via .webClient(...). [3]


🌐 Web query:

Spring Security NimbusJwtDecoder RestOperations timeout configuration 2024 2025

💡 Result:

To configure connect/read timeouts for the HTTP calls Spring Security makes to fetch OIDC metadata and/or the JWK Set, supply a RestOperations (typically a RestTemplate) to the NimbusJwtDecoder builder via .restOperations(...) (works with both withIssuerLocation(...) and withJwkSetUri(...)). Spring Security’s reference docs show this as the supported approach and note a default of 30s connect + 30s socket/read unless you override it. [1]

`@Bean`
JwtDecoder jwtDecoder(RestTemplateBuilder builder) {
    RestOperations rest = builder
        .setConnectTimeout(Duration.ofSeconds(5))
        .setReadTimeout(Duration.ofSeconds(5))
        .build();

    return NimbusJwtDecoder.withIssuerLocation("https://idp.example.com/issuer")
        .restOperations(rest)
        .build();
    // or: .withJwkSetUri(jwkSetUri).restOperations(rest).build();
}

The NimbusJwtDecoder.JwkSetUriJwtDecoderBuilder#restOperations(RestOperations) hook is part of the public API. [2]

Note: there was an enhancement request (Dec 11, 2023) indicating that some internal paths used a default RestTemplate “with no timeout configured” (risking hung threads), so explicitly wiring timeouts as above is the safest option across versions. [3]

Sources: [1] Spring Security Reference – “Configuring Timeouts” (Resource Server JWT) • [2] Spring Security Javadoc – NimbusJwtDecoder.JwkSetUriJwtDecoderBuilder#restOperations • [3] spring-projects/spring-security issue #14269


Remove or caveat the YAML/properties timeout configuration—it will silently have no effect.

Spring Boot 4.0 (Spring Security 7.x) does not expose spring.security.oauth2.resourceserver.jwt.client.registration.connect-timeout or similar timeout properties for the resource server's JWT decoder. The documented properties under spring.security.oauth2.resourceserver.jwt.* are limited to issuer-uri, jwk-set-uri, and validation options only.

The programmatic approach shown in lines 112–138 (using NimbusJwtDecoder with a custom RestOperations) is the documented and correct way to configure timeouts. Developers who apply the declarative YAML/properties config will believe timeouts are set to 10 seconds when they actually remain at Spring Security's default of 30 seconds, creating a false sense of control.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/content/docs/cookbooks/java-spring-boot-jwt-timeout.mdx` around lines 73
- 97, Remove the misleading YAML/properties timeout entries under
spring.security.oauth2.resourceserver.jwt (the application.yml and
application.properties TabItems) and add a clear caveat noting these properties
are ignored in Spring Boot 4 / Spring Security 7; instead, reference and
recommend the programmatic approach shown in the doc (the NimbusJwtDecoder +
custom RestOperations example around the existing "NimbusJwtDecoder" /
"RestOperations" code in lines ~112–138) and instruct readers to configure
timeouts via a custom RestTemplate/HttpClient or WebClient passed into
NimbusJwtDecoder rather than via declarative properties.

@netlify
Copy link

netlify bot commented Feb 23, 2026

Deploy Preview for scalekit-starlight ready!

Name Link
🔨 Latest commit 6902c35
🔍 Latest deploy log https://app.netlify.com/projects/scalekit-starlight/deploys/699cd623f1877f0008095f38
😎 Deploy Preview https://deploy-preview-397--scalekit-starlight.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants