Skip to content

feat: instrumentation for kinde auth#39

Merged
sohankshirsagar merged 4 commits intomainfrom
sohan/kinde-instrumentation
Jan 16, 2026
Merged

feat: instrumentation for kinde auth#39
sohankshirsagar merged 4 commits intomainfrom
sohan/kinde-instrumentation

Conversation

@sohankshirsagar
Copy link
Copy Markdown
Contributor

@sohankshirsagar sohankshirsagar commented Jan 16, 2026

Problem

Kinde's StorageManager generates a new random device_id on each server startup. Session data is stored with keys like device:{device_id}:{user_id}. During replay, the new server has a different device_id than the one used during recording, so token lookups fail and is_authenticated() returns False.

Solution

Two-tier patching approach in replay mode:

1. Primary: Patch StorageManager.get()

  • Try normal lookup first
  • If not found, scan session keys for matching pattern with any device ID
  • Extract and cache the correct device ID from the recorded session
  • Return the found token data

This works when apps store Kinde tokens in the session cookie using Kinde's standard storage. This is preferred since this goes through normal auth flow and things like get_user_info will still work as expected.

2. Fallback: Patch all is_authenticated() methods

  • If the StorageManager patch doesn't help (returns False), return True anyway
  • Safe because we're replaying known-good authenticated requests

This fallback handles apps that:

  • Store auth state in custom locations (in-memory dicts, Redis, databases)
  • Use Kinde only for OAuth flow but manage sessions themselves
  • Don't store full token data in session cookies

Note

Adds REPLAY-mode Kinde SDK instrumentation and wires it into auto-init.

  • New KindeInstrumentation patches kinde_sdk in REPLAY: primary patch to StorageManager.get() to recover device-prefixed session data; fallback patches is_authenticated() across Kinde classes/helpers to return True when original returns False
  • Registered Kinde instrumentation in drift_sdk._init_auto_instrumentations() (REPLAY-only)
  • README: adds Kinde to supported packages
  • Type-check config: adds drift/instrumentation/kinde/** to unresolved-import overrides

Written by Cursor Bugbot for commit 2366f1e. This will update automatically on new commits. Configure here.

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

No issues found across 5 files

Copy link
Copy Markdown
Contributor

@jy-tan jy-tan left a comment

Choose a reason for hiding this comment

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

Remember to add to README.md

@sohankshirsagar sohankshirsagar merged commit 5d97f8e into main Jan 16, 2026
18 checks passed
@sohankshirsagar sohankshirsagar deleted the sohan/kinde-instrumentation branch January 16, 2026 20:27
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

2 issues found across 34 files (changes from recent commits).

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="drift/instrumentation/kinde/instrumentation.py">

<violation number="1" location="drift/instrumentation/kinde/instrumentation.py:116">
P2: Guard against missing `is_authenticated` methods. As written, `getattr(cls, method_name)` will raise if the SDK version lacks the method, preventing instrumentation from loading in replay.</violation>

<violation number="2" location="drift/instrumentation/kinde/instrumentation.py:145">
P2: Handle missing `is_authenticated` function in helpers. `getattr(module, func_name)` will raise if the function is absent, which can stop instrumentation during replay.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Returns:
True if patching succeeded, False otherwise.
"""
original = getattr(module, func_name)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: Handle missing is_authenticated function in helpers. getattr(module, func_name) will raise if the function is absent, which can stop instrumentation during replay.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At drift/instrumentation/kinde/instrumentation.py, line 145:

<comment>Handle missing `is_authenticated` function in helpers. `getattr(module, func_name)` will raise if the function is absent, which can stop instrumentation during replay.</comment>

<file context>
@@ -101,11 +102,77 @@ def _scan_session_for_key(session: Any, target_key: str) -> tuple[str | None, An
+    Returns:
+        True if patching succeeded, False otherwise.
+    """
+    original = getattr(module, func_name)
+
+    def patched(*args: Any, **kwargs: Any) -> bool:
</file context>
Suggested change
original = getattr(module, func_name)
original = getattr(module, func_name, None)
if original is None:
logger.debug(f"[KindeInstrumentation] {module_name}.{func_name}() not found, skipping patch")
return False

Returns:
True if patching succeeded, False otherwise.
"""
original = getattr(cls, method_name)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: Guard against missing is_authenticated methods. As written, getattr(cls, method_name) will raise if the SDK version lacks the method, preventing instrumentation from loading in replay.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At drift/instrumentation/kinde/instrumentation.py, line 116:

<comment>Guard against missing `is_authenticated` methods. As written, `getattr(cls, method_name)` will raise if the SDK version lacks the method, preventing instrumentation from loading in replay.</comment>

<file context>
@@ -101,11 +102,77 @@ def _scan_session_for_key(session: Any, target_key: str) -> tuple[str | None, An
+    Returns:
+        True if patching succeeded, False otherwise.
+    """
+    original = getattr(cls, method_name)
+
+    def patched(*args: Any, **kwargs: Any) -> bool:
</file context>
Suggested change
original = getattr(cls, method_name)
original = getattr(cls, method_name, None)
if original is None:
logger.debug(f"[KindeInstrumentation] {class_name}.{method_name}() not found, skipping patch")
return False

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.


_patch_is_authenticated_function(helpers, "is_authenticated", "helpers")
except ImportError:
logger.debug("[KindeInstrumentation] Could not import helpers, skipping patch")
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Incomplete exception handling misses AttributeError from getattr

Medium Severity

The try-except blocks in _patch_all_is_authenticated_methods only catch ImportError, but the helper functions _patch_is_authenticated_method and _patch_is_authenticated_function use getattr(cls, method_name) without a default value at lines 116 and 145. If a class is imported successfully but lacks the is_authenticated method (e.g., due to API changes in a future Kinde SDK version), an uncaught AttributeError will propagate. Since _apply_patch in the registry has no exception handling, this could fail the entire instrumentation. The Django instrumentation shows the preferred pattern with except Exception as a fallback.

Additional Locations (2)

Fix in Cursor Fix in Web

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.

2 participants