Stack logo
Sync up on the latest from Convex.
Ian Macartney's avatar
Ian Macartney
3 months ago

Testing authenticated functions from the dashboard

Acting as a user from the Convex dashboard

This post will walk you through testing your functions on the dashboard when they require authentication.

Base case

If your function is only checking auth like this:

const identity = await ctx.auth.getUserIdentity();
if (identity === null) throw new Error("Unauthenticated");

Then you can pass this check by checking the "Act as a user" button, which will add fake subject & issuer fields.

Acting as a user in the dashboardActing as a user in the dashboard

This will result in identity looking like this instead of null:

# console.log(identity)
{
  issuer: "fake_issuer",
  subject: "fake_id",
  tokenIdentifier: "fake_issuer|fake_id",
}

Acting as a user

1. Get your JWT

If you are sending requests as yourself, you can get your own JWT from your browser. This is often stored in your browser's cookies or local storage, which you can access in the developer tools under the "Application" tab.

For Clerk, you'll want the __session cookie:

Cookies section, with a cookie named "__session..."Cookies section, with a cookie named "__session..."

For Convex Auth you'll want the __convexAuthJWT_... cookie or value in local storage:

Local storage section, with a key named "_convexAuthJWT..."Local storage section, with a key named "_convexAuthJWT..."

If you want to test a function as someone else, first follow these instructions with your own JWT, then modify the fields to match the desired user.

2. Decode your JWT fields

Even though JWTs are secured by a signature, all of the fields can be decoded by anyone. The "secure" JWT merely provides a signed signature of the fields, so you can verify that the fields haven't been modified since it was signed.

You can then use jwt.io to decode the value. If it's an OpenID ID Token the "payload" should look something like this when you paste the JWT into the "Encoded" text area on that site:

{
  "sub": "some-id-string",
  "iat": 1723171234,
  "iss": "https://some-auth-provider-issuer-url.com",
  "aud": "convex",
  "exp": 1723175678
}

It can also have other fields, such as these standard OpenID claims ("claims" refers to the fields in the JWT).

3. Use the fields to "Act as a user"

In the Convex dashboard function runner you can check the "Act as a user" checkbox and specify what the object returned from ctx.auth.getUserIdentity() will be when calling your function from the dashboard.

The identity fields can mostly be copied from the JWT, but the ID Token will change or be omitted. Taking the example from above, you would enter something like this in the dashboard's field for "Act as a user":

{
  "subject": "some-id-string",
  "issuer": "https://some-auth-provider-issuer-url.com"
}

Along with other fields you might want like those listed here. You can get the issuer URL from your auth.config.ts value for the provider's domain. This is likely an environment variable.

You don't have to pass anything your function doesn't rely on. For many applications the "subject" and "issuer" will suffice unless you're testing user creation.

Testing with Convex Auth

Convex Auth allows you to use your Convex backend as the authentication provider for your project, issuing and validating its own JWTs. Under the hood, it isn't storing much in that JWT other than the sessionId and userId. If you don't want to go through the JWT discovering and decoding dance, you can just pass in the subject and user IDs directly:

{
  subject: "userId|sessionId", 
	issuer: "https://your-deployment-123.convex.site"
}

Where the sessionId comes from the authSessions table, and the userId is whatever your desired user's ID is, with a | between them.

Note: if you don't need one or the other in your function (e.g. if you aren't using auth.getUserId), the unused ID doesn't need to be a valid ID string. If you only use userId for instance, you could pass:

{ subject: "<userId>|-", issuer: "" }

Mimicking tokenIdentifier

The tokenIdentifier field of auth.getUserIdentity() is formatted as <issuer>|<subject>, so if we have a user in our database with a tokenIdentifier like "https://some-issuer-123.clerk.accounts.dev|user_abc123", we can "Act as a user" like this:

{
  subject: "user_abc123", 
  issuer: "https://some-issuer-123.clerk.accounts.dev"
}

Summary

In this post we looked at how to test authenticated functions from the dashboard using the "Act as a user" feature, passing in values decoded from our JWT, or constructed to match some expected fields. As always, let us know in Discord what you think.

Build in minutes, scale forever.

Convex is the sync platform with everything you need to build your full-stack project. Cloud functions, a database, file storage, scheduling, search, and realtime updates fit together seamlessly.

Get started