Amplify has re-imagined the way frontend developers build fullstack applications. Develop and deploy without the hassle.

Page updated Jun 19, 2024

Custom data access using Lambda functions

You can define your own custom authorization rule with a Lambda function.

import {
type ClientSchema,
} from '@aws-amplify/backend';
const schema = a.schema({
Todo: a
content: a.string(),
// STEP 1
// Indicate which models / fields should use a custom authorization rule
.authorization(allow => [allow.custom()]),
export type Schema = ClientSchema<typeof schema>;
export const data = defineData({
authorizationModes: {
defaultAuthorizationMode: 'lambda',
// STEP 2
// Pass in the function to be used for a custom authorization rule
lambdaAuthorizationMode: {
function: defineFunction({
entry: './custom-authorizer.ts',
// (Optional) STEP 3
// Configure the token's time to live
timeToLiveInSeconds: 300,

In your application, you can perform CRUD operations against the model with the function auth mode.

try {
final todo = Todo(content: 'My new todo');
final request = ModelMutations.create(
authorizationMode: APIAuthorizationType.function,
final createdTodo = await Amplify.API.mutations(request: request).response;
if (createdTodo == null) {
safePrint('errors: ${response.errors}');
safePrint('Mutation result: ${}');
} on APIException catch (e) {
safePrint('Failed to create todo', e);

The Lambda function of choice will receive an authorization token from the client and execute the desired authorization logic. The AppSync GraphQL API will receive a payload from Lambda after invocation to allow or deny the API call accordingly.

To configure a Lambda function as the authorization mode, create a new file amplify/data/custom-authorizer.ts. You can use this Lambda function code template as a starting point for your authorization handler code:

// amplify/data/custom-authorizer.ts
// This is sample code. Update this to suite your needs
import type { AppSyncAuthorizerHandler } from 'aws-lambda'; // types imported from @types/aws-lambda
type ResolverContext = {
userid: string;
info: string;
more_info: string;
export const handler: AppSyncAuthorizerHandler<ResolverContext> = async (
) => {
console.log(`EVENT: ${JSON.stringify(event)}`);
const {
requestContext: { apiId, accountId }
} = event;
const response = {
isAuthorized: authorizationToken === 'custom-authorized',
resolverContext: {
// eslint-disable-next-line spellcheck/spell-checker
userid: 'user-id',
info: 'contextual information A',
more_info: 'contextual information B'
deniedFields: [
ttlOverride: 300
console.log(`RESPONSE: ${JSON.stringify(response, null, 2)}`);
return response;

You can use the template above as a starting point for your custom authorization rule. The authorization Lambda function receives the following event:

"authorizationToken": "ExampleAuthToken123123123", # Authorization token specified by client
"requestContext": {
"apiId": "aaaaaa123123123example123", # AppSync API ID
"accountId": "111122223333", # AWS Account ID
"requestId": "f4081827-1111-4444-5555-5cf4695f339f",
"queryString": "mutation CreateEvent {...}\n\nquery MyQuery {...}\n", # GraphQL query
"operationName": "MyQuery", # GraphQL operation name
"variables": {} # any additional variables supplied to the operation

Your Lambda authorization function needs to return the following JSON:

// required
"isAuthorized": true, // if "false" then an UnauthorizedException is raised, access is denied
"resolverContext": { "banana": "very yellow" }, // JSON object visible as $ctx.identity.resolverContext in VTL resolver templates
// optional
"deniedFields": ["TypeName.FieldName"], // Forces the fields to "null" when returned to the client
"ttlOverride": 10 // The number of seconds that the response should be cached for. Overrides default specified in "amplify update api"

Review the Amplify documentation to set the custom authorization token for the Data client.