Skip to content

Add sveltekit cloudflare pages docs #415

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 14 commits into
base: main
Choose a base branch
from

Conversation

KeeganBeuthin
Copy link
Contributor

@KeeganBeuthin KeeganBeuthin commented May 9, 2025

This PR adds documentation for integrating Kinde authentication with SvelteKit on Cloudflare Pages.

I've created this guide based on my implementation experience, and while it's functional, I recognize that it's more complex than ideal. The current solution requires more code than I'd like, especially in the server handler, due to the unique constraints of Cloudflare's serverless environment and how it interacts with OAuth flows.

I would greatly appreciate feedback on:

  1. How to further simplify this implementation while maintaining security and functionality
  2. Any Cloudflare-specific best practices I might have missed
  3. Opportunities to reduce the code footprint, particularly in the auth handler
  4. Alternative approaches that might provide a more elegant solution

I'm very open to suggestions on how to make this guide more concise and maintainable.

Summary by CodeRabbit

  • Documentation
    • Added a comprehensive guide for integrating Kinde authentication with SvelteKit on Cloudflare Pages, including setup instructions, code examples, and configuration for secure session management using Cloudflare KV storage. The guide covers authentication flows, route protection, and error handling.
  • New Features
    • Introduced secure authentication flows including login, registration, OAuth callback, and logout.
    • Implemented hybrid session management combining Cloudflare KV storage for tokens and cookies for OAuth temporary data.
    • Added route protection to redirect unauthenticated users to the login page.

Copy link
Contributor

coderabbitai bot commented May 9, 2025

Walkthrough

A new documentation file was added, providing detailed instructions and code for integrating Kinde authentication into a SvelteKit app on Cloudflare Pages using Cloudflare KV for secure state and token management. The guide includes setup steps, a custom KV and cookie hybrid storage adapter, authentication route handlers, session management, and route protection.

Changes

File(s) Change Summary
src/content/docs/integrate/third-party-tools/kinde-sveltekit-with-cloudflare.mdx New documentation with step-by-step guide for integrating Kinde auth in SvelteKit with Cloudflare KV and cookies.
src/lib/kindeAuth.ts Added initializeKindeAuth function for hybrid KV and cookie storage; added CookieStorage class for OAuth temporary data.
src/routes/api/auth/[...kindeAuth]/+server.ts Added async GET handler supporting login, register, OAuth callback, and logout flows with helper functions for PKCE, token exchange, and state management.
src/routes/dashboard/+page.server.ts Added exported load function to protect dashboard route by redirecting unauthenticated users and extracting user profile.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant SvelteKitApp
    participant CloudflareKV
    participant KindeAuth

    User->>SvelteKitApp: Requests /api/auth/login
    SvelteKitApp->>CloudflareKV: Store OAuth state (setState)
    SvelteKitApp->>User: Redirect to KindeAuth (login)

    User->>KindeAuth: Authenticate
    KindeAuth->>User: Redirect back with code/state

    User->>SvelteKitApp: Requests /api/auth/kinde_callback
    SvelteKitApp->>CloudflareKV: Validate state (getState)
    SvelteKitApp->>KindeAuth: Exchange code for tokens (with client secret and PKCE)
    KindeAuth-->>SvelteKitApp: Return tokens
    SvelteKitApp->>CloudflareKV: Store tokens (setState)
    SvelteKitApp->>User: Set session cookie and redirect to app

    User->>SvelteKitApp: Requests protected route
    SvelteKitApp->>CloudflareKV: Check tokens (getState)
    alt Tokens expired
        SvelteKitApp->>KindeAuth: Refresh tokens
        KindeAuth-->>SvelteKitApp: Return refreshed tokens
        SvelteKitApp->>CloudflareKV: Update tokens
    end
    alt Authenticated
        SvelteKitApp->>User: Serve protected content
    else Not authenticated
        SvelteKitApp->>User: Redirect to login
    end
Loading

Suggested labels

sdk

Suggested reviewers

  • DanielRivers
  • clairekinde11

Poem

🐇 Hop, hop, hop, through code we go,
Kinde and Cloudflare make auth flow.
Tokens stored safe in KV’s nest,
Cookies hold secrets for OAuth’s quest.
Login, logout, sessions tight,
Bunny’s work is done just right!
🥕✨🐰


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@KeeganBeuthin KeeganBeuthin changed the title Add sveltekit cloudflare docs Add sveltekit cloudflare pages docs May 9, 2025
Copy link
Contributor

@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

🧹 Nitpick comments (12)
src/content/docs/integrate/third-party-tools/kinde-sveltekit-with-cloudflare.mdx (12)

1-5: Nitpick: Validate front matter schema.
Ensure the YAML front matter keys (page_id, title, description) align with your documentation site's expected schema. Consider adding metadata fields like sidebar_position or category if your site supports them for better navigation.


8-11: Suggestion: Use a callout component for complexity note.
Instead of a plain blockquote, leverage your MDX callout/snippet component (e.g., <Alert type="warning">…</Alert>) to highlight the implementation complexity. It improves readability and consistency with other guides.


13-18: Optional: Clarify prerequisites.
Add explicit versions for Node.js, SvelteKit, Wrangler CLI, and specify which Cloudflare Pages target (e.g., pages) you’re deploying to. It prevents compatibility issues for newcomers.


31-34: Combine installation commands.
You can streamline dependency installation into a single command for brevity:

- ```bash
- npm install @kinde-oss/kinde-auth-sveltekit
- npm install -D @sveltejs/adapter-cloudflare
- ```
+ ```bash
+ npm install @kinde-oss/kinde-auth-sveltekit @sveltejs/adapter-cloudflare -D
+ ```  

47-65: Nitpick: Consistent quoting in wrangler.toml.
You mix single- and double-quotes for environment variables. For clarity and consistency, use double quotes throughout:

-[vars]
-KINDE_SCOPE = 'openid profile email offline'
+ [vars]
+ KINDE_SCOPE = "openid profile email offline"

Also consider updating compatibility_date to the latest stable date to avoid deprecation warnings.


179-183: Refactor: Uniform error response.
Both console.error and return json({ error: ... }) are used. Consider extracting a helper for error responses to maintain a consistent JSON shape and status code across all endpoints.


185-201: Optional: Replace switch with a handler map.
A lookup object reduces boilerplate and makes adding endpoints easier:

const handlers: Record<string, Handler> = {
  login: (e) => handleLogin(e, storage, false),
  register: (e) => handleLogin(e, storage, true),
  kinde_callback: (e) => handleCallback(e, storage),
  logout: (e) => handleLogout(e, storage)
};
return handlers[path]?.(event) ?? json({ error: 'Unknown auth endpoint' }, { status: 404 });

214-218: Nitpick: Move helper functions to a shared utils file.
Extract sha256 and base64URLEncode into src/lib/utils/crypto.ts to avoid cluttering the route handler and enable reuse across other guides or modules.


365-443: Optional: Simplify client_secret logic.
Since Kinde always requires the client secret, you can remove the if (USE_PKCE && …) branch and always append client_secret, then conditionally append code_verifier. This flattens nested conditions.


445-457: Optional: Clear session cookies on logout.
After deleting tokens from KV, also clear any session cookies (Set-Cookie: session=; Max-Age=0) to fully end the user’s session client-side.


