My Netlify site is named mellow-lolly-ecaae8.netlify.app
. My goal is to use Netlify Identity, and use a serverless function to save the user’s name, email, and user ID to a cloud database hosted on Planetscale.
First I installed netlify-identity-widget
and added the button element to my site. I sent an invitation to myself to be the first user. (My site will be invite-only, so I used the Netlify website to configure the identity settings to not provide a “sign-up” tab on the identity modal.) I logged in and out, deleted and recreated my user, and this much worked fine so far.
The problem began when I created serverless functions, following the instructions in the Netlify Documentation:
First I tried putting this code in three different files in the /functions
folder, one at a time: identity-validate.js
, identity-signup.js
, and identity-login.js
. (You might say, wait a minute, you tried signup
but you’re not allowing signups! But when I tried the others & they didn’t work, I thought I might learn through experimenting with signup
, in case I misunderstood the descriptions in the documentation of where these three triggers actually fit in the auth flow.)
import { withPlanetscale } from "@netlify/planetscale";
export const handler: Handler = withPlanetscale(async (event, context) => {
console.log('event ', event);
console.log('context ', context);
const { identity, user } = context.clientContext;
console.dir('identity ', identity);
console.dir('user ', user);
const { email, id } = user;
const name = user.metadata['name'];
const {
planetscale: { connection },
} = context;
await connection.execute(
`INSERT INTO Users (id, email, name) VALUES (${id}, ${email}, ${name})`
);
return {
statusCode: 200,
body: "User created in Planetscale",
};
});
The dev tools Network pane returned {"code":422,"msg":"Failed to handle signup webhook"}
, and that message appears in the identity modal.
Here’s the log output from the Netlify Functions page:
context {
callbackWaitsForEmptyEventLoop: true,
succeed: [Function (anonymous)],
fail: [Function (anonymous)],
done: [Function (anonymous)],
functionVersion: '$LATEST',
functionName: 'blah blah blah etcetera',
memoryLimitInMB: '1024',
logGroupName: '/aws/lambda/ blah blah blah etcetera',
logStreamName: '2023/03/30/[$LATEST]blah blah blah etcetera',
clientContext: {
custom: {
netlify: 'blah blah blah etcetera'
},
identity: {
url: 'https://mellow-lolly-ecaae8.netlify.app/.netlify/identity',
token: 'blah blah blah etcetera'
}
},
identity: undefined,
invokedFunctionArn: 'arn:aws:lambda:us-east-1:blah blah blah etcetera:function:blah blah blah etcetera',
awsRequestId: 'blah blah blah etcetera',
getRemainingTimeInMillis: [Function: getRemainingTimeInMillis],
planetscale: { connection: Connection { session: null, config: [Object] } }
}
Mar 30, 03:02:46 PM: 'identity 'Mar 30, 03:02:46 PM: 'user 'Mar 30, 03:02:46 PM: 4223e65b ERROR Invoke Error {
"errorType":"TypeError",
"errorMessage":"Cannot destructure property 'email' of 'user' as it is undefined.",
"stack":[
"TypeError: Cannot destructure property 'email' of 'user' as it is undefined.",
" at /var/task/functions/identity-login.js:5909:11",
" at /var/task/functions/identity-login.js:5898:12",
" at Generator.next (<anonymous>)",
" at /var/task/functions/identity-login.js:5886:67",
" at new Promise (<anonymous>)",
" at __awaiter (/var/task/functions/identity-login.js:5868:10)",
" at Runtime.handler (/var/task/functions/identity-login.js:5897:30)",
" at Runtime.handleOnceNonStreaming (file:///var/runtime/index.mjs:1085:29)"
]
}
It seems to always give the same output. context.clientContext
doesn’t actually have user
, so user
was undefined, and so, “Cannot destructure property ‘email’ of ‘user’ as it is undefined.”
I hoped I would find a user object somewhere in context
or identity
, but as you can see, it’s absent. What am I doing wrong?