Skip to content

Authorization and integrity

Flows can check authorization by inspecting the context property passed to the flow function. When a flow is served over HTTP, a context provider populates this context from the request.

import 'package:genkit/genkit.dart';
import 'package:schemantic/schemantic.dart';
part 'self_summary.g.dart'; // Generated by build_runner
// Define the input schema
@Schema()
abstract class $SelfSummaryInput {
String get uid;
}
// Define the output schema
@Schema()
abstract class $SelfSummaryOutput {
String get profileSummary;
}
final selfSummaryFlow = ai.defineFlow(
name: 'selfSummaryFlow',
inputSchema: SelfSummaryInput.$schema,
outputSchema: SelfSummaryOutput.$schema,
fn: (input, context) async {
final auth = context.context?['auth'];
if (auth == null) {
throw GenkitException('Unauthenticated', status: StatusCode.unauthenticated);
}
// Access typed properties on the generated concrete class
if (input.uid != auth['uid']) {
throw GenkitException(
'You may only summarize your own profile data.',
status: StatusCode.permissionDenied,
);
}
// Flow logic here...
return SelfSummaryOutput(profileSummary: 'User profile summary would go here');
},
);

You can verify this logic by manually passing context during execution:

// Error: Unauthenticated
await selfSummaryFlow(SelfSummaryInput(uid: 'abc-def'));
// Error: Permission denied
await selfSummaryFlow(
SelfSummaryInput(uid: 'abc-def'),
context: {'auth': {'uid': 'hij-klm'}},
);
// Success
await selfSummaryFlow(
SelfSummaryInput(uid: 'abc-def'),
context: {'auth': {'uid': 'abc-def'}},
);

When serving flows over HTTP with GenkitRouter (from package:genkit/io.dart), pass a contextProvider to verify incoming requests and populate the context. The provider receives a framework-neutral RequestData (lowercased headers, method, and parsed input), so the same function works with the standalone server, Shelf, or any other adapter.

import 'dart:async';
import 'package:genkit/genkit.dart';
import 'package:genkit/io.dart';
FutureOr<Map<String, dynamic>> apiKeyContextProvider(RequestData request) {
final authHeader = request.headers['authorization'];
if (authHeader == null || !authHeader.startsWith('Bearer ')) {
// A thrown GenkitException is answered with its status (here 401).
// Any other exception results in a 403.
throw GenkitException('Missing API Key', status: StatusCode.unauthenticated);
}
final token = authHeader.substring(7);
if (token != 'REQUIRED_API_KEY') {
throw GenkitException('Invalid API Key', status: StatusCode.permissionDenied);
}
return {
'auth': {'uid': 'admin', 'key': token},
};
}
void main() async {
final ai = Genkit();
// ... define selfSummaryFlow ...
final genkit = GenkitRouter()
..addAction(selfSummaryFlow, contextProvider: apiKeyContextProvider);
await genkit.serve(port: 3400);
}

In a Shelf app, mount the same router with genkit.asShelfHandler() from genkit_shelf, or protect a single route with shelfHandler(selfSummaryFlow, contextProvider: apiKeyContextProvider).