459-469: Optional: Handle circular objects in safeStringify.
For more robust error logging, consider using a library like fast-safe-stringify which gracefully handles circular references.


500-520: Optional: Delegate route protection to sessionHooks.
Rather than manually checking storage.getState('tokens'), leverage the hook-injected event.locals.session or a helper ensureAuthenticated(event) to reduce duplication and centralize logic.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5790c16 and fd4203e.

📒 Files selected for processing (1)
  • src/content/docs/integrate/third-party-tools/kinde-sveltekit-with-cloudflare.mdx (1 hunks)
🔇 Additional comments (2)
src/content/docs/integrate/third-party-tools/kinde-sveltekit-with-cloudflare.mdx (2)

133-146: Suggestion: Verify sessionHooks integration.
Confirm that sessionHooks actually injects session data into event.locals before resolve(event). Some hook implementations require you to capture and return its response:

// e.g.
const response = await sessionHooks({ event, storage });
return await resolve(event, { locals: event.locals });

Please double-check the @kinde-oss/kinde-auth-sveltekit docs for exact usage.


220-225: Skip: Base64 URL encoding logic is correct.
This implementation properly replaces URL-unsafe characters. No changes needed.

Copy link
Contributor

@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: 3

♻️ Duplicate comments (2)
src/content/docs/integrate/third-party-tools/kinde-sveltekit-with-cloudflare.mdx (2)

199-204: Cryptographically secure randomness is correctly implemented
You’re already using crypto.getRandomValues, which satisfies the earlier recommendation to avoid Math.random(). No changes needed here.


446-504: Guard verbose logging behind a debug flag
There are multiple console.log calls printing URLs, statuses, and potentially sensitive data. As noted in previous feedback, avoid verbose or secret-exposing logs in production. Wrap these logs in a debug check (e.g. if (KINDE_DEBUG === 'true') { ... }).

🧹 Nitpick comments (2)
src/content/docs/integrate/third-party-tools/kinde-sveltekit-with-cloudflare.mdx (2)

56-65: (Optional) Expose a debug flag in your Wrangler config
You reference KINDE_DEBUG in the code but haven’t added it to wrangler.toml. Consider adding:

KINDE_DEBUG = "false"

This lets users toggle detailed logs without touching source.


532-537: Enhance cookie security with Secure attribute
When setting the kinde_session cookie, add ; Secure so it’s only sent over HTTPS. Example:

- 'Set-Cookie': `kinde_session=${sessionId}; Path=/; HttpOnly; SameSite=Lax; Max-Age=2592000`
+ 'Set-Cookie': `kinde_session=${sessionId}; Path=/; HttpOnly; SameSite=Lax; Secure; Max-Age=2592000`
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fd4203e and f7f8f38.

📒 Files selected for processing (1)
  • src/content/docs/integrate/third-party-tools/kinde-sveltekit-with-cloudflare.mdx (1 hunks)

Copy link
Contributor

@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

🧹 Nitpick comments (10)
src/content/docs/integrate/third-party-tools/kinde-sveltekit-with-cloudflare.mdx (10)

1-5: Add an explicit H1 heading.
While the frontmatter defines title, it’s helpful for readability to include an H1 in the content itself. For example, right after the frontmatter add:

# Integrating Kinde Authentication with SvelteKit on Cloudflare Pages

8-11: Convert the implementation note into an admonition.
To improve scannability, wrap the complexity note in a callout (e.g., a ::: tip or ::: warning block) rather than inline text:

::: tip
This implementation is more complex than ideal due to Cloudflare's
serverless constraints. We're working on more elegant solutions, 
but this guide provides a robust working implementation.
:::

79-81: Log or surface missing KV binding errors.
createKindeStorage currently returns null silently when AUTH_STORAGE is unavailable. Consider logging or throwing to help readers diagnose misconfigurations:

-  if (!AUTH_STORAGE) {
-    return null;
-  }
+  if (!AUTH_STORAGE) {
+    console.error('❌ AUTH_STORAGE KV namespace is not bound in Wrangler');
+    return null;
+  }

84-95: Avoid swallowing errors in storage adapter.
All catch blocks return false or null without logging the underlying exception. For better debugging, log error.message:

-  } catch (error) {
-    return false;
-  }
+  } catch (error) {
+    console.error('KV.setState error:', error);
+    return false;
+  }

Apply similar logging in getState and deleteState.


360-367: Add the Secure attribute to cookies.
When setting kinde_session, include Secure; so browsers only send it over HTTPS:

- 'Set-Cookie': `kinde_session=${sessionId}; Path=/; HttpOnly; SameSite=Lax; Max-Age=2592000`
+ 'Set-Cookie': `kinde_session=${sessionId}; Path=/; HttpOnly; Secure; SameSite=Lax; Max-Age=2592000`

397-404: Gate verbose logs behind the debug flag.
fetchTokens prints URLs and flags on every invocation, which may leak PII. Wrap all console.log calls in:

if (KINDE_DEBUG === 'true') { /* ... */ }

to mirror other parts of the implementation.


462-466: Use SvelteKit’s event.cookies API.
Instead of manual regex parsing of event.request.headers, prefer:

const sessionId = event.cookies.get('kinde_session');

This is more robust and future-proof.


507-511: Remove unused kindeAuthClient import.
kindeAuthClient is imported but never used in this snippet. Deleting it will keep the sample focused:

-import { kindeAuthClient } from '@kinde-oss/kinde-auth-sveltekit';

521-524: Simplify cookie retrieval in load().
As above, use event.cookies.get('kinde_session') to fetch the session ID instead of regex on headers.


577-584: Consolidate token refresh logic.
You duplicate an OAuth token-refresh flow here. Consider reusing fetchTokens (with grant_type=refresh_token) or extracting shared logic into a helper to avoid drift.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f7f8f38 and fd95df9.

📒 Files selected for processing (1)
  • src/content/docs/integrate/third-party-tools/kinde-sveltekit-with-cloudflare.mdx (1 hunks)
🔇 Additional comments (1)
src/content/docs/integrate/third-party-tools/kinde-sveltekit-with-cloudflare.mdx (1)

133-142: Session hooks integration looks solid.
The handle function properly injects the custom storage adapter when available and defers to default behavior otherwise.

@clairekinde11
Copy link
Collaborator

Hey @KeeganBeuthin not sure if you are finished with this, but looks like coderabbit has a few suggestions.

Copy link
Contributor

@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: 3

♻️ Duplicate comments (1)
src/content/docs/integrate/third-party-tools/kinde-sveltekit-with-cloudflare.mdx (1)

154-158: ⚠️ Potential issue

Missing import for KINDE_DEBUG
You’ve added a KINDE_DEBUG variable in your Wrangler config but are not importing it here. Without it, you cannot guard debug logs. Add to the import:

-import { KINDE_ISSUER_URL, KINDE_CLIENT_ID, KINDE_CLIENT_SECRET, KINDE_REDIRECT_URL, KINDE_POST_LOGIN_REDIRECT_URL, KINDE_POST_LOGOUT_REDIRECT_URL, KINDE_AUTH_WITH_PKCE, KINDE_SCOPE } from '$env/static/private';
+import {
+  KINDE_ISSUER_URL,
+  KINDE_CLIENT_ID,
+  KINDE_CLIENT_SECRET,
+  KINDE_REDIRECT_URL,
+  KINDE_POST_LOGIN_REDIRECT_URL,
+  KINDE_POST_LOGOUT_REDIRECT_URL,
+  KINDE_AUTH_WITH_PKCE,
+  KINDE_SCOPE,
+  KINDE_DEBUG
+} from '$env/static/private';
🧹 Nitpick comments (5)
src/content/docs/integrate/third-party-tools/kinde-sveltekit-with-cloudflare.mdx (5)

