fix: update Kinde and Convex guide for better integration#669
fix: update Kinde and Convex guide for better integration#669tamalchowdhury wants to merge 7 commits intomainfrom
Conversation
WalkthroughThe Kinde + Convex integration documentation is significantly expanded from a brief overview to a comprehensive step-by-step tutorial, including project setup, OAuth authentication wiring, Convex backend schemas with webhook syncing, and a real-time message board example with styling. The guide now provides end-to-end code examples and implementation patterns. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
Deploying kinde-docs-preview with
|
| Latest commit: |
8555a00
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://c7fdc4f7.kinde-docs-preview.pages.dev |
| Branch Preview URL: | https://tamal-update-convex-auth-upd.kinde-docs-preview.pages.dev |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
src/content/docs/integrate/third-party-tools/kinde-and-convex.mdx (1)
423-425: Consider adding an explicitKINDE_DOMAINguard in the webhook code example for clarity.Line 423 in the webhook handler calls
decodeWebhook(jwt, process.env.KINDE_DOMAIN)without first validating that the environment variable is set. While the guide documents settingKINDE_DOMAINas a prerequisite step, adding an explicit guard would make the example more robust and educate developers on handling missing environment variables:Suggested documentation improvement
- const decoded = await decodeWebhook(jwt, process.env.KINDE_DOMAIN); // https://<your_kinde_business>.kinde.com + const kindeDomain = process.env.KINDE_DOMAIN; + if (!kindeDomain) { + return new Response("Server misconfiguration: KINDE_DOMAIN is not set", { status: 500 }); + } + const decoded = await decodeWebhook(jwt, kindeDomain); // https://<your_kinde_business>.kinde.com🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/content/docs/integrate/third-party-tools/kinde-and-convex.mdx` around lines 423 - 425, Add an explicit guard that validates process.env.KINDE_DOMAIN before calling decodeWebhook(jwt, process.env.KINDE_DOMAIN): check that the environment variable is present and non-empty (e.g., in the webhook handler function where jwt is used), and if missing return an early Response with an appropriate error status and message (so the call to decodeWebhook is never made with an undefined domain); reference the decodeWebhook call, the jwt variable, and process.env.KINDE_DOMAIN when adding this conditional check and early return.
🤖 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/integrate/third-party-tools/kinde-and-convex.mdx`:
- Around line 296-306: The one-time upsert guard incorrectly sets
hasUpserted.current = true before storeUser completes and never resets on
sign-out; update the useEffect that references hasUpserted, isAuthenticated,
user, and storeUser so that: (1) when !isAuthenticated || !user you reset
hasUpserted.current = false, and (2) only set hasUpserted.current = true after
the Promise returned by storeUser resolves successfully (handle errors without
flipping the flag). This ensures retries on failure and re-syncs after a new
sign-in.
- Around line 54-58: The quickstart step currently installs only "convex" but
the guide later imports "@kinde-oss/kinde-auth-react" (seen in imports like
`@kinde-oss/kinde-auth-react`), causing module-not-found errors; update the
install instruction (the step that runs npm install convex) to also install
"@kinde-oss/kinde-auth-react" (e.g., npm install convex
`@kinde-oss/kinde-auth-react`) so fresh setups have both dependencies available.
- Around line 138-139: The auth flow in useAuthFromKinde() is using
getAccessToken() but Convex custom auth requires the ID token; update
useAuthFromKinde() to call getIdToken() instead of getAccessToken(), pass that
ID token where the Convex auth payload is constructed (the value used for
applicationID/aud checks), and ensure any variable names or comments reflect
that this token is the ID token used for identity/authentication.
---
Nitpick comments:
In `@src/content/docs/integrate/third-party-tools/kinde-and-convex.mdx`:
- Around line 423-425: Add an explicit guard that validates
process.env.KINDE_DOMAIN before calling decodeWebhook(jwt,
process.env.KINDE_DOMAIN): check that the environment variable is present and
non-empty (e.g., in the webhook handler function where jwt is used), and if
missing return an early Response with an appropriate error status and message
(so the call to decodeWebhook is never made with an undefined domain); reference
the decodeWebhook call, the jwt variable, and process.env.KINDE_DOMAIN when
adding this conditional check and early return.
| 4. Install the Convex dependencies: | ||
|
|
||
|  | ||
| ```bash | ||
| npm install convex | ||
| ``` |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, let's examine the file to see the actual content at the specified lines
cat -n src/content/docs/integrate/third-party-tools/kinde-and-convex.mdx | sed -n '50,80p'Repository: kinde-oss/documentation
Length of output: 1414
🏁 Script executed:
# Check all import statements and npm install commands in the file
rg -n 'npm install|import.*kinde|from.*kinde' src/content/docs/integrate/third-party-tools/kinde-and-convex.mdxRepository: kinde-oss/documentation
Length of output: 763
🏁 Script executed:
# Let's also check what Kinde packages are documented elsewhere in the repo
fd -e mdx -e md | head -20 | xargs rg -h 'npm install.*kinde|@kinde-oss|kinde/' | sort | uniqRepository: kinde-oss/documentation
Length of output: 9342
🏁 Script executed:
# Check all npm install commands in the repo to see package naming patterns
rg -n 'npm install.*kinde' src/content/docs --type mdx -A 2 -B 2 | head -100Repository: kinde-oss/documentation
Length of output: 94
🏁 Script executed:
# Look for package.json files or NPM registry info about kinde packages
find . -name "package.json" -type f | head -5 | xargs cat 2>/dev/null | grep -A 5 -B 5 'kinde' | head -50Repository: kinde-oss/documentation
Length of output: 49
🏁 Script executed:
# Search for references to the auth react package across the docs
rg '@kinde.*auth.*react|kinde.*auth.*react' src/content/docs --type mdx | cut -d: -f2 | sort | uniqRepository: kinde-oss/documentation
Length of output: 94
🏁 Script executed:
# Check all npm install commands mentioning kinde across docs
rg 'npm install.*kinde' src/content/docs -A 2 -B 2Repository: kinde-oss/documentation
Length of output: 1814
🏁 Script executed:
# Search all mdx files for kinde package references to see patterns
rg '@kinde' src/content/docsRepository: kinde-oss/documentation
Length of output: 50379
🏁 Script executed:
# Look at other integration guides to see what packages they recommend
fd '\.mdx$' src/content/docs/integrate | head -10 | xargs rg 'npm install' -A 1Repository: kinde-oss/documentation
Length of output: 406
Quickstart is missing required dependency install.
Line 57 installs only convex, but lines 74, 106, and 158 import @kinde-oss/kinde-auth-react. Fresh setups will fail with module not found errors.
🔧 Proposed fix
- npm install convex
+ npm install convex `@kinde-oss/kinde-auth-react`📝 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.
| 4. Install the Convex dependencies: | |
|  | |
| ```bash | |
| npm install convex | |
| ``` | |
| 4. Install the Convex dependencies: |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/content/docs/integrate/third-party-tools/kinde-and-convex.mdx` around
lines 54 - 58, The quickstart step currently installs only "convex" but the
guide later imports "@kinde-oss/kinde-auth-react" (seen in imports like
`@kinde-oss/kinde-auth-react`), causing module-not-found errors; update the
install instruction (the step that runs npm install convex) to also install
"@kinde-oss/kinde-auth-react" (e.g., npm install convex
`@kinde-oss/kinde-auth-react`) so fresh setups have both dependencies available.
| // domain must match the ID token's "iss"; applicationID must match the ID token's "aud". | ||
| // Decode your ID token at jwt.io to confirm (use getIdToken() and paste the string). |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n src/content/docs/integrate/third-party-tools/kinde-and-convex.mdx | sed -n '100,150p'Repository: kinde-oss/documentation
Length of output: 1941
🌐 Web query:
Convex custom auth config applicationID JWT audience claim
💡 Result:
In Convex Custom JWT auth, applicationID in convex/auth.config.ts is the value Convex expects to see in the JWT’s aud (audience) claim:
- If you set
applicationID, Convex will verifyjwt.aud === applicationID(exact match). [1] - If you omit
applicationID, Convex does not validateaud, which Convex warns is often insecure (a token minted for another app/service could be replayed against yours). [1]
Example:
export default {
providers: [
{
type: "customJwt",
applicationID: "your-application-id", // must match JWT `aud`
issuer: "https://your.issuer.url.com", // must match JWT `iss`
jwks: "https://your.issuer.url.com/.well-known/jwks.json",
algorithm: "RS256",
},
],
};Source: Convex “Custom JWT Provider” docs. [1]
🌐 Web query:
Kinde getAccessToken vs getIdToken Convex integration
💡 Result:
For a Convex auth integration, you almost always want Kinde’s ID token, not the access token.
getIdToken(OIDC ID token): Proves who the user is (identity). Convex authentication is based on OpenID Connect ID tokens (JWTs). Use this token as the value you pass to Convex (e.g., viaConvexProviderWithAuth/client.setAuth(...)). [1][2]getAccessToken(OAuth access token): Proves what the user can access (authorization) for a specific API/resource (often a differentaud). It’s meant to be sent to your APIs, not used as your app’s “who is logged in” token. [3][4]
Rule of thumb:
- If the token is for Convex user auth → use
getIdToken. [1] - If the token is for calling your backend/API → use
getAccessToken. [3]
If you really want to authenticate Convex using an access token, you must ensure its JWT claims match what Convex validates (notably iss, sub, exp, plus aud/applicationID, and iat for refresh behavior) and configure Convex accordingly (OIDC provider or custom JWT provider). [2]
Sources:
[1] Convex Authentication overview (OIDC ID tokens as JWTs) — https://docs.convex.dev/auth
[2] Convex Custom JWT provider requirements (sub,iss,exp,iat,aud) — https://docs.convex.dev/auth/advanced/custom-jwt
[3] Kinde: About access tokens — https://docs.kinde.com/build/tokens/about-access-tokens/
[4] Kinde: About ID tokens — https://docs.kinde.com/build/tokens/about-id-tokens/
The code at lines 110-115 should use getIdToken() instead of getAccessToken() for Convex authentication.
The comments at lines 138-139 are correct: Convex custom auth validates the ID token's aud claim against applicationID. However, the code uses getAccessToken(), which provides a different token with different claims. For Convex user authentication, the ID token must be used. The getAccessToken() method is for API authorization, not identity authentication.
Update useAuthFromKinde() to call getIdToken() instead of getAccessToken().
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/content/docs/integrate/third-party-tools/kinde-and-convex.mdx` around
lines 138 - 139, The auth flow in useAuthFromKinde() is using getAccessToken()
but Convex custom auth requires the ID token; update useAuthFromKinde() to call
getIdToken() instead of getAccessToken(), pass that ID token where the Convex
auth payload is constructed (the value used for applicationID/aud checks), and
ensure any variable names or comments reflect that this token is the ID token
used for identity/authentication.
| const hasUpserted = useRef(false); | ||
|
|
||
| useEffect(() => { | ||
| if (!isAuthenticated || !user || hasUpserted.current) return; | ||
| hasUpserted.current = true; | ||
| storeUser({ | ||
| givenName: user.givenName, | ||
| familyName: user.familyName, | ||
| email: user.email, | ||
| }).catch(console.error); | ||
| }, [isAuthenticated, user, storeUser]); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n src/content/docs/integrate/third-party-tools/kinde-and-convex.mdx | sed -n '290,310p'Repository: kinde-oss/documentation
Length of output: 888
The one-time upsert guard prevents retries and blocks user syncs across sessions.
Line 300 sets hasUpserted.current = true before storeUser completes, blocking retries if the call fails. More critically, the flag is never reset on sign-out—when the user signs back in, hasUpserted.current remains true from the previous session, causing the new login to skip the upsert entirely.
The proposed fix correctly addresses both issues by resetting the flag when the user is not authenticated or present, and setting it only after storeUser succeeds.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/content/docs/integrate/third-party-tools/kinde-and-convex.mdx` around
lines 296 - 306, The one-time upsert guard incorrectly sets hasUpserted.current
= true before storeUser completes and never resets on sign-out; update the
useEffect that references hasUpserted, isAuthenticated, user, and storeUser so
that: (1) when !isAuthenticated || !user you reset hasUpserted.current = false,
and (2) only set hasUpserted.current = true after the Promise returned by
storeUser resolves successfully (handle errors without flipping the flag). This
ensures retries on failure and re-syncs after a new sign-in.
Description (required)
Restructured the guide for complete integration. Removed dependency from 3rd party adapter. Add clarity to user sync and add advance sync using Kinde webhooks.
Related issues & labels (optional)
Summary by CodeRabbit
Release Notes