shadow_ayaS
Convex Community3y ago
2 replies
shadow_aya

"'internal' authentication" for a HTTP client

Personally, almost all of my Convex functions are meant to be used backend-to-db (might be questionable design but let's forget that for a minute). In finding support-community"Internal" authentication and realizing that, in theory, anyone can call my session & rate limiting functions, I first panicked, and then came with an acceptable solution.

ConvexHttpClientAsServer

type OmitDbToken<T extends FunctionReference<any>> = Omit<T, '_args'> & { _args: Omit<T['_args'], 'dbToken'> };
type HasDbToken<Fn extends FunctionReference<any>, T> = 'dbToken' extends keyof Fn['_args'] ? T : never;

class ConvexHttpClientAsServer extends ConvexHttpClient {
    constructor(url: string) {
        super(url);
    }

    public serverMutation<Mutation extends FunctionReference<"mutation">>(
        ctx: Mutation,
        ...args: HasDbToken<Mutation, OptionalRestArgs<OmitDbToken<Mutation>>>
    ) {
        return super.mutation(
            ctx,
            Object.assign({}, { dbToken: process.env.CONVEX_DB_TOKEN! }, ...args)
        );
    }

    public serverQuery<Query extends FunctionReference<"query">>(
        ctx: Query,
        ...args: HasDbToken<Query, OptionalRestArgs<OmitDbToken<Query>>>
    ) {
        return super.query(
            ctx,
            Object.assign({}, { dbToken: process.env.CONVEX_DB_TOKEN! }, ...args)
        );
    }

    // the rest (like actions) isn't implemented cause I don't use em yet
    // but it's all pretty similar, just gotta copypaste

}

export const convex = new ConvexHttpClientAsServer(process.env.NEXT_PUBLIC_CONVEX_URL!);

for context

DB_TOKEN on Convex matches CONVEX_DB_TOKEN on server

usage

convex.serverQuery(api.siteSessions.findBySid, {sid: sid})

findBySid method

export const findBySid = query({
    args: {
        dbToken: v.string(),
        sid: v.string(),
    },
    async handler(ctx, { dbToken, ...args }) {
        if (process.env.DB_TOKEN !== dbToken) throw new Error(); // reject request
        
        // ...        

    },
});


this is kind of a madness but it works - no need to dotenv anywhere else, and it's still typesafe.
note: to validate the function's arguments - in case 'dbToken' doesn't exist, args will be never

So yeah, if anyone wants to use this, you may :HuTaoThumbsUp:
Was this page helpful?