31-34: Consolidate dependency installation
Instead of two separate npm install commands, you can combine them to reduce friction:

npm install @kinde-oss/kinde-auth-sveltekit @sveltejs/adapter-cloudflare -D

80-82: Improve error visibility in the storage adapter
Currently, createKindeStorage and its methods swallow errors and return null/false, which can make debugging difficult. Consider logging the caught error or rethrowing so failures are visible during development:

-  if (!AUTH_STORAGE) {
-    return null;
-  }
+  if (!AUTH_STORAGE) {
+    console.error('AUTH_STORAGE binding missing');
+    throw new Error('KV namespace binding AUTH_STORAGE is not configured.');
+  }
...
-  } catch (error) {
-    return false;
-  }
+  } catch (error) {
+    console.error('KV put error:', error);
+    throw error;
+  }

Also applies to: 94-96, 111-113, 121-123


461-464: Leverage SvelteKit’s event.cookies API
Manually parsing event.request.headers.get('cookie') is error‐prone. Prefer:

const sessionId = event.cookies.get('kinde_session');

And to clear:

event.cookies.delete('kinde_session', { path: '/', secure: true, sameSite: 'Lax' });

This improves readability and correctness.

Also applies to: 515-518, 615-618


501-502: Remove unused kindeAuthClient import
You import kindeAuthClient but never use it in +layout.server.ts. Either use the client for session loading or remove this line to avoid confusion.


603-646: Extract common cookie and token logic into helpers
The dashboard load logic duplicates cookie parsing and getUserIdFromToken. Consider moving these to shared utilities ($lib/session.ts) and reusing them across both the layout and dashboard handlers to DRY up the code.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fd95df9 and f6add05.

📒 Files selected for processing (1)
  • src/content/docs/integrate/third-party-tools/kinde-sveltekit-with-cloudflare.mdx (1 hunks)
🔇 Additional comments (1)
src/content/docs/integrate/third-party-tools/kinde-sveltekit-with-cloudflare.mdx (1)

1-5: Frontmatter is well‐formed
The YAML frontmatter includes page_id, title, and description, which are essential for MDX metadata.

Copy link
Contributor

@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: 1

♻️ Duplicate comments (1)
src/content/docs/integrate/third-party-tools/kinde-sveltekit-with-cloudflare.mdx (1)

445-467: ⚠️ Potential issue

Missing Secure flag on cookie clear
When clearing the kinde_session cookie, you should include the Secure attribute to match the setter and ensure the cookie is invalidated over HTTPS:

- 'Set-Cookie': 'kinde_session=; Path=/; HttpOnly; SameSite=Lax; Max-Age=0'
+ 'Set-Cookie': 'kinde_session=; Path=/; HttpOnly; Secure; SameSite=Lax; Max-Age=0'

This is critical to avoid stale cookies.

🧹 Nitpick comments (10)
src/content/docs/integrate/third-party-tools/kinde-sveltekit-with-cloudflare.mdx (10)

1-5: Frontmatter formatting
Consider aligning the frontmatter with the MDX style guide. For example, if page_id is auto-generated (and not referenced elsewhere), you can remove it or add a comment explaining its use so readers understand why it’s present.


31-34: Combine installation commands
You can streamline the setup by installing both packages in one step, e.g.:

npm install @kinde-oss/kinde-auth-sveltekit -D @sveltejs/adapter-cloudflare

This reduces friction for readers following the guide.


85-94: Log storage errors for debugging
Silently returning false in setState can obscure KV failures. Consider logging the exception before returning:

   } catch (error) {
-    return false;
+    console.error('KV setState error:', error);
+    return false;
   }

This will help users triage storage issues.


99-110: Surface KV retrieval errors
Similarly, suppressing errors in getState by returning null hides root causes. Add logging for the catch block:

   } catch (error) {
-    return null;
+    console.error('KV getState error:', error);
+    return null;
   }

This improves observability in production.


157-158: Cleanup environment imports
You’ve defined KINDE_DEBUG in wrangler.toml but it’s not imported or used here. Either remove KINDE_DEBUG from the configuration or import and guard your logs against it (e.g., wrap console.error/console.debug calls).


169-178: Robust endpoint detection
url.pathname.split('/').pop() can return an empty string if the path ends with a slash. Consider trimming trailing slashes first:

const path = url.pathname.replace(/\/$/, '').split('/').pop() || '';

This ensures you always extract the correct segment.


275-377: Scope debug/error keys per user
You’re storing callback errors under generic keys ('last_error', 'token_error'), which may collide across concurrent flows. Namespace these entries (e.g., error:state:${state} or using the session ID) to isolate error data per user.


379-442: Simplify PKCE branch
Since you only store a true codeVerifier when PKCE is enabled, the extra !== 'true' check is no longer needed. You can streamline to:

-  if (USE_PKCE && codeVerifier && codeVerifier !== 'true') {
-    params.append('code_verifier', codeVerifier);
-    params.append('client_secret', SECRET);
-  } else {
-    params.append('client_secret', SECRET);
-  }
+  params.append('client_secret', SECRET);
+  if (USE_PKCE && codeVerifier) {
+    params.append('code_verifier', codeVerifier);
+  }

This reduces conditional complexity.


501-504: Use SvelteKit's cookie API
Rather than parsing event.request.headers, leverage SvelteKit’s built-in cookie helpers:

const sessionId = event.cookies.get('kinde_session');

This simplifies the code and handles encoding correctly.


589-632: Route protection example
The dashboard load function clearly illustrates guarding routes. To avoid duplicate logic, consider exporting and reusing the getUserIdFromToken helper from your callback code rather than redefining it here.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f6add05 and f86ff69.

📒 Files selected for processing (1)
  • src/content/docs/integrate/third-party-tools/kinde-sveltekit-with-cloudflare.mdx (1 hunks)
🔇 Additional comments (6)
src/content/docs/integrate/third-party-tools/kinde-sveltekit-with-cloudflare.mdx (6)

137-143: Integrate session hooks with storage
The conditional spread of storage into sessionHooks is concise and correctly bypasses KV when unbound. This cleanly wires Cloudflare KV into the Kinde session lifecycle.


200-205: Secure randomness for OAuth state
Great use of crypto.getRandomValues for generating the state parameter—this addresses the cryptographic security concern and was an essential fix.


208-219: PKCE helper functions
The sha256 and base64URLEncode utilities correctly implement the PKCE code challenge. Their concise, promise-based design is ideal for Cloudflare’s environment.


221-272: Login flow implementation
The login handler cleanly orchestrates state, redirect, optional PKCE setup, and redirects to Kinde. Parameter extraction was moved into the correct order—this is well structured and readable.


469-480: Graceful error serialization
The safeStringify helper elegantly handles both Error objects and unstringifiable payloads, ensuring robust debugging output.


