Authing HTTP Action with OAuth2?
Hey again Convex friends, poking along to build a "GPT Action Set" (REST API that ChatGPT "GPTs" can use). Got HTTP Actions working, but a little stumped on the auth side, looks like my API needs to offer an oauth2 login. Any idea how to implement that?
Using Clerk for auth at the moment, but happy to switch to auth0 if that makes it easier (the guides have been easy peasy so far, so haven't invested much time!)
21 Replies
You can provide the user identity JWT (access token) in the header as
Authorization: Bearer <JWT>
https://docs.convex.dev/functions/http-actions#authentication
The same token as is returned in the ConvexProviderWithClerk: https://github.com/get-convex/convex-js/blob/main/src/react-clerk/ConvexProviderWithClerk.tsx#L63-L66HTTP Actions | Convex Developer Hub
HTTP actions allow you to build an HTTP API right in Convex!
GitHub
convex-js/src/react-clerk/ConvexProviderWithClerk.tsx at main · get...
TypeScript/JavaScript client library for Convex. Contribute to get-convex/convex-js development by creating an account on GitHub.
Hey @Mike Lyons, do you have some docs on the "needs to offer an oauth2 login" requirement? As Ian points out, if you control the caller (which I understand is a GPT in this case), the caller can use the Authorization header with a JWT token and then in your httpAction
ctx.auth
will work like in other functions.Here are the two auth options for in the GPT config screen.
API Key seems to apply to anyone using the GPT which means if you use that, you can't share the GPT with someone else or everyone using the GPT will have access to the same account (in this case, my authed set of Convex HTTP Actions).
OAuth seems like the right way to do it -- that way each person that uses the GPT can provide access to their own account
So I could use "API Key" to set the JWT token, but then I wouldn't be able to share my GPT with anyone else
Can you configure clerk as your oauth provider?
Clerk recently added support for using it as an OAuth 2 provider
https://clerk.com/docs/advanced-usage/clerk-idp
Use Clerk as an OAuth 2 Provider | Clerk
Learn how to use Clerk to facilitate Single Sign-On (SSO) with other clients that support the OAuth 2.0 protocol.
Yeah, I've been following the instructions there today, but it's a little opaque when things aren't working. The GPT is complaining that the access_token is missing, but I suspect it's b/c my "let's see if I can make a CNAME that redirects to my convex subdomain is enough to make the Action Set config happy that everything is on the same domain" likely fails an SSL check.
I think my problem is the overlap of this post and the "Custom domain?" one. I'm not sure if most services insist that auth and the backend are on the same root domain, but the GPT certainly does. So while I suspect the doc linked above would sort it all out, without convex custom domains I'm not sure how to know it (unless I implement a proxy in vercel or something)
could you point GPT at your Next.js as a proxy, and pass the auth header through? to diagnose if it's a domain issue?
One thing I was thinking was just grab the JWT and using "API Key" auth to force it through and make sure that works. Any idea how to get the JWT token for a user?
you can use the
useAuth
from clerk and use the getToken
like here: https://discord.com/channels/1019350475847499849/1174018663226036324/1174055654919507979you can use the
useAuth
from clerk and use the getToken
like here: https://github.com/get-convex/convex-js/blob/main/src/react-clerk/ConvexProviderWithClerk.tsx#L63-L66GitHub
convex-js/src/react-clerk/ConvexProviderWithClerk.tsx at main · get...
TypeScript/JavaScript client library for Convex. Contribute to get-convex/convex-js development by creating an account on GitHub.
it's also likely in localstorage/ cookie too
Ok so I do get a pretty massive token out with that. But when I pass the
Authorization: Bearer XXXXX
, getUserIdentity()
returns the empty object {}
(same as if I didn't return the Authorization header)check a JWT decoder to see if it looks like the identity token (should have an "aud" field e.g.). Also check that your auth.config.js is good. I can't remember where to find logs about why auth isn't working
ok will poke around. thanks ian!
alrighty, I was doing a couple things wrong (turns out I shouldn't use the same object into getToken and not awaiting right, but now I just get
null
instead of {}
. Don't see any errors in the convex logs fwiwThe only time I've ever heard the "auth and backend must be on the same root domain" thing before is in the context of browser SDKs for services like Auth0, and in that context it was a way to mitigate cookie-related issues. I'm not sure what reason chatGPT could have for requiring this.
You can inspect the
sync
websocket messages in the Network tab to see if there's any error messages there from auth
Or call an http endpoint with the token and see what it says in logs / returnedHey hey, figured it out!
So the problem is that Convex HTTP Actions look for "Convex" templated JWTs in
Authorization: Bearer XXXXX
does not accept standard JWTs. This is consistent with the code sample you sent me (and what I originally had), but when you mentioned check if it was a valid JWT with a JWT decoder, that let me to remove the {template: "convex"}
bit. So the original problem was just that I wasn't awaiting correctly in the HTTP Action handler (which did show up in the logs once I knew where to look).
So for anyone else reading this:
1. Make sure you're checking the "Logs" tab in the Convex Dashboard if something seems off first.
2. Make sure you're await
ing on getUserIdentity()
3. Make sure you're using getToken({template: "convex"})
(and the result will not work with standard JWT decoders)
Also as a feature request, would be lovely if the logs note when an Authorization: Bearer XXXX
auth fails -- I was hitting a point where I couldn't tell if Convex was even checking auth. Bonus points if the log error includes a note about generating the JWT with the convex template.
Thanks everyone for your help!great feedback. thanks @Mike Lyons ! and very glad to hear you got it working
Hey, so I've been plugging along with this and I think I'm most of the way there on OAuth2 -- the one thing I can't figure out is why the access_token I get at the end of the oauth2 flow (from clerk) does not seem to be accepted by convex.
I think maybe it's similar to my previous goof of using Clerk's getToken() without
{template: 'convex'}
-- there's something about the format the access_token is returned in that is perhaps valid, but not what convex expects. Do you have any ideas about how convex processes the Authorization: Bearer XXXXXX
with Clerk? For example, is Convex expecting a JWT there (not just any arbitrary token)? The oauth2 access_token is definitely not in JWT format (it's just a long [A-Z0-9])
Thanks!Yeah, Convex currently requires a JWT token with
aud
field including what you have configured in applicationID
in auth.config.js