genkit icon indicating copy to clipboard operation
genkit copied to clipboard

GenKit Auth Issue using onCallGenkit and firebase

Open codercatdev opened this issue 1 month ago • 4 comments

Related issues

[REQUIRED] Version info

node: 20.x

firebase-functions: 6.1.1

firebase-tools: 13.x

firebase-admin: 12.x

genkit: 0.9.x

[REQUIRED] Test case

Currently, onCallGenkit does not provide a way to pass Firebase Authentication context (user ID, email, custom claims, etc.) from the callable function to Genkit flows.

Current workaround - must use onCall instead of onCallGenkit:

export const generatePoem = onCall(
    createGenKitOptions('generatePoem'),
    async (request) => {
        const flow = generatePoemFlow();
        const authClaims = extractAuthClaims(request.auth);
        
        const result = await flow.run(
            {
                subject: request.data.subject,
                auth: authClaims,  // Manually passing auth
            },
            { context: { auth: authClaims } }  // Also in context
        );
        
        return result.result;
    }
);

[REQUIRED] Steps to reproduce

  1. Create a Firebase callable function using onCallGenkit
  2. Attempt to access Firebase Auth context (user ID, custom claims) within the Genkit flow
  3. Observe that auth context is not available in the flow

Minimal reproduction:

// genkit.ts - Using onCallGenkit (DESIRED)
export const generatePoem = onCallGenkit(
    { authPolicy: createAuthPolicy('generatePoem') },
    generatePoemFlow()
);

// generatePoemFlow.ts
export const generatePoemFlow = () => {
    const ai = genkit({
        plugins: [googleAI()],
        model: 'googleai/gemini-2.5-flash',
    });
    
    return ai.defineFlow(
        {
            name: 'generatePoem',
            inputSchema: z.object({ subject: z.string() }),
            outputSchema: z.object({ poem: z.string() }),
        },
        async ({ subject }) => {
            // ❌ Cannot access auth.uid, auth.email, or custom claims here
            // Auth context is validated by authPolicy but not passed to flow
            const { text } = await ai.generate({
                prompt: `Compose a poem about ${subject}.`
            });
            return { poem: text };
        }
    );
};

[REQUIRED] Expected behavior

Auth context should be automatically available in Genkit flows when using onCallGenkit, similar to how it's available in regular onCall functions:

Option 1: Automatic injection via flow context

async ({ subject }, context) => {
    console.log('User:', context.auth.uid, context.auth.email);
    console.log('Custom claims:', context.auth.token);
    // Use auth context for user-scoped operations
}

Option 2: Extended CallableOptions

export const generatePoem = onCallGenkit(
    { 
        authPolicy: createAuthPolicy('generatePoem'),
        passAuthContext: true  // Auto-inject auth
    },
    generatePoemFlow()
);

Option 3: Middleware/transform function

export const generatePoem = onCallGenkit(
    { authPolicy: createAuthPolicy('generatePoem') },
    generatePoemFlow(),
    {
        transform: (request) => ({
            ...request.data,
            auth: request.auth
        })
    }
);

[REQUIRED] Actual behavior

Auth context is NOT available in Genkit flows when using onCallGenkit. Developers must:

  1. Abandon onCallGenkit and use onCall with manual flow execution:
export const generatePoem = onCall(
    createGenKitOptions('generatePoem'),
    async (request) => {
        const flow = generatePoemFlow();
        const authClaims = extractAuthClaims(request.auth);
        
        const result = await flow.run(
            {
                subject: request.data.subject,
                auth: authClaims,  // Manually passing auth
            },
            { context: { auth: authClaims } }  // Also in context
        );
        
        return result.result;
    }
);
  1. Or pass UIDs as input data (security risk - clients can spoof this)

  2. Or fetch auth context separately in flows (inefficient, breaks traceability)

This defeats the purpose of onCallGenkit's streamlined integration.

Were you able to successfully deploy your functions?

Yes, functions deploy successfully. However, the limitation forces using onCall instead of onCallGenkit to access auth context in flows.


Additional Context

Why This Matters

  1. Security: Auth context is essential for user-scoped operations and access control within flows
  2. Observability: Audit trails require knowing which user triggered operations
  3. Personalization: AI responses need to be personalized based on user data
  4. Developer Experience: Abandoning onCallGenkit for basic auth needs is poor DX
  5. Best Practices: Encourages proper auth-aware design vs. passing UIDs as input (spoofable)

Common Use Cases Blocked

  • User-scoped AI generation: Personalize based on user preferences by UID
  • Audit logging: Track which user triggered AI operations
  • Custom claims logic: Different model configs for premium vs. free tier users
  • Multi-tenant apps: Route to org-specific data using custom claims
  • Rate limiting: Implement per-user quotas based on custom claims

Proposed Implementation

// Inside firebase-functions implementation
export function onCallGenkit<A extends GenkitAction>(
    opts: CallableOptions<ActionInput<A>>,
    flow: A
): CallableFunction<ActionInput<A>, Promise<ActionOutput<A>>, ActionStream<A>> {
    return onCall(opts, async (request, response) => {
        const context = {
            auth: request.auth ? {
                uid: request.auth.uid,
                token: request.auth.token,
            } : undefined,
        };
        
        return await flow.run(request.data, { context });
    });
}

This would be non-breaking (auth context optional in flows) and consistent with Firebase's security model.

codercatdev avatar Nov 10 '25 21:11 codercatdev

I couldn't figure out how to label this issue, so I've labeled it for a human to triage. Hang tight.

google-oss-bot avatar Nov 10 '25 21:11 google-oss-bot

Hi @codercatdev. Thanks for reporting this issue, it has been received and we'll review it as soon as possible!

CorieW avatar Nov 11 '25 13:11 CorieW

I actually think I found the solution, I didn't realize there was an object passed and a helper function. I think this is more of a documentation issue in genkit repo on how to actually use it.

https://genkit.dev/docs/deployment/authorization/#user-authentication

When you use onCallGenkit, context.auth is returned as an object with a uid for the user ID, and a token that is a DecodedIdToken. You can always retrieve this object at any time using ai.currentContext() as noted earlier. When running this flow during development, you would pass the user object in the same way:

codercatdev avatar Nov 12 '25 16:11 codercatdev

@codercatdev thanks for the update. I've moved this issue to the Genkit repo, since this is potentially a docs issue there.

CorieW avatar Nov 13 '25 12:11 CorieW