556-582: Token refresh flow
The refresh logic correctly handles HTTP errors and JSON parsing, storing refreshed tokens back to KV. This aligns neatly with OAuth best practices.

Copy link
Contributor

@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: 2

🧹 Nitpick comments (12)
src/content/docs/integrate/third-party-tools/kinde-sveltekit-with-cloudflare.mdx (12)

8-11: Rephrase the note for clarity.
Consider updating “more complex than ideal” to something like “more complex than desired” to make the tone smoother.


13-18: Specify Node.js and npm versions in prerequisites.
Add a note about required Node.js (e.g., v16+) and npm/yarn versions to ensure compatibility with SvelteKit and Wrangler.


44-65: Update compatibility_date to the current date.
The example uses "2023-06-28", which may be outdated. Suggest replacing with "<YYYY-MM-DD>" or documenting that this value should match the latest Cloudflare runtime date.


75-130: Log errors in KV adapter catch blocks for better observability.
Currently, failures in setState, getState, and deleteState are swallowed (returning false or null). Consider logging error.message inside each catch to aid debugging of KV operations.


157-169: Polish import formatting and include debug flag.

  • Add a missing space after the comma in KINDE_AUTH_WITH_PKCE,KINDE_SCOPE.
  • Since KINDE_DEBUG is defined in wrangler.toml, import it here to enable conditional logging later.

172-200: Use SvelteKit’s route parameters instead of URL.pathname.
Leverage event.params.kindeAuth (the dynamic [...kindeAuth] segment) for dispatching to login, register, etc., to avoid brittle string parsing based on URL segments.


225-274: Check KV write results in handleLogin.
storage.setState returns a boolean—consider verifying it's true and handling error cases (e.g., return a 500 response) rather than assuming success.


397-401: Simplify PKCE check in fetchTokens.
The codeVerifier !== 'true' condition is redundant since codeVerifier is always a string or undefined. You can streamline to:

