Serverless Okta JWT as AWS API Gateway Authorizer

About this solution

In todays technological world it has become very popular ( and quite easy )  to create serverless architectures with Lambdas and expose them via API gateway.

The expose part is something which we could protect better. Solution provided here is basic blueprint which leverages openID  ( in this case set up in Okta ).


This software/code is provided to you “as-is” and without warranty of any kind, express, implied or otherwise, including without limitation, any warranty of fitness for a particular purpose


Tech involved

Although I would like to keep the solution requirements to minimal this requires some software/services to work nicely together. Below I highlighted what we will need:

  • Serverless – to create and configure the stack
  • AWS – to consume provided services
  • Okta –  to provide authentication

Setting up the solution

Setup of the whole solution involves several steps. I have outlined them below.

Create Okta openID application

  • Login to your Okta organisation and navigate to Admin part
  • Go to application
  • Create new native application with `openID` ( this is the only option atm)
  • For the name we have used `OpenID – myAppName`
  • For the redirect URL you can paste `api://myAppName` ( or anything else if you plan to use different kind of flows )
  • Save the app and proceed to editing.
  • In general settings you need to modify *Allowed grant types* and enable `Resource Owner Password`
  • In client credentials enable `Use Client Authentication` ( make note of Client Id and Client Secret)
  • Assign the application to engineers which should have access to REST API

As a nice feature you could use claims to determine who can execute READ/WRITE actions


Verify token generation

In order to verify that you can get tokens from the app you have just created you need to call one of Okta endpoints.

  • Create basic authentication credentials consisting of the following client_id:client_secret
    You can use the following snippet

    echo "client_id:client_secret" | base64
  • With the result of that command you will be able to make calls using Authorization: Basic <result-of-command>
  • Make http call to token endpoint , making sure to replace your-okta-tenant-name , username and password
    curl -X POST \
    https://xxx.okta-emea.com/oauth2/default/v1/token \
    -H 'Authorization: Basic MG9hMmQzN.........Q==' \
    -H 'Cache-Control: no-cache' \
    -H 'Content-Type: application/x-www-form-urlencoded' \
    -d 'username=username&password=Password1&grant_type=password&scope=openid'


  • In response you should receive token in the following format
    "access_token": "eyJraW.....BvXdkU2Gg",
    "token_type": "Bearer",
    "expires_in": 3600,
    "scope": "openid",
    "id_token": "eyJr....yg"


Obtain a public key from Okta

At this point of time you have fully working Okta openID app and can obtain tokens. Our next task is to obtain public key which will allow us in later stage to verify token signature.

There are many ways to obtain the key – and each of them can either take more time or involves you providing more information. My idea was simple – automate it as much as possible… therefore I came up with go-jwk-pem (available in github ) . It is a simple CLI tool which takes either token or Okta server URL and retrieves public key which have been used to sign the JWT.

In this instance I will just use token from previous step

go-jwk-pem from-token --token eyJraW.....BvXdkU2Gg | /usr/bin/env ruby -e 'p ARGF.read'

Result of this command is single line public key , which is last piece of our puzzle which we need to make our solution working.

"-----BEGIN RSA PUBLIC KEY-----\nMIIBIjA........A4\nzTsuZ+eQLfhNbuA.....wWtcDsd+vMUlS7iJow\n2QIDAQAB\n-----END RSA PUBLIC KEY-----\n\n"


Creating AWS stack using Serverless

The time has come when we begin real fun 🙂 Let’s begin by cloning the solution from Github

One thats done we need to modify value in serverless.env.yml


Since this functions are written in go we need to build them before deploying

> [SHELL]  RafPe $ make build
env GOOS=linux go build -ldflags="-s -w" -o bin/func1 func1/main.go
env GOOS=linux go build -ldflags="-s -w" -o bin/auth auth/main.go

And now let’s deploy by using one of profile for AWS ( from credentials file ) running simple command

> [SHELL]  RafPe $ sls deploy -s dev --aws-profile myAwsProfile --verbose

Output shows us details about our functions deployes ( this is minimal blueprint so your output can have more )

Serverless: Stack update finished...
Service Information
service: test-auth
stage: dev
region: eu-west-1
stack: test-auth-dev
api keys:
  ANY - https://reiw2emcp3.execute-api.eu-west-1.amazonaws.com/dev/hello
  func1: test-auth-dev-func1
  auth: test-auth-dev-auth

Stack Outputs
AuthLambdaFunctionQualifiedArn: arn:aws:lambda:eu-west-1:123:function:test-auth-dev-auth:3
Func1LambdaFunctionQualifiedArn: arn:aws:lambda:eu-west-1:123:function:test-auth-dev-func1:3
ServiceEndpoint: https://reiw2emcp3.execute-api.eu-west-1.amazonaws.com/dev
ServerlessDeploymentBucketName: test-auth-dev-serverlessdeploymentbucket-2g5ap50n5lwn


Testing the solution

So right now we can immediately check if our setup works. Let’s start by trying to make simple http call

> [SHELL]  RafPe $ http https://reiw2emcp3.execute-api.eu-west-1.amazonaws.com/dev/hello
HTTP/1.1 401 Unauthorized
Connection: keep-alive
Content-Length: 26
Content-Type: application/json
Date: Sat, 15 Dec 2018 11:01:24 GMT
Via: 1.1 bce55e537f8dfcf0127f649d11fd1821.cloudfront.net (CloudFront)
    "message": "Unauthorized"

As expected we get Unauthorized message 😉 Let’s try to add token generated by Okta and make the call again

> [SHELL]  RafPe $ http https://reiw2emcp3.execute-api.eu-west-1.amazonaws.com/dev/hello Authorization:'Bearer eyJraWQ....QHMi5ISw'
HTTP/1.1 200 OK
Connection: keep-alive
Content-Length: 69
Content-Type: application/json
Date: Sat, 15 Dec 2018 11:10:04 GMT
Via: 1.1 94d63cbf92082237b86267ffd4cacc64.cloudfront.net (CloudFront)
X-Cache: Miss from cloudfront
X-MyCompany-Func-Reply: world-handler
    "message": "Okay so your other function also executed successfully!"

and voilla 😉 we have just created custom authorizer validating our Okta JWT.



Although this is just a blueprint it can be nicely extended. I would like to point out several items you might be interested about this

  • Solution can be nicely extended to use claims to provide appropriate access – I find it really nice
  • You are not limited to use goLang because of one function being written in go. Serverless support multiple frameworks – just need to define those on function level then ( and define what packages you are including )


if you have any feedback – please leave comment or add your code into github repo 😉





AWS – Writing better code in Node.js for Lambda functions


Been a while but finally its time to post some of technical information I accumulated since my last post. Today we will focus on improvements in code from the time you released something aka version 1 into a code base which you can run tests against.


The past …

In my last post I described some modular code I started to work on for use with Lambda ( available here ) The code back then contained a lot of redundant blocks ( which I was aware of 😉  ) however it enabled me to focus on making it better. Just to get everyone idea how it did look like here is snippet from initial code commit

....  // code removed for demo purposes // .... 

