Secure AWS Lambda: JWT Token Authentication Using Node JS.

Shubham Chavan
AWS Tip
Published in
6 min readApr 29, 2024

--

Why are we discussing this topic?

Hey there, in the world of cloud computing and serverless setups, keeping things safe and sound is a big deal. That’s where JWT (JSON Web Tokens) steps in. It’s like your trusty lock and key for securely passing info between your apps and services. So, if you’re hanging out with AWS Lambda and API Gateway, JWT is your go-to security buddy.

Why JWT?

  1. Secure Data Transmission: JWT provides a secure and compact means of transmitting information between parties. It’s like wrapping your data in a digital envelope, ensuring that it stays safe and intact as it travels between your applications and services.
  2. Stateless Authentication: With JWT, authentication becomes stateless, meaning the server doesn’t need to keep track of a user’s session state. Instead, each JWT contains all the necessary information for verifying the user’s identity and permissions, making it highly scalable and efficient.
  3. Versatility and Standardization: JWT is a widely adopted industry standard, supported by various programming languages and frameworks. Its versatility allows developers to implement authentication and authorization across different platforms consistently, fostering interoperability and ease of integration.

In this blog, we’ll chat about why JWT is awesome and how you can use it to beef up security in your AWS Lambda setup. Let’s dive in!

Prerequisites:

Assuming that you have the lambda deployed using API Gateway. In this blog I have a demo lambda deployed using AWS api gateway

API Gateway Setup

the demo lambda just returns “Hello from Lambda!” 😁😁

Lambda Execution Using Postman

Now lets work a bit on code to generate token.

const jwt = require('jsonwebtoken');

// Sample payload
const payload = {
userId: '123456789',
username: 'example_user',
role: 'admin' // Sample role
};

// Secret key to sign the token
const secretKey = 'your-secret-key'; // Replace this with your actual secret key

// Options for the JWT token
const options = {
expiresIn: '1h' // Token expiration time
};

// Create the JWT token
const token = jwt.sign(payload, secretKey, options);

console.log(token); // Output the generated token

Here I am using jsonwebtoken library to generate token.

Few pointers on above jwt token generator

  1. Role of secrets key: When creating a JWT token, the jsonwebtoken library uses the secret key to digitally sign the token. This signature is added to the token payload, ensuring that any tampering with the token contents can be detected. Secret key acts as a shared secret between the token issuer and the token verifier
  2. expiresIn option: The option is used to set the expiry time of token.

Once we run the script using node, we get the valid token which looks something like this,

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiIxMjM0NTY3ODkiLCJ1c2VybmFtZSI6ImV4YW1wbGVfdXNlciIsInJvbGUiOiJhZG1pbiIsImlhdCI6MTcxNDM1MjQ3OCwiZXhwIjoxNzE0MzU2MDc4fQ.SbzowzygNIjAmPCts51APKwae4Za5th-X2LHpcO80Pg

Note that the token is divided in 3 parts separated by period, the structure looks like header.payload.signature

  1. Header: The header typically consists of two parts: the token type (typ) and the signing algorithm (alg). It is base64url encoded and contains information about the token and how it should be validated.
  2. Payload: The payload contains the claims, which are statements about the entity (typically the user) and additional data.
  3. Signature: The signature is created by combining the encoded header, encoded payload, and a secret key using the specified algorithm. It’s used to verify that the token was not tampered with and was issued by a trusted party.

So in short, if any of the data is tampered in header or payload, the signature wont match and jwt verification fails.

Now lets works on setting up the token verification logic and add that token verification as a custom authenticator in our API gateway.

Architecture

AWS Architecture Diagram

In our setup, Postman acts as our client tool. The “business logic Lambda” is simply a Lambda function that responds with the message ‘Hello from Lambda!’. The “demo-custom-authy” Lambda, on the other hand, serves as the authentication mechanism responsible for verifying JWT tokens.

Execution

Now, let’s focus on coding to verify the token and forward the request to the business logic Lambda if the token checks out. Here are some key guidelines to keep in mind as we write our code.

  1. IAM policy: AWS works on IAM policy to grant any sort of action. Once token verification is complete, our Lambda should generate an IAM policy granting API Gateway permission to invoke the “Business Logic Lambda”.
  2. Shared secret: For this demo, I’ll store the secret key locally, but in a real-world scenario, it’s best practice to store such sensitive information like secret keys in AWS Secrets Manager for enhanced security.
const jwt = require('jsonwebtoken');

async function handler(event, context) {
console.log(event)
const token = event.authorizationToken;

if (!token) {
return {
statusCode: 403,
body: JSON.stringify({ message: 'Token is required' })
};
}
const jwtToken = token.split(' ')[1]
console.log(jwtToken)
try {
const decoded = jwt.verify(jwtToken, 'your-secret-key'); // Change this to your actual secret key

return {
principalId: 'abcdef',
policyDocument: {
Version: '2012-10-17',
Statement: [
{
Action: 'execute-api:Invoke',
Effect: 'Allow',
Resource: event.methodArn
},
],
}
};
} catch (err) {
console.log(err)
return {
statusCode: 401,
body: JSON.stringify({ message: 'Unauthorized' })
};
}
};
exports.handler = handler;

When deploying this code to AWS Lambda, ensure to update the handler configuration accordingly. In my setup, the code resides in a file named ‘handler.js’, and the function is named ‘handler’. Therefore, the handler configuration would be ‘handler.handler’. Adjust this according to your file and function names.

Now create a lambda with above code and configuration and name it ‘custom-authy

Now go to API gateway console and select the authorizer,

Custom Authenticator

As above, we selected our recently created lambda as a cutom authenticatoy lambda fuction, the important thing to notice here is the token source. The Authorizer is the header name of our http requent. The API gateway will pass the value of this header to the custom-authy lambda as a authorizationToken in the event.

Now, Add the authorizer in the Method execution of GET request.

Adding Custom Auth in Method
Method request after auth addition

After token validation is successfully completed, the Lambda will either permit or deny access to API Gateway based on the token’s validity.

lets consider 3 cases,

  1. Token is not passed in the http request:

In this scenario, API Gateway will respond with an Unauthorized error.

{
"message": "Unauthorized"
}

2. If token validation fails, a deny policy is passed to API Gateway.

{
"message": '<unauthorized || token expired || invalid signature>'
}

// or any error message from api gateway

3. If token validation is successful, the request will be forwarded to the business logic Lambda, and a response will be received.

"Hello from Lambda!"

Conclusion:

In conclusion, this tutorial demonstrated the implementation of JWT token authentication in AWS Lambda API Gateway. By leveraging custom authenticator Lambdas, we ensured secure access to API endpoints, granting permissions based on token validation results. Through this process, we enhanced the security of serverless applications, showcasing the seamless integration of authentication mechanisms within the AWS ecosystem.

Happy Coding😃! Do clap🙏, share, and subscribe!

Follow me on LinkedIn

--

--

Hey there! I'm Shubham Chavan, a tech enthusiast, exploring the ever-evolving world of cloud solutions.