- if (USE_PKCE && codeVerifier && codeVerifier !== 'true') {
+ if (USE_PKCE && codeVerifier) {

490-493: Remove unused kindeAuthClient import.
kindeAuthClient isn’t referenced in this layout loader; you can delete it to clean up the code.


504-507: Leverage event.cookies.get() for cookie retrieval.
Instead of manually parsing event.request.headers, use SvelteKit’s event.cookies.get('kinde_session') for more robust cookie handling.


592-597: Use built-in cookie API in dashboard route.
Similar to the layout loader, replace manual header parsing with event.cookies.get('kinde_session') to simplify the protected-route sample.


626-634: Add TypeScript typing for getUserIdFromToken.
Define the idToken parameter as a string to improve clarity:

function getUserIdFromToken(idToken: string): string | null { ... }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f86ff69 and 10e3e75.

📒 Files selected for processing (1)
  • src/content/docs/integrate/third-party-tools/kinde-sveltekit-with-cloudflare.mdx (1 hunks)
🔇 Additional comments (6)
src/content/docs/integrate/third-party-tools/kinde-sveltekit-with-cloudflare.mdx (6)

1-5: Frontmatter metadata looks good.
The page_id, title, and description are present and follow the project’s conventions.


19-28: Verify callback URL formatting.
The example uses /api/auth/kinde_callback; ensure that matches the route in your SvelteKit project (it should align with the [...kindeAuth] handler path).


31-34: Dependency installation is correct.
Installing @kinde-oss/kinde-auth-sveltekit and the Cloudflare adapter covers the essentials.


38-41: KV namespace setup instructions are clear.
The steps to create and copy the namespace ID in Cloudflare Pages are accurate.


67-70: Securing the client secret is well addressed.
Moving KINDE_CLIENT_SECRET into a Wrangler secret aligns with best practices.


137-149: Hooks integration is correct.
Using sessionHooks with a conditional storage binding ensures session support on Cloudflare Pages.

Copy link
Contributor

@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: 0

♻️ Duplicate comments (2)
src/content/docs/integrate/third-party-tools/kinde-sveltekit-with-cloudflare.mdx (2)

203-208: Duplicate of previous crypto‐secure randomness suggestion
generateRandomString now uses crypto.getRandomValues, fulfilling the earlier recommendation to avoid Math.random().


373-378: ⚠️ Potential issue

Namespace token exchange errors
You log and store JSONified errors under a fixed key token_error, which could collide across users or flows. It’s safer to namespace it similarly to state errors, e.g.:

- await storage.setState('token_error', { … });
+ await storage.setState(`token_error:${state}`, { … });
🧹 Nitpick comments (4)
src/content/docs/integrate/third-party-tools/kinde-sveltekit-with-cloudflare.mdx (4)

46-65: Suggest updating compatibility_date to the current date
Keeping compatibility_date up-to-date helps ensure you benefit from the latest Cloudflare Pages runtime improvements. Consider bumping this to today’s date (e.g., "2025-05-01").


75-130: Improve error visibility in the KV storage adapter
Currently, setState / getState / deleteState swallow errors and return false / null without logging. In a production scenario, you’d want to at least log error.message (or rethrow) to aid debugging. For example:

 setState: async (stateId: string, stateData: any) => {
   try {
     // ...
     await AUTH_STORAGE.put(key, value, { expirationTtl: 600 });
     return true;
   } catch (error) {
-    return false;
+    console.error(`KV put failed for ${key}:`, error);
+    throw error;
   }
 },

383-445: Minor: simplify PKCE vs. non-PKCE branch
The check codeVerifier && codeVerifier !== 'true' is vestigial—your stored state is never the literal "true". You can consolidate to:

- if (USE_PKCE && codeVerifier && codeVerifier !== 'true') {
+ if (USE_PKCE && codeVerifier) {

490-493: Remove unused import
kindeAuthClient is imported but never used in +layout.server.ts. Consider removing to keep the snippet focused:

- import { kindeAuthClient } from '@kinde-oss/kinde-auth-sveltekit';
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 10e3e75 and 95fed36.

📒 Files selected for processing (1)
  • src/content/docs/integrate/third-party-tools/kinde-sveltekit-with-cloudflare.mdx (1 hunks)
🔇 Additional comments (15)
src/content/docs/integrate/third-party-tools/kinde-sveltekit-with-cloudflare.mdx (15)

137-150: Hooks integration is correctly wired
The sessionHooks call now properly passes storage only when available, preserving default behavior otherwise. This aligns with the package’s API and looks correct.


157-170: Environment imports look good
All required KINDE_* vars are pulled from $env/static/private, and KINDE_DEBUG isn’t referenced in this example (debug logs have been removed), so you don’t need to import it here.


172-200: Approve GET handler routing logic
The switch on path correctly delegates to the four endpoints (login, register, kinde_callback, logout) and falls back to a 404. Error handling for missing KV is appropriate.


211-215: SHA-256 helper implementation is correct
The sha256 function leverages crypto.subtle.digest as expected for PKCE, with proper encoding.


217-222: Base64 URL‐encode helper is accurate
Your base64URLEncode correctly replaces URL-unsafe characters and trims padding.


225-274: Login handler properly scopes state and redirect
You generate a cryptographically secure state, conditionally store the PKCE verifier, and namespace both verifier and redirect keys. The OAuth URL construction is clear and correct.


297-308: State validation and error scoping look good
Invalid state flows now log the error and store a namespaced error:${state} entry, avoiding cross-session collisions.


318-321: Cleanup of state and redirect keys is correct
Deleting both the PKCE verifier and redirect entries ensures no stale data remains in KV.


323-336: Token storage under session‐scoped key is solid
Storing the full token set with timestamp and TTL fields under session:${sessionId}:tokens is precisely what you need for later validation and refresh.


340-352: User ID extraction is handled safely
The ID token is parsed defensively with a try/catch, which prevents runtime crashes on malformed tokens.


359-367: Session cookie includes Secure flag
Your Set-Cookie header now has HttpOnly; Secure; SameSite=Lax; Max-Age=2592000, which aligns with best practices.


448-470: Logout handler correctly clears session
Deleting the session:${sessionId}:tokens key and clearing the cookie with Secure; SameSite=Lax is spot-on.


473-483: safeStringify covers edge cases
This helper gracefully handles errors and unstringifiable objects. It’s concise and effective.


495-557: Layout load function and token refresh logic are correct
The session lookup, expiration check with buffer, and refresh flow cover all necessary cases. Error handling safely falls back to unauthenticated.


592-635: Dashboard route protection is solid
You correctly redirect unauthenticated users and extract userId from the ID token. In a Cloudflare Pages environment, atob is available, so this will run smoothly.

@KeeganBeuthin
Copy link
Contributor Author

resolved a few of the comments that were outdated.

@clairekinde11 clairekinde11 requested review from clairekinde11, alex72508 and DanielRivers and removed request for alex72508 May 20, 2025 02:44
@@ -0,0 +1,638 @@
---
page_id: 4f3a9e2a-12eb-4b4c-8790-48b6e09a224d
Copy link
Collaborator

@clairekinde11 clairekinde11 May 20, 2025

Choose a reason for hiding this comment

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

Please use the following as front matter:

---
page_id: 4f3a9e2a-12eb-4b4c-8790-48b6e09a224d
title: Kinde with Sveltekit on Cloudflare Pages
sidebar:
  order: 9
relatedArticles:
  - 855e5ca8-f2fb-4162-a594-10cee8a2ff8b
  - f1ba22b9-b35f-478a-be09-4524d060fe36
  - 00d62179-e0e8-489c-90f7-9a593f3b058a
---

This guide walks you through implementing Kinde authentication in a SvelteKit application deployed to Cloudflare Pages using KV storage for state management.


> Note: This implementation is more complex than ideal due to Cloudflare's serverless environment constraints. We're working on more elegant solutions, but this guide provides a robust working implementation.
Copy link
Collaborator

@clairekinde11 clairekinde11 May 20, 2025

Choose a reason for hiding this comment

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

Notes and warnings, etc. are rendered in markdown as:

<Aside type="warning">

This implementation is more complex than ideal due to Cloudflare's serverless environment constraints. We're working on more elegant solutions, but this guide provides a robust working implementation.

</Aside>


> Note: This implementation is more complex than ideal due to Cloudflare's serverless environment constraints. We're working on more elegant solutions, but this guide provides a robust working implementation.

## Prerequisites
Copy link
Collaborator

Choose a reason for hiding this comment

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

Rename to : What you need

- A Kinde account (register at [kinde.com](https://kinde.com))
- SvelteKit project ready for Cloudflare Pages deployment

## 1. Set Up a Kinde Application
Copy link
Collaborator

Choose a reason for hiding this comment

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

Our styling for step headings is 'Step #: Heading' Use colon.

Step 1: Heading

Step 2: Heading

etc

Copy link
Collaborator

Choose a reason for hiding this comment

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

Application should be lowercase

Copy link
Collaborator

Choose a reason for hiding this comment

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

Also we use Sentence case, not title case

A few heading fixes and punctuation updates.
KINDE_DEBUG = "false"
```

## 4.1 Add KINDE_CLIENT_SECRET Separately from a .dev.vars file to avoid leaking your secret.
Copy link
Collaborator

Choose a reason for hiding this comment

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

We don't use substep headings. Make this a h3 if it's part of step 4, or else renumber headings to make this 5.

Copy link
Contributor

@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: 2

♻️ Duplicate comments (10)
src/content/docs/integrate/third-party-tools/kinde-sveltekit-with-cloudflare.mdx (10)

13-13: Rename "Prerequisites" heading to "What you need"
Per style guidelines, the first section should be titled What you need.


152-152: 🛠️ Refactor suggestion

Standardize step heading style
Update to:

- ## 7. Implement authentication routes
+ ## Step 7: Implement authentication routes

587-587: 🛠️ Refactor suggestion

Standardize step heading style
Update to:

- ## 9. Protect routes
+ ## Step 9: Protect routes

132-132: 🛠️ Refactor suggestion

Standardize step heading style
Update to:

- ## 6. Set up SvelteKit Hooks
+ ## Step 6: Set up SvelteKit hooks

36-36: 🛠️ Refactor suggestion

Standardize step heading style
Update to:

- ## 3. Configure Cloudflare KV Storage
+ ## Step 3: Configure Cloudflare KV storage

485-488: 🛠️ Refactor suggestion

Standardize step heading style
Update to:

- ## 8. Check Authentication Status
+ ## Step 8: Check authentication status

71-71: 🛠️ Refactor suggestion

Standardize step heading style
Update to:

- ## 5. Create a KV Storage Adapter
+ ## Step 5: Create a KV storage adapter

11-11: 🛠️ Refactor suggestion

Use <Aside> component for warnings
Replace the blockquote note with the <Aside type="warning"> component to ensure it renders consistently with our design system:

- > Note: This implementation is more complex than ideal due to Cloudflare's serverless environment constraints. …
+ <Aside type="warning">
+
+ This implementation is more complex than ideal due to Cloudflare's serverless environment constraints. …
+
+ </Aside>

19-19: 🛠️ Refactor suggestion

Standardize step headings with "Step #: Heading"
Use our pattern for numbered steps with a colon and sentence case. For example:

- ## 1. Set Up a Kinde application
+ ## Step 1: Set up a Kinde application

1-5: ⚠️ Potential issue

Complete front matter for sidebar and related articles
The front matter is missing the sidebar, order, and relatedArticles fields required by our documentation templates. Please update to match the standard front matter:

---
 page_id: 4f3a9e2a-12eb-4b4c-8790-48b6e09a224d
 title: "Integrating Kinde Authentication with SvelteKit on Cloudflare Pages"
+sidebar:
+  order: 9
+relatedArticles:
+  - 855e5ca8-f2fb-4162-a594-10cee8a2ff8b
+  - f1ba22b9-b35f-478a-be09-4524d060fe36
+  - 00d62179-e0e8-489c-90f7-9a593f3b058a
 description: "A step-by-step guide to implement Kinde authentication in a SvelteKit application deployed to Cloudflare Pages"
---
🧹 Nitpick comments (8)
src/content/docs/integrate/third-party-tools/kinde-sveltekit-with-cloudflare.mdx (8)

31-34: Combine installation commands for brevity
You can merge the two npm install commands into one for conciseness:

 ```bash
-npm install @kinde-oss/kinde-auth-sveltekit
-npm install -D @sveltejs/adapter-cloudflare
+npm install @kinde-oss/kinde-auth-sveltekit
+npm install --save-dev @sveltejs/adapter-cloudflare

---

`67-70`: **Consolidate secret instructions under the main Wrangler setup**  
Rather than a separate "4.1" subheading, consider folding the `wrangler secret put` guidance into Step 4 to keep numbering flat and clear.

---

`75-130`: **Improve error handling in the storage adapter**  
Currently errors are swallowed (returning `false`/`null`) without logging, which can make debugging difficult. Consider logging the error message before returning, or throwing an explicit error to bubble up issues:

```diff
   setState: async (stateId: string, stateData: any) => {
     try {
       …
     } catch (error) {
-      return false;
+      console.error(`createKindeStorage.setState error for ${stateId}:`, error);
+      return false;
     }
   },

154-200: Format imports and spacing for readability
Split the long import onto multiple lines and ensure spaces after commas:

-import { KINDE_ISSUER_URL, KINDE_CLIENT_ID, KINDE_CLIENT_SECRET, KINDE_REDIRECT_URL, KINDE_POST_LOGIN_REDIRECT_URL, KINDE_POST_LOGOUT_REDIRECT_URL, KINDE_AUTH_WITH_PKCE,KINDE_SCOPE } from '$env/static/private';
+import {
+  KINDE_ISSUER_URL,
+  KINDE_CLIENT_ID,
+  KINDE_CLIENT_SECRET,
+  KINDE_REDIRECT_URL,
+  KINDE_POST_LOGIN_REDIRECT_URL,
+  KINDE_POST_LOGOUT_REDIRECT_URL,
+  KINDE_AUTH_WITH_PKCE,
+  KINDE_SCOPE
+} from '$env/static/private';

224-275: Add error handling around storage operations
Wrap calls to storage.setState in try/catch or at least check the boolean return value to ensure state or redirect is stored successfully before proceeding.


383-444: Simplify PKCE verification logic
The check codeVerifier !== 'true' is unnecessary—codeVerifier is either a generated string or undefined. Simplify to:

- if (USE_PKCE && codeVerifier && codeVerifier !== 'true') {
+ if (USE_PKCE && codeVerifier) {

490-492: Remove unused kindeAuthClient import
kindeAuthClient is imported but never used. Consider removing this line to prevent confusion:

- import { kindeAuthClient } from '@kinde-oss/kinde-auth-sveltekit';

592-635: Type and reuse the getUserIdFromToken helper
Define the function signature explicitly and consider sharing it between the callback and dashboard logic to avoid duplication. For example:

- function getUserIdFromToken(idToken) {
+ function getUserIdFromToken(idToken: string): string | null {
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 95fed36 and 4141782.

📒 Files selected for processing (1)
  • src/content/docs/integrate/third-party-tools/kinde-sveltekit-with-cloudflare.mdx (1 hunks)
🔇 Additional comments (4)
src/content/docs/integrate/third-party-tools/kinde-sveltekit-with-cloudflare.mdx (4)

137-150: Hooks integration snippet looks correct
The handle function properly injects the KV storage adapter into sessionHooks.


202-209: Helper functions are correctly implemented
generateRandomString, sha256, and base64URLEncode use secure APIs and handle encoding/decoding appropriately.


448-470: Logout handler correctly clears session
The code properly deletes the KV entry and clears the secure session cookie.


472-483: Error stringification helper is robust
safeStringify handles both Error instances and arbitrary objects safely.

@clairekinde11
Copy link
Collaborator

Hey @KeeganBeuthin I'm not able to do a code check, but from a style/copy perspective I left a few comments. Here's our contribution guide for future topics - https://docs.kinde.com/contribute/

Copy link
Contributor

@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: 1

♻️ Duplicate comments (2)
src/content/docs/integrate/third-party-tools/kinde-sveltekit-with-cloudflare.mdx (2)

51-54: Standardize Step 4 heading style
The heading uses “Set Up” instead of “Set up”. This duplicates an earlier suggestion.


286-389: ⚠️ Potential issue

Namespace token_error storage to avoid collisions
Storing errors under a global key risks overlapping diagnostics across flows. Use a state-specific key like error:${state}.

- await storage.setState('token_error', {
+ await storage.setState(`error:${state}`, {
     time: new Date().toISOString(),
     error: safeStringify(error)
   });
🧹 Nitpick comments (5)
src/content/docs/integrate/third-party-tools/kinde-sveltekit-with-cloudflare.mdx (5)

28-37: Use sentence case for step headings
The step title uses “Set Up” (title case). To align with Sentence case guidelines, change to “Set up”.

- ## Step 1: Set Up a Kinde application
+ ## Step 1: Set up a Kinde application

45-50: Sentence case for Storage step
Change “Configure Cloudflare KV Storage” to “Configure Cloudflare KV storage” to match Sentence case conventions.

- ## Step 3: Configure Cloudflare KV Storage
+ ## Step 3: Configure Cloudflare KV storage

56-74: Consider updating compatibility_date
The compatibility_date = "2023-06-28" is outdated for a 2025 deployment. Updating this to a more recent date ensures alignment with Cloudflare Pages’ current environment.

- compatibility_date = "2023-06-28"
+ compatibility_date = "2025-05-01"  # or the current date of merge

84-139: Enhance storage adapter error visibility
Silent return false/null in catch blocks can obscure underlying issues. Logging the error message will aid debugging.

     } catch (error) {
-      return false;
+      console.error('KV setState error:', error);
+      return false;
     }
...
     } catch (error) {
-      return null;
+      console.error('KV getState error:', error);
+      return null;
     }
...
     } catch (error) {
-      return false;
+      console.error('KV deleteState error:', error);
+      return false;
     }

392-450: Clean up unnecessary codeVerifier check
Since you only store a verifier when PKCE is enabled, the && codeVerifier !== 'true' guard is redundant. Remove it for clarity.

- if (USE_PKCE && codeVerifier && codeVerifier !== 'true') {
+ if (USE_PKCE && codeVerifier) {
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4141782 and 1cb94d9.

📒 Files selected for processing (1)
  • src/content/docs/integrate/third-party-tools/kinde-sveltekit-with-cloudflare.mdx (1 hunks)
🔇 Additional comments (14)
src/content/docs/integrate/third-party-tools/kinde-sveltekit-with-cloudflare.mdx (14)

1-10: Front matter is correctly formatted
The YAML front matter matches the project’s required keys and indentation style.


16-20: Admonition formatting looks good
The <Aside type="warning"> block has the proper blank lines before and after content, matching the project’s style.


22-27: Checklist section is clear
The “## What you need” heading and its bullet list correctly outline prerequisites.


40-43: Installation instructions are accurate
The npm install commands are clear and correct for both production and dev dependencies.


143-159: Hook integration is correct
The handle implementation ties Kinde session hooks to the custom storage adapter as intended.


165-209: Auth route dispatcher looks solid
The switch on the trailing path segment and early storage availability check handle the OAuth flows as expected.


211-217: Secure random generation is implemented properly
The generateRandomString function uses crypto.getRandomValues and a suitable character set.


220-230: PKCE helper functions are well-defined
The sha256 and base64URLEncode implementations follow the PKCE spec and use the Web Crypto API.


234-284: Login handler logic is clear and robust
State, PKCE, and redirect parameter handling appear correct, with clean separation of concerns.


456-479: Logout handler properly clears session
The session cookie is securely cleared with the Secure flag, and the redirect to Kinde’s logout endpoint is correct.


481-492: Error stringification helper is effective
The safeStringify function cleanly handles both Error instances and arbitrary objects.


499-567: Layout load implements token refresh logic correctly
Your logic for reading the session cookie, checking expiry, and refreshing tokens is sound and includes a safety buffer.


569-593: Refresh token flow is well-handled
The refresh request parameters, error handling, and response parsing cover expected failure modes.


601-644: Protected route enforcement is correct
The dashboard loader enforces authentication, redirects unauthenticated users, and extracts the user ID safely.

Copy link
Contributor

@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: 0

♻️ Duplicate comments (1)
src/content/docs/integrate/third-party-tools/kinde-sveltekit-with-cloudflare.mdx (1)

381-386: ⚠️ Potential issue

Namespace token-error storage to avoid collisions
You’re writing errors under the fixed key token_error, which can overwrite errors from concurrent sessions. Prefix it with the flow’s state or session ID—e.g., error:${state}—to isolate per-flow diagnostics.

- await storage.setState('token_error', {
+ await storage.setState(`error:${state}`, {
🧹 Nitpick comments (9)
src/content/docs/integrate/third-party-tools/kinde-sveltekit-with-cloudflare.mdx (9)

1-4: Capitalize "SvelteKit" correctly in the title
The front-matter title uses "Sveltekit" (lowercase K). For consistency with the product name, update it to "SvelteKit".

--- title: Kinde with Sveltekit on Cloudflare Pages
+++ title: Kinde with SvelteKit on Cloudflare Pages

28-28: Ensure consistent sentence-case in step headings
The first step heading uses "Set Up" (title case) while others use sentence case. Change to "Set up a Kinde application" to match style.

- ## Step 1: Set Up a Kinde application
+ ## Step 1: Set up a Kinde application

52-52: Ensure consistent sentence-case in step headings
Similarly, update "Set Up Wrangler configuration" to "Set up Wrangler configuration" for consistency.

- ## Step 4: Set Up Wrangler configuration
+ ## Step 4: Set up Wrangler configuration

76-79: Avoid using a sub-heading for a single note
The line "### Add KINDE_CLIENT_SECRET separately…" is rendered as a tertiary heading. Per style, convert this into a regular paragraph or wrap in an <Aside> block so it doesn’t interrupt the step flow.


56-63: Refresh compatibility_date to latest Cloudflare environment
The example uses "2023-06-28". It’s best practice to bump this to the current date (e.g., "2025-05-01") so readers know it’s tested against the latest Pages runtime.

- compatibility_date = "2023-06-28"
+ compatibility_date = "2025-05-01"

40-43: Combine installation commands for brevity
You can merge the two npm install commands into one to streamline the instructions.

npm install @kinde-oss/kinde-auth-sveltekit @sveltejs/adapter-cloudflare --save-dev

87-94: Handle missing KV binding more explicitly
Currently createKindeStorage returns null if AUTH_STORAGE isn’t bound—this may lead to silent failures downstream. Consider throwing an error or logging a warning so implementers know their binding is misconfigured.

-  if (!AUTH_STORAGE) {
-    return null;
-  }
+  if (!AUTH_STORAGE) {
+    console.error('AUTH_STORAGE namespace is not bound in wrangler.toml');
+    throw new Error('Missing KV binding: AUTH_STORAGE');
+  }

183-185: Use SvelteKit’s route params instead of manual URL splitting
Parsing the endpoint by url.pathname.split('/').pop() can break if the path changes. Since this is in a [...kindeAuth] route, you can access the segment via event.params.kindeAuth.

- const path = url.pathname.split('/').pop() || '';
+ const path = event.params.kindeAuth;

459-462: Use SvelteKit’s cookie API in logout handler
Instead of parsing event.request.headers.get('cookie'), leverage event.cookies.get('kinde_session') and event.cookies.delete('kinde_session') for clarity and maintainability.

- const cookies = event.request.headers.get('cookie') || '';
- const sessionMatch = cookies.match(/kinde_session=([^;]+)/);
- const sessionId = sessionMatch ? sessionMatch[1] : null;
+ const sessionId = event.cookies.get('kinde_session');
+ if (sessionId) {
+   event.cookies.delete('kinde_session', { path: '/', httpOnly: true, sameSite: 'Lax', secure: true });
+ }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1cb94d9 and ca5d150.

📒 Files selected for processing (1)
  • src/content/docs/integrate/third-party-tools/kinde-sveltekit-with-cloudflare.mdx (1 hunks)

@DanielRivers
Copy link
Member

Hi @KeeganBeuthin As you alluded to there is quite a bit of code here, many of the method and functions here and the flows are included in the @kinde/js-utils package. The KV store can be adopted in there. Lets arrange a call and I can discuss options with you on this. 👍

Copy link
Member

@DanielRivers DanielRivers left a comment

Choose a reason for hiding this comment

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

Needs better utilisaton of @kinde/js-utils

Copy link
Contributor

@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: 3

🧹 Nitpick comments (2)
src/content/docs/integrate/third-party-tools/kinde-sveltekit-with-cloudflare.mdx (2)

154-156: Global storage assignment can race across concurrent requests

setActiveStorage stores the KV instance in a module-level singleton. On Cloudflare Workers, multiple requests share the same isolate, so a second request can overwrite the storage while the first is still executing. Consider returning the storage object from initializeKindeAuth and passing it explicitly to js-utils functions that allow it, or open an issue to add per-request context support in @kinde/js-utils.


24-28: Minor grammar: plural noun without article

“A Cloudflare account with Pages and KV access” reads smoother as:

- A Cloudflare account with Pages and KV access
+ A Cloudflare account with access to Pages and KV

Purely editorial – ignore if house style differs.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ca5d150 and e359991.

📒 Files selected for processing (1)
  • src/content/docs/integrate/third-party-tools/kinde-sveltekit-with-cloudflare.mdx (1 hunks)
🧰 Additional context used
🪛 LanguageTool
src/content/docs/integrate/third-party-tools/kinde-sveltekit-with-cloudflare.mdx

[grammar] ~26-~26: The verb form ‘access’ does not seem to match the subject ‘KV’.
Context: ... A Cloudflare account with Pages and KV access - A Kinde account with an SPA applicati...

(SUBJECT_VERB_AGREEMENT)

@KeeganBeuthin
Copy link
Contributor Author

changes made to utilize js-utils. Documentation is reliant on pending approval of kinde-oss/js-utils#142

Copy link
Contributor

@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: 3

🧹 Nitpick comments (3)
src/content/docs/integrate/third-party-tools/kinde-sveltekit-with-cloudflare.mdx (3)

24-29: Minor copy-editing for prerequisites list
The first list item reads “Pages and KV access”. For subject/verb agreement and clarity consider:

- A Cloudflare account with Pages and KV access
+ A Cloudflare account with access to Cloudflare Pages and KV

Tiny polish, but it prevents the “KV access” grammar warning flagged by tooling.


39-42: Add missing article in step description
“In Cloudflare dashboard” should include the article “the” to read naturally:

- In Cloudflare dashboard, go to **Workers & Pages > KV**
+ In the Cloudflare dashboard, go to **Workers & Pages > KV**

48-52: Update compatibility_date to avoid unexpected runtime differences
compatibility_date = "2023-06-28" is quite old. New contributors copying this file may hit subtle runtime differences (e.g. URL pattern handling) because Workers activates backwards-compat shims for that date. Unless you rely on legacy behaviour, bump this to today’s date or add a note explaining the freeze.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e359991 and aa6a1f6.

📒 Files selected for processing (1)
  • src/content/docs/integrate/third-party-tools/kinde-sveltekit-with-cloudflare.mdx (1 hunks)
🧰 Additional context used
🪛 LanguageTool
src/content/docs/integrate/third-party-tools/kinde-sveltekit-with-cloudflare.mdx

[grammar] ~26-~26: The verb form ‘access’ does not seem to match the subject ‘KV’.
Context: ... A Cloudflare account with Pages and KV access - A Kinde account with an SPA applicati...

(SUBJECT_VERB_AGREEMENT)


[uncategorized] ~39-~39: You might be missing the article “the” here.
Context: ... Configure Cloudflare KV storage 1. In Cloudflare dashboard, go to **Workers & Pages > KV...

(AI_EN_LECTOR_MISSING_DETERMINER_THE)


[uncategorized] ~74-~74: You might be missing the article “a” here.
Context: ...DE_CLIENT_SECRET ``` ## Step 4: Create hybrid storage adapter Create `src/lib/kindeA...

(AI_EN_LECTOR_MISSING_DETERMINER_A)

Comment on lines +266 to +270
// Handle expected window error in server environment
if (error instanceof Error && error.message.includes('window')) {
// Wait for async token storage to complete
await new Promise(resolve => setTimeout(resolve, 2000));
return redirect(302, config.postLoginRedirectURL);
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Replace arbitrary 2 s sleep with deterministic wait
Using setTimeout(2000) to “wait for async token storage” is brittle: slow writes may still race; fast writes waste 2 s. Prefer awaiting the promise returned by exchangeAuthCode (it already resolves after storage) or expose a flush() helper from your storage adapter.

-      await new Promise(resolve => setTimeout(resolve, 2000));
+      // Storage write completed inside exchangeAuthCode; no need to delay.

If @kinde/js-utils truly emits the window error before the promise settles, consider opening an issue upstream instead of hard-coding a delay.

🤖 Prompt for AI Agents
In
src/content/docs/integrate/third-party-tools/kinde-sveltekit-with-cloudflare.mdx
around lines 266 to 270, replace the arbitrary 2-second setTimeout delay used to
wait for async token storage with a deterministic wait by awaiting the promise
returned by the async token storage function (such as exchangeAuthCode) or by
calling a flush() method from the storage adapter if available. This ensures the
code only proceeds after token storage completes, avoiding brittle fixed delays.

Comment on lines +278 to +283
async function handleLogout(config: ReturnType<typeof getConfig>) {
const logoutUrl = new URL('/logout', config.issuerURL);
logoutUrl.searchParams.append('redirect', config.postLogoutRedirectURL);

return redirect(302, logoutUrl.toString());
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Logout endpoint doesn’t clear local session data
Redirecting to Kinde’s /logout without first deleting session cookies or KV tokens means the user can still appear authenticated until the IdP callback returns. Clear both stores before redirecting:

 async function handleLogout(config: ReturnType<typeof getConfig>) {
+  // Clear local auth
+  await setActiveStorage().removeSession(); // pseudo-code – adjust to actual js-utils API
+
   const logoutUrl = new URL('/logout', config.issuerURL);
   logoutUrl.searchParams.append('redirect', config.postLogoutRedirectURL);
   return redirect(302, logoutUrl.toString());
 }

This ensures instant sign-out and avoids token reuse in subsequent requests.

📝 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
async function handleLogout(config: ReturnType<typeof getConfig>) {
const logoutUrl = new URL('/logout', config.issuerURL);
logoutUrl.searchParams.append('redirect', config.postLogoutRedirectURL);
return redirect(302, logoutUrl.toString());
}
async function handleLogout(config: ReturnType<typeof getConfig>) {
// Clear local auth
await setActiveStorage().removeSession(); // pseudo-code – adjust to actual js-utils API
const logoutUrl = new URL('/logout', config.issuerURL);
logoutUrl.searchParams.append('redirect', config.postLogoutRedirectURL);
return redirect(302, logoutUrl.toString());
}
🤖 Prompt for AI Agents
In
src/content/docs/integrate/third-party-tools/kinde-sveltekit-with-cloudflare.mdx
around lines 278 to 283, the logout function redirects to the logout URL without
clearing local session data, which can cause the user to appear authenticated
temporarily. Modify the function to clear session cookies and any KV tokens or
local storage related to authentication before performing the redirect. This
ensures immediate sign-out and prevents token reuse in subsequent requests.

Comment on lines +138 to +157
export function initializeKindeAuth(event: RequestEvent): boolean {
const platform = event.platform as any;
const env = platform?.env;
const AUTH_STORAGE = env?.AUTH_STORAGE;

if (!AUTH_STORAGE) {
console.error('KV storage not available');
return false;
}

// KV storage for long-term token storage
const tokenStorage = new KvStorage(AUTH_STORAGE, { defaultTtl: 2592000 });

// Cookie storage for temporary OAuth data
const tempStorage = new CookieStorage(event);

// Set up js-utils storage
setActiveStorage(tokenStorage); // For tokens
setInsecureStorage(tempStorage); // For OAuth temp data

Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Avoid re-registering global storage on every request
setActiveStorage and setInsecureStorage mutate singleton state inside @kinde/js-utils. Calling them on every request can introduce race conditions under high concurrency and unnecessary object churn.

Suggested pattern:

-let tokenStorage: KvStorage | undefined;
-let tempStorage: CookieStorage | undefined;
-
-export function initializeKindeAuth(event: RequestEvent): boolean {
-
-  // KV storage for long-term token storage
-  tokenStorage = tokenStorage ?? new KvStorage(AUTH_STORAGE, { defaultTtl: 2592000 });
-  // Cookie storage for temporary OAuth data
-  tempStorage = new CookieStorage(event);
-  setActiveStorage(tokenStorage);
-  setInsecureStorage(tempStorage);
-
-}
+const globalTokenStorage = new WeakMap<object, KvStorage>();
+
+export function initializeKindeAuth(event: RequestEvent): boolean {
+
+  if (!globalTokenStorage.has(AUTH_STORAGE)) {
+    globalTokenStorage.set(AUTH_STORAGE, new KvStorage(AUTH_STORAGE, { defaultTtl: 2592000 }));
+    setActiveStorage(globalTokenStorage.get(AUTH_STORAGE)!);
+  }
+  setInsecureStorage(new CookieStorage(event)); // per-request, fine
+
+}

That ensures the heavy KV instance is initialised once per process while keeping per-request cookie storage.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In
src/content/docs/integrate/third-party-tools/kinde-sveltekit-with-cloudflare.mdx
around lines 138 to 157, the calls to setActiveStorage and setInsecureStorage
are made on every request, which can cause race conditions and unnecessary
object creation. Refactor the code to initialize the KV storage and call
setActiveStorage once per process outside the request handler, while keeping the
CookieStorage and setInsecureStorage calls inside the request handler to
maintain per-request state. This avoids re-registering global storage on every
request and improves concurrency safety.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants