RJ
RJ•14mo ago

User impersonation with Clerk

I'm implementing user impersonation with Clerk (https://clerk.com/docs/custom-flows/user-impersonation), and appear to have succeed in creating an actor token through Clerk's API and authenticating with it. My ostensible proof of this:
import { useAuth } from "@clerk/clerk-react";

// ...

const { actor } = useAuth(); // `actor` is present
import { useAuth } from "@clerk/clerk-react";

// ...

const { actor } = useAuth(); // `actor` is present
My understanding, per https://clerk.com/docs/custom-flows/user-impersonation#jwt-claims, is when impersonating a user, the sub claim should contain the ID for the impersonated user, so Convex should by default in all regards treat the impersonator as the impersonated user. But my Convex functions still seem to be functioning as though the value of the sub claim is the impersonator. Any clue why this might be happening? Anything I'm misunderstanding about how any of this works?
9 Replies
StoicWanderer
StoicWanderer•14mo ago
@RJ I think you mistyped your sentence, why would Convex treat the impersonator as the impersonated user, if there is a sub claim in Clerk, whoich you are using, then your app should open the app as the impersonated user, correct me if I'm wrong. @RJ This is from the official Clerk docs: The act.sub claim is the ID of the impersonator. The sub claim is the impersonated user (user_123), while act.sub contains the ID of the impersonator (user_456).
RJ
RJOP•14mo ago
I don't know why this is happening, that's my question! 🙂 Right, that's why I would have expected this to work without any additional configuration/effort on the Convex side of things. Unless perhaps the trouble stems from the ConvexProviderWithClerk component, although glancing at the source code didn't reveal anything obviously wrong to me. Hold up! Let me verify that I'm not just misinterpreting application behavior here.
StoicWanderer
StoicWanderer•14mo ago
Go ahead ill wait
RJ
RJOP•14mo ago
Confirmed, that's not the issue.
StoicWanderer
StoicWanderer•14mo ago
Imo, Convex doesnt differentiate between userId's, only Clerk does, so if you log in with userX impersonating userY then Convex still should return the impersonated userprofile for instance and not the actors id @RJ this what you expect right?
RJ
RJOP•14mo ago
I expect the subject field of the Convex UserIdentity object to contain the value of the sub claim in the JWT, which I expect to be the impersonated user in this context. But this does not appear to be the case.
StoicWanderer
StoicWanderer•14mo ago
Are you using a JWT template? In Clerk Normally, you dont need to specify the {{session.actor}} claim if your are using the Convex default template Check your JWT template and try using const {sessionClaims} = auth(); if zou are on App Router Next.js
RJ
RJOP•14mo ago
I just double-checked the value of the token with:
const { getToken } = useAuth();
getToken({ template: "convex" }).then((token) => {
console.log(token);
});
const { getToken } = useAuth();
getToken({ template: "convex" }).then((token) => {
console.log(token);
});
I am using a JWT template, which looks like this:
{
"aud": "convex",
"email": "{{user.primary_email_address}}",
"picture": "{{user.profile_image_url}}",
"given_name": "{{user.first_name}}",
"updated_at": "{{user.updated_at}}",
"family_name": "{{user.last_name}}",
"email_verified": "{{user.email_verified}}"
}
{
"aud": "convex",
"email": "{{user.primary_email_address}}",
"picture": "{{user.profile_image_url}}",
"given_name": "{{user.first_name}}",
"updated_at": "{{user.updated_at}}",
"family_name": "{{user.last_name}}",
"email_verified": "{{user.email_verified}}"
}
And the sub claim is showing up as the impersonator's user ID, and there is no actor claim! This is in addition to the fact that:
import { useAuth } from "@clerk/clerk-react";

// ...

const { actor } = useAuth(); // `actor` is present
import { useAuth } from "@clerk/clerk-react";

// ...

const { actor } = useAuth(); // `actor` is present
I find this surprising, but likely that's just because I don't actually understand what's going on here well enough 🙂 Ok I figured it out—I had swapped the order of Clerk user IDs in the API call which created the actor token for impersonation 😎 So, nothing interesting here after all. Appreciate you rubber ducking with me @StoicWanderer!
StoicWanderer
StoicWanderer•14mo ago
Not a problem, glad you figured it out and works after all.