Skip to content

Authorization and integrity

When building any public-facing application, it’s extremely important to protect the data stored in your system. When it comes to LLMs, extra diligence is necessary to ensure that the model is only accessing data it should, tool calls are properly scoped to the user invoking the LLM, and the flow is being invoked only by verified client applications.

Genkit provides mechanisms for managing authorization policies and contexts. Flows running on Firebase can use an auth policy callback (or helper). Alternatively, Firebase also provides auth context into the flow where it can do its own checks. For non-Functions flows, auth can be managed and set through middleware.

Flows can check authorization in two ways: either the request binding (e.g. onCallGenkit for Cloud Functions for Firebase or express) can enforce authorization, or those frameworks can pass auth policies to the flow itself, where the flow has access to the information for auth managed within the flow.

import { genkit, z, UserFacingError } from 'genkit';
const ai = genkit({ ... });
export const selfSummaryFlow = ai.defineFlow( {
name: 'selfSummaryFlow',
inputSchema: z.object({ uid: z.string() }),
outputSchema: z.object({ profileSummary: z.string() }),
}, async (input, { context }) => {
if (!context.auth) {
throw new UserFacingError('UNAUTHENTICATED', 'Unauthenticated');
}
if (input.uid !== context.auth.uid) {
throw new UserFacingError('PERMISSION_DENIED', 'You may only summarize your own profile data.');
}
// Flow logic here...
return { profileSummary: "User profile summary would go here" };
});

It is up to the request binding to populate context.auth in this case. For example, onCallGenkit automatically populates context.auth (Firebase Authentication), context.app (Firebase App Check), and context.instanceIdToken (Firebase Cloud Messaging). When calling a flow manually, you can add your own auth context manually.

// Error: Authorization required.
await selfSummaryFlow({ uid: 'abc-def' });
// Error: You may only summarize your own profile data.
await selfSummaryFlow.run(
{ uid: 'abc-def' },
{
context: { auth: { uid: 'hij-klm' } },
},
);
// Success
await selfSummaryFlow(
{ uid: 'abc-def' },
{
context: { auth: { uid: 'abc-def' } },
},
);

When running with the Genkit Development UI, you can pass the Auth object by entering JSON in the “Auth JSON” tab: {"uid": "abc-def"}.

You can also retrieve the auth context for the flow at any time within the flow by calling ai.currentContext(), including in functions invoked by the flow:

import { genkit, z } from 'genkit';
const ai = genkit({ ... });
async function readDatabase(uid: string) {
const auth = ai.currentContext()?.auth;
// Note: the shape of context.auth depends on the provider. onCallGenkit puts
// claims information in auth.token
if (auth?.token?.admin) {
// Do something special if the user is an admin
} else {
// Otherwise, use the `uid` variable to retrieve the relevant document
}
}
export const selfSummaryFlow = ai.defineFlow(
{
name: 'selfSummaryFlow',
inputSchema: z.object({ uid: z.string() }),