JWT Token Generation Using AWS Lambda

Introduction

Here at BeamWallet we tend to prefer micro-service architecture approach as opposed to archaic monolithic thinking. Recently we came across a simple/common issue which is generating JWT Token to allow our servers to communicate between each other.

Since all of our systems live in private VPCs  and in the interest of the DRY principle we decided to build a centralised service that would handle all of this. We built the solution using AWS Lambda and also AWS API Gateway.

We have 2 different ways of deploying and for secret storing. 

AWS  Elastic Beanstalk with AWS Secret Manager

Our EBS applications are Java Spring backends which have all the passwords and keys stored in AWS Secret Manager.  On start up of each app all passwords are loaded from AWS Secret Manager and loaded into the System Properties.

Our naming convention for naming secrets stored in the Secret Manager is <system>/<environment>
Eg core/dev  or common/staging (where common has commonly used variables across all systems)

AWS ECS with Ansible

We deploy our other apps to ECS using ansible, where the secrets are stored in our Ansible Vault, and after the passwords are stored in ECS' Task definition as Environment Variables.

Our Solution (In Lambda)

Setting up IAM

Add the following roles

Screen Shot 2018-08-10 at 5.19.15 pm.png

Add the Lambda Function

Screen Shot 2018-08-10 at 5.22.18 pm.png

Configure the Lambda function

Set the handler to org.srini.awslambda.examples.generatejwt.GenerateJWTFunctionHandler::handleRequest

Screen Shot 2018-08-10 at 5.24.47 pm.png

Private Key Retrieval

As mentioned above we store our secrets in 2 different locations so we wanted our function to be smart enough to know where to get the private key from. We have a list which contains which service to get which key from.

The easiest one to get the secrets from was the AWS Secrets using the aws-java-sdk. We have all our private keys with the same name so the naming convention was really easy. 

String endpoint = "secretsmanager.eu-central-1.amazonaws.com";
AwsClientBuilder.EndpointConfiguration config = new AwsClientBuilder.EndpointConfiguration(endpoint, region);
AWSSecretsManagerClientBuilder clientBuilder = AWSSecretsManagerClientBuilder.standard();
clientBuilder.setEndpointConfiguration(config);
AWSSecretsManager client = clientBuilder.build();
GetSecretValueRequest request = new GetSecretValueRequest().withSecretId(service + "/" + environment);
String res = client.getSecretValue(request).getSecretString();
HashMap map = new Gson().fromJson(res, new HashMap<String, String>().getClass());
return map.get(AWS_SECRET_KEYWORD).toString();

The hardest step was  getting the private key from the ECS configuration. To access we needed retrieve the task definition from within the container definition which is inside the service. Again we were following the same naming conventions across all of our services which made this task much easier.

String privateKey = "";
AmazonECSClientBuilder clientBuilder = AmazonECSClientBuilder.standard();
clientBuilder.setRegion(region);
AmazonECS client = clientBuilder.build();
String commonName = environment + "-" + service;
List<Service> services = client.describeServices(new DescribeServicesRequest().withCluster(commonName).withServices(commonName)).getServices();
if (service.isEmpty()) {
    throw new IllegalArgumentException("No cluster/service is found with " + commonName);
}
// will always return 1 or 0
String taskDefinition = services.get(0).getTaskDefinition();
List<ContainerDefinition> containerDefinitions = client.describeTaskDefinition(new DescribeTaskDefinitionRequest().withTaskDefinition(taskDefinition)).getTaskDefinition().getContainerDefinitions();
if (containerDefinitions.isEmpty()) {
    throw new IllegalArgumentException("No container definitions is found with " + commonName);
}
// will always return 1 or 0
for (KeyValuePair keyPair : containerDefinitions.get(0).getEnvironment()) {
    if (keyPair.getName().equals(AWS_ECS_KEYWORD)) {
        privateKey = keyPair.getValue();
    }
}
return privateKey;

Key Generation

We are using the Java Security Library to generate the token, io.jsonwebtoken.jjwt to generate the JWT token, and using Lambda variables to set how long we want the time out to be. 

public class TokenGenerator {
    private final int DEFAULT_TIME_IN_MINUTES = 10;
    private final String timeInMinutes = System.getenv("TIME_IN_MINUTES");
    private final String TOKEN_TYPE = "typ";
    private final String RND = "rnd";

    public String generateToken(String secretKey, String subject) throws NoSuchAlgorithmException, InvalidKeySpecException {
        int TIME_IN_MINUTES = DEFAULT_TIME_IN_MINUTES;
        if (!com.amazonaws.util.StringUtils.isNullOrEmpty(timeInMinutes)) {
            TIME_IN_MINUTES = Integer.parseInt(timeInMinutes);
        }
        String jwtToken = "";
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PrivateKey privateKey = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(Base64.decodeBase64(secretKey)));
        jwtToken = Jwts.builder()
                .claim(TOKEN_TYPE, "service")
                .claim(RND, Date.from(LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant()))
                .setSubject(subject)
                .setIssuedAt(new Date())
                .setExpiration(Date.from(LocalDateTime.now().plusMinutes(TIME_IN_MINUTES).atZone(ZoneId.systemDefault()).toInstant()))
                .signWith(SignatureAlgorithm.RS512, privateKey)
                .compact();
        return jwtToken;
    }
}

API Gateway

The api gateway was used just as a very simple means to ensure we were able to build/develop and also would be able to use on all environments. To set up the API Gateway

Step 1: Create API

Screen Shot 2018-08-10 at 4.33.02 pm.png

Step 2: Link to Lambda

 

Screen Shot 2018-08-10 at 4.33.45 pm.png

Step 3: Deploy the API

Screen Shot 2018-08-10 at 5.13.00 pm.png

They came, they saw, they Beamed

This year, Beam became the first app to let UAE pay for fuel from their car. 12 milion litres later, here’s a little throwback to our Beam pioneers.

Based in Dubai, Maureen, Brenda, Hadi and Ahmed were the first in UAE to trial Beam at ENOC in July this year. Watch what they had to say or read the interview below.

 

Maureen

 

It was all too easy. It was actually a little strange. Because I have the habit of having to get out of the car and pay. I wouldn’t mind pumping my own gas but it was extremely easy. I can never imagine using my credit card again to pay for gas.

 

“It was all too easy. It was actually a little strange.”

 

Brenda

It’s actually been a great experience. It’s very easy and convenient to use, and hassle-free because I don’t have to get out of the car. It’s just easy, just press the button and it automatically detects how much you owe, and you pay via the app and you’re on your way. It’s very quick, easy and hassle-free.

 

“Just press the button… and you’re on your way”

 

Ahmed

 

The experience was really good. It was really fast. I didn’t have to get out of my car. I didn’t have to hand over my credit card. I just had to take my phone out, use Beam, and it was fast.

 

“I didn’t have to get out of my car. I didn’t have to hand over my credit card.”

 

Hadi

 

It’s an amazing experience because I always wanted to pay with credit card at the gas station. I couldn’t earlier because there was an extra charge. And when it was available, you always had to step out of the car to pay with the PIN because the machines were not mobile.

 

Now I can sit in the car, pay with Beam, enjoy the rewards and not have to step out of the car especially with the hot weather.

 

“It’s an amazing experience… Now I can sit in the car, pay with Beam, and enjoy the rewards.”

 

Related posts

Like what you see? Beam at ENOC today to win fuel for a year: www.winfuel.ae

Mitch Williams won fuel for a year in October. See what he had to say here.

 

 

The story behind Beam at ENOC

They say Rome wasn’t built in a day. This year, Beam became the first app to let UAE pay for fuel from their car. The path was not without challenges. Our product team gives us a behind-the-scenes look at the journey to creating a world-first.

 

Where did the idea come from?

Testing in the lab   

Testing in the lab

 

ENOC approached us to do a pilot in late 2015. Their goal was to let UAE residents be the first in the world to pay with their phones at the pump.

 

How did Beam execute this?

It was a long journey due to the nature of the petrol station infrastructure. We had to do a lot of cross border testing of the solution step by step between Sydney (where our product team is based) and Dubai.

 

What challenges did Beam face?

The primary challenge was designing a solution where the series of events (sessions) between Beam and ENOC's systems are managed seamlessly without the user feeling all the steps involved. From the time the customer arrives at the petrol station to payment, the number of scenarios that could go wrong was quite high.

 

ENOC’s goal was to let UAE residents be the first in the world to pay with their phone at the pump.”

 

What issues did the team solve in the process?

We solved:

  • The network connectivity issues between Beam's (cloud based) and ENOC's (closed network/VPN) systems .

  • The mapping out of events between Beam and ENOC's systems accurately and reliably. One of our developers said this felt like "stacking peas with a boxing glove".

  • Real life scenarios that could not be encountered in a lab environment. We continuously monitored the logs for such scenarios and proactively addressed them on a daily basis.

 

“Instead of providing the same payment method at all places, we optimise the experience based on the environment you are in.”

 

What are the key achievements with this particular solution?

We created a world-first experience in the UAE and the growth rate was beyond our expectations. We have 50K Beamers transacting at ENOC, 12 million litres of fuel pumped, and 210k tanks filled so far and this is growing as we speak.

 

“One of our developers said this felt like stacking peas with a boxing glove.”

 

Why is this solution unique?

This solution is unique because:

  • We use BLE beacons at the pump to make the pump selection easy through the app

  • Instead of providing the same payment method at all places, we optimise the experience based on the environment you are in.

  • Beam is a wallet you can use at over 2,600 stores in the UAE not just at ENOC stations, which makes it convenient for our customers.

 

      “The growth rate was beyond our expectations.”

The first Beamers to test the fuel experience

The first Beamers to test the fuel experience

What does this mean for the future of Beam?

  • We’ve always believed that the payment experience should be optimised based on the environment instead of giving customers one-size-fits-all solutions.

  • Our experience at ENOC proved that you can alter the way we pay to make it easier for the customers, and when you do this, people will switch to pay with Beam.

 

“Beam is a wallet you can use at over 2,600 stores in the UAE, not just at ENOC stations.”

 

What does this mean for the future of Beam? (cont…)

  • We will continue to improve our current experiences at ENOC, restaurants (tipping, splitting bills etc.) and tap to pay at the checkout.

  • We are continually on the lookout for new opportunities where we can make the payment method easier and more convenient for our customers.

  • Our long term vision is that payments should be an entirely seamless and rewarding experience for buyers and sellers.

 

“The payment experience should be optimised based on the environment instead of giving customers one-size-fits-all solutions.”

 

Related posts

Like what you see? Beam at ENOC today to win fuel for a year: www.winfuel.ae

Maureen, Brenda, Hadi and Ahmed were the pioneers of the Beam at ENOC experience.

See what they had to say here.