var timestamp = new Date().getTime();
  const uniqueId  = uuid.v1();

  console.log(`[CreatePlatformEndpoint] [${timestamp}] [${uniqueId}][Info] Starting execution`);
      var responseCode = 400;
      var responseBody = "";
      var response = {
        statusCode: responseCode,
        body:       responseBody

      if ( !isDef(event.body) )

          console.log(`[CreatePlatformEndpoint] [${timestamp}] [${uniqueId}][Error] Missing body information (EC.001)`);

          let errorData = {
            code: "EC.001",
            data: {
              message: "Missing body"

          response.body = {
            action:  "CreatePlatformEndpoint",
            status:  "error",
            error:   errorData,

          response.body = JSON.stringify(response.body)



      var jsonBody = JSON.parse(event.body);

      console.log(`[CreatePlatformEndpoint] [${timestamp}] [${uniqueId}][Info] Parsed body from request`);

      if ( !isDef(jsonBody.deviceToken) || !isDef(jsonBody.platformApplicationArn))

          console.log(`[CreatePlatformEndpoint] [${timestamp}] [${uniqueId}][Error] Missing required parameters in body (EC.002)`);
          let errorData = {
            code: "EC.002",
            data: {
              message: "Missing required parameters in body"

          response.body = {
            action:  "CreatePlatformEndpoint",
            status:  "error",
            error:   errorData,

          response.body = JSON.stringify(response.body)


And now this is just only portion of  code which been redundant. It was just in single file. Now imagine we have multiple components with multiple files and we need to make a single change into logic which is repeated across all those ?! Madness :/

Therefore it took some time ( as I’m far away from being a js developer 😉 ) but I changed …

Making it better …

by creating classes and also in this way trying to regain control on controlling the lifetime of object’ instances. This also enabled me to start writing tests for my code which I’m really happy about as it help so much in test driven development ( this was inspired by the following article )

  • Write your business logic so that it is separate from your FaaS provider (e.g., AWS Lambda), to keep it provider-independent, reusable and more easily testable.

  • When your business logic is written separately from the FaaS provider, you can write traditional Unit Tests to ensure it is working properly.

  • Write Integration Tests to verify integrations with other services are working correctly.


So how does the new code looks like ? Take a sneak peak on  snippet from shared resource

const uuid = require('uuid');

class xSharedFunctions { 
                this.callback       =  callback;
                this.component      =  (component === null || component === undefined ) ? 'undefined' : component ;
                this.disableLogging =  disableLogging

            let that = this;

            var responseCode = (respCode === null || respCode === undefined  ) ? 200:respCode ;
            var responseBody = "";
            var response = {
              statusCode: responseCode,
              headers: {
                "Access-Control-Allow-Origin" : "*",      // Required for CORS support to work
                "Access-Control-Allow-Credentials" : true // Required for cookies, authorization headers with HTTPS
              body:       responseBody
            response.body = {
                component: that.component,
                status:  "success",
                data: dataSuc
            response.body = JSON.stringify(response.body);
            return response;



Once that is in place we can go ahead and try to …


… use the code in our modules/applications

To get all required references we required our resources and use their functions

'use strict';

var xSharedFunctions = require('../xRes/shared/xSharedFunctions');
var xSnsEndpointManager = require('../xRes/xSnsEndpointManager');

const uuid      = require('uuid');
const component  = 'sns'

var xSharedFnc = new xSharedFunctions('sns');

module.exports.create = (event, context, callback) => {
  const uniqueId      = uuid.v1();
  var xSnsEndpointMgr = new xSnsEndpointManager(uniqueId,callback);

  xSharedFnc.logmsg(uniqueId,'info','Starting execution');



with keeping the above in mind we should not forget to …


… test our code 🙂

And that is why for example I got rests which looks like the following now ( using Mocha and Babel ) …


describe('xSnsEndpointManager', function() {
        describe('#createPlatformEndpoint()', function() {
                before(function () {

                    AWS.mock('SNS', 'createPlatformEndpoint', function (params, callback) {
                    callback(null, '{"ResponseMetadata":{"RequestId":"efdb1199-f10e-5b0b-bff9-43addbda438b"},"EndpointArn":"arn:aws:sns:eu-west-1:12345:endpoint/APNS_SANDBOX/blah-app/c08d3ccd-3e07-328c-a77d-20b2a790122f"}')


                it('should create endpoint if token provided', function(){

                    var xSnsEndpointMgr = new xSnsEndpointManager('1234',function(dummy,responseCallback){

                        let result = JSON.parse(responseCallback.body);

                        let resultData = JSON.parse(result.data);

                    let res = xSnsEndpointMgr.createPlatformEndpoint('eee','eee');

                after(function () {
                    AWS.restore('SNS', 'createPlatformEndpoint')




Closing thoughts …

So as you can see it all starts to look nice and definitely will get you further if you implement tests. For those interested to see how do I do things here are the links to my repositores on git


I hope someone would be able to reuse something for their own needs 😉 Happy coding!



AWS – API Gateway returning 502 from Lambda proxy


If you have been scratching your head why does API Gateway returns 502 and within your code there are no exceptions ?

Does your API gateway response contain something like below ?


Then make sure that you are returning correct response object containing body and status code i.e.

      var response = {
        statusCode: 200,
        body:       '\0/'

If you still see problem then consider if you are returning complex objects in your body ? If so the following should be additionally applied before returning

response.body = JSON.stringify(response.body)

And thats it 🙂 Solved the problem for me