I wonder if we can use Authentication API along with AWS Lamda / Serveless Framework setting. Since I am not proficient to server-side, I want something easier way to use Moralis APIs.
it may be possible, for authentication you have to call the api to get a message to sign, then you have to send that message to front end for the user to sign it and after you get the signed message from the user you can validate the signature by making another api call
Ok, I try it anyway.
But I wonder if Moralis stores user data and authentication information in your database. When a user signs up or logs in with Moralis, their information is stored in Moralisâ cloud database? Otherwise should I connect to Mongo db with Lambda?
I got this question because I noticed that setting own parse server needs Mongo db connected.
It depends on your application needs. You can make it work with your own database or without a database and only check the user authentication once. You may need a database somewhere to store a session token
It seems AWS Lambda received a call with the code below.
But the issue I face now is that I am getting an alert that says Status code 500 {"error":"Cannot read property 'Web3Provider' of undefined"}
from my front-end.
Could you lead me to right direction? Do you have any documentations that I can refer to make this server setting work?
authenticateUser.js
âuse strictâ;
const ethers = require(âethersâ);exports.handler = async (event) => {
console.log(âEvent received:â, event);
const body = JSON.parse(event.body);
const { address, signedMessage } = body;if (!address || !signedMessage) {
return {
statusCode: 400,
body: JSON.stringify({ error: âMissing address or signed message.â }),
};
}try {
const provider = new ethers.providers.Web3Provider(window.ethereum);
const signer = provider.getSigner();
const recoveredAddress = await signer.getAddress(signedMessage);if (address.toLowerCase() === recoveredAddress.toLowerCase()) { // You can create a session or JWT token here and return it in the response return { statusCode: 200, body: JSON.stringify({ success: true }), }; } else { return { statusCode: 401, body: JSON.stringify({ error: "Invalid signature." }), }; }
}
catch (error) {
return {
statusCode: 500,
body: JSON.stringify({ error: error.message }),
};
}
};
Log in AWS Lambda
2023-03-27T12:30:34.664Z e66db2a1-7873-429a-9bba-1a499a2be302 INFO Event received: {
resource: â/authenticateUserâ,
path: â/authenticateUserâ,
httpMethod: âPOSTâ,
headers: {
âAccept-Encodingâ: âgzip, deflateâ,
âCloudFront-Forwarded-Protoâ: âhttpsâ,
âCloudFront-Is-Desktop-Viewerâ: âtrueâ,
âCloudFront-Is-Mobile-Viewerâ: âfalseâ,
âCloudFront-Is-SmartTV-Viewerâ: âfalseâ,
âCloudFront-Is-Tablet-Viewerâ: âfalseâ,
âCloudFront-Viewer-ASNâ: â16509â,
âCloudFront-Viewer-Countryâ: âUSâ,
âcontent-typeâ: âapplication/jsonâ,
Host: â5xkgxbww4k.execute-api.us-east-1.amazonaws.comâ,
traceparent: â00-a786a5c39fb7c194b79e391f936b3376-d2563e38edbb33fb-01â,
âUser-Agentâ: âAmazon CloudFrontâ,
Via: â1.1 3c7c59dd8a259f28206268185f3ecaa2.cloudfront.net (CloudFront)â,
âX-Amz-Cf-Idâ: â0_Lkdhyya9DuoTEz1jl_BLvZdjb0Drcf2CgS4-M-1iY1_jxlsD0_eg==â,
âX-Amzn-Trace-Idâ: âRoot=1-64218c69-5fb81b184735351950117fdaâ,
âx-bubble-depthâ: â1â,
âX-Forwarded-Forâ: â34.220.209.63, 130.176.100.142â,
âX-Forwarded-Portâ: â443â,
âX-Forwarded-Protoâ: âhttpsâ
},
multiValueHeaders: {
âAccept-Encodingâ: [ âgzip, deflateâ ],
âCloudFront-Forwarded-Protoâ: [ âhttpsâ ],
âCloudFront-Is-Desktop-Viewerâ: [ âtrueâ ],
âCloudFront-Is-Mobile-Viewerâ: [ âfalseâ ],
âCloudFront-Is-SmartTV-Viewerâ: [ âfalseâ ],
âCloudFront-Is-Tablet-Viewerâ: [ âfalseâ ],
âCloudFront-Viewer-ASNâ: [ â16509â ],
âCloudFront-Viewer-Countryâ: [ âUSâ ],
âcontent-typeâ: [ âapplication/jsonâ ],
Host: [ â5xkgxbww4k.execute-api.us-east-1.amazonaws.comâ ],
traceparent: [ â00-a786a5c39fb7c194b79e391f936b3376-d2563e38edbb33fb-01â ],
âUser-Agentâ: [ âAmazon CloudFrontâ ],
Via: [
â1.1 3c7c59dd8a259f28206268185f3ecaa2.cloudfront.net (CloudFront)â
],
âX-Amz-Cf-Idâ: [ â0_Lkdhyya9DuoTEz1jl_BLvZdjb0Drcf2CgS4-M-1iY1_jxlsD0_eg==â ],
âX-Amzn-Trace-Idâ: [ âRoot=1-64218c69-5fb81b184735351950117fdaâ ],
âx-bubble-depthâ: [ â1â ],
âX-Forwarded-Forâ: [ â34.220.209.63, 130.176.100.142â ],
âX-Forwarded-Portâ: [ â443â ],
âX-Forwarded-Protoâ: [ âhttpsâ ]
},
queryStringParameters: null,
multiValueQueryStringParameters: null,
pathParameters: null,
stageVariables: null,
requestContext: {
resourceId: â8p2jrhâ,
resourcePath: â/authenticateUserâ,
httpMethod: âPOSTâ,
extendedRequestId: âCcLggFPeoAMFXAw=â,
requestTime: â27/Mar/2023:12:30:33 +0000â,
path: â/dev/authenticateUserâ,
accountId: â461270241695â,
protocol: âHTTP/1.1â,
stage: âdevâ,
domainPrefix: â5xkgxbww4kâ,
requestTimeEpoch: 1679920233340,
requestId: â0afa95ad-9081-4536-a5ff-f4bb51e84ddfâ,
identity: {
cognitoIdentityPoolId: null,
accountId: null,
cognitoIdentityId: null,
caller: null,
sourceIp: â34.220.209.63â,
principalOrgId: null,
accessKey: null,
cognitoAuthenticationType: null,
cognitoAuthenticationProvider: null,
userArn: null,
userAgent: âAmazon CloudFrontâ,
user: null
},
domainName: â5xkgxbww4k.execute-api.us-east-1.amazonaws.comâ,
apiId: â5xkgxbww4kâ
},
body: â{âaddressâ:â0x8cDE5Aec2Ea9189C7c90509e377D4925F19D91E2â,âsignedMessageâ:âtestâ}â,
isBase64Encoded: false
}
it looks like ethers.providers is undefined
Hey, thanks.
This is what I have in package.json, what else am I missing?
{
"name": "aws-node-express-api",
"version": "1.0.0",
"description": "",
"dependencies": {
"body-parser": "^1.20.2",
"ethers": "^6.2.2",
"express": "^4.18.2",
"moralis": "^2.17.0",
"serverless-http": "^3.1.1"
},
"devDependencies": {
"serverless-offline": "^12.0.4"
}
}
maybe the syntax is different for that version of ethers,
https://stackoverflow.com/questions/60785630/how-to-connect-ethers-js-with-metamask
=>
Using ethers.js to interact with Metamask
v6.0.0 (2023-02-02) and above
const provider = new ethers.BrowserProvider(window.ethereum);
// Prompt user for account connections
await provider.send("eth_requestAccounts", []);
const signer = provider.getSigner();
console.log("Account:", await signer.getAddress());
v5.7.2 and below
const provider = new ethers.providers.Web3Provider(window.ethereum, "any");
// Prompt user for account connections
await provider.send("eth_requestAccounts", []);
const signer = provider.getSigner();
console.log("Account:", await signer.getAddress());
I am working on this quite a while, but still drifting aroundâŚ
I get Status code 500 {"error":"Request failed with status code 400"}
from the frone-end. I see this logs in Lambdaâs Cloud watch: Error encountered: AxiosError: Request failed with status code 400
Can you identify my problem? Sorry Iâm still new in server-side configs. Do I have to have Cloud function? Do I need some codes other than this?
"use strict";
const Moralis = require("moralis").default;
const axios = require("axios");
const startMoralis = async () => {
await Moralis.start({
apiKey: process.env.MORALIS_API_KEY,
});
};
exports.handler = async (event) => {
console.log("Event received:", event);
const body = JSON.parse(event.body);
const { address, message, signature } = body;
if (!address || !message || !signature) {
return {
statusCode: 400,
body: JSON.stringify({ error: "Missing address, message or signature." }),
};
}
try {
// Initialize Moralis
console.log("Initializing Moralis...");
await startMoralis();
console.log("Moralis initialized.");
// Call the Moralis Authentication API
console.log("Calling Moralis Authentication API...");
const response = await axios.post("https://xxxx.grandmoralis.com:2053/server/functions/authenticateUser", {
address,
message,
signature,
});
console.log("Moralis Authentication API response:", response.data);
if (response.data.success) {
return {
statusCode: 200,
body: JSON.stringify({ success: true }),
};
} else {
return {
statusCode: 401,
body: JSON.stringify({ error: "Invalid signature." }),
};
}
} catch (error) {
console.error("Error encountered:", error);
return {
statusCode: 500,
body: JSON.stringify({ error: error.message }),
};
}
};
what is the line that returns an error?
I think this part caused the error:
axios.post("https://xxxx.grandmoralis.com:2053/server/functions/authenticateUser", {
address,
message,
signature,
});
you are using a moralis managed server for authentication?
@rio. I have a simpler solution if your using next. if you want a serverless solution you could just write your auth method as a next APi call in your server side code a communicate with you DB from here. (this is if your using next js of course). doing a custom auth is really simple even the moralis source code for the old authenticate call is only a few lines. you just need to take in the usrs FE sig and use a library like ethereum-js to call a recovery method. Considering that the initial problem is simple, to not over complicate things i would suggest that if your using nextJs, just writeyou api call there. something like this would work
export async function handler(
req: NextApiRequest,
res: NextApiResponse<ResponseData>
next: NextFunction
) {
const { signature, nonce, publicAddress, } = req.body;
const userExists = await doesUserExist(publicAddress)
if (!nonce || !signature) {
return next(new ErrorResponse(
"User already exists. please use a unique address", 400, 3
));
}
try {
const msg = getMessage(nonce)
const recoveredAddress = ethers.utils.recoverAddress(
hashMessage(msg), signature
);
if (recoveredAddress.toLowerCase() === publicAddress.toLowerCase()) {
const nonce: number = Math.floor(Math.random() * 10000);
if (!userExists) {
const user: User | null = await User.create({
publicAddress, nonce
})
sendToken(user!, 200, res);
} else {
const user: User | null = await User.findOne({ publicAddress })
sendToken(user!, 200, res);
}
} else {
res.status(401).send({
error: 'Signature verification failed',
});
}
} catch(err: unknown) {
next(err);
}
}
this is of course if a solution like this satisfies your needs an reqirements. if not then just keep searching yoyull find a solution eventyualy. but look into to this if it can be adapted to your specifc needs and setup
Of course depending on what DB your working with you will need to adapt my sol above for appending/checking users etc
I think so. I am trying to migrate to moralis v2 from moralis v1(hosted).
Therefore, I use the same App key. Using the same App key might cause issues?
ok, you have to do it in your self hosted server, you can also try to understand the above answer
Hi @error_undefined, Thank you so much for the reply!
I really appreciate your detailed code sample. Unfortunately I donât use Next.js, but my tech stack is something like this:
Front: Bubble(no-code, but extensive Javascript capability)
Back-end: AWS Lambda w/ Serverless Framework
API Connector in Bubble and API Gateway in AWS communicates. With that, I could successfully implement this: https://docs.moralis.io/web3-data-api/evm/integrations/aws-lambda-nodejs
What I keep failing is a call to ethers.js
functions.
I have asked chatGTP how I can convert your code sample so that I can apply that to my environment did not work out yet.
Do I need to have self hosted server? I want to do the same with Serverless
configuration.
Are you saying that Serverless
is impossible? Why you have this introduced at the beginning of the doc if it is not doable when it comes to Authentication API?
@cryptokid Could you make this instruction applicable to non-game developers? Again I want to use AWS Lambda as my server.
what are the functionalities that use your moralis server now?
do you really need authentication with a wallet that requires to sign a message and validate it in your application?
Yes, I do need the authentication. Currently my app is
running with Moralis version 1 with the Metamask login implemented.