In Part 1, I introduced an app that sends an SMS notification when your Fitbit battery is low. Part 2 covers the Authentication Flow of the process.

The flow is as follows:
- User accesses the sign-up page (and by default, provides authorization via Fitbit.com). The request is passed through an API Gateway to a Lambda function. The Lambda function calls a Fitbit api to authenticate the user.
- The Fitbit authentication returns to the Lambda code. From there: (3) the token is saved to a DynamoDB database, (4) a message is placed on a SNS topic, and (5) a success response is sent back to the webpage
- The user information (access_token, refresh_token, and mobile number) is saved to a DynamoDB table
- An SN![e1079abb478cc4e04d13615bc10aa4ca[1]](http://s3.amazonaws.com/darianbjohnson/wp-content/uploads/2016/02/e1079abb478cc4e04d13615bc10aa4ca1.jpg) S topic receives the mobile number as a message S topic receives the mobile number as a message
- A success message is sent back to the end user.
- The SNS topic (step 4) calls a second Lambda function.
- The Create_User_Topic lambda function creates a sns topic for the newly authenticated user.
- Once the topic is created, a notice is sent to the user’s mobile device – asking to confirm subscription.
- The user confirms the subscription.
A few call-outs:
- I originally planned to have the sign-up request come from PHP to a SQS queue, but Lambda cannot be automatically triggered from a queue. So I used an API gateway.
- I restricted the API gateway to only accept calls from the EC2 IP address, as a second layer of security.
- There was no real need to use DynamoDB – I used it primarily because it provides cross-region availability without replication.
- I decoupled my Lambda functions in case I later decide to use a professional service to send the SMS messages.
- Lambda runs functions asynchronously.. which means I had to nest functions if a response was needed before the next function could be executed. There’s probably a cleaner way to do this with async await… but the nesting method was good enough for this exercise.
I won’t cut & paste all the code here (there are some great examples online, and I’m happy to share more details asked in the comments). I will share the Authentication function… in case there is someone out there wondering how to call the Fitbit APIs from node.js.
var aws = require('aws-sdk');  
var ddb = new aws.DynamoDB();
var sns = new aws.SNS();
exports.handler = function(event, context) {
    var client_id = 'Client ID From Fitbit';
    var client_secret = 'Client Secret From Fitbit';
    var table = "Fitbit_Authorization_Table";
    var code = event.code;
    var mobile = '1-' + event.mobile
    mobile = mobile.replace(/[^\w\s]/gi, ''); //remove crazy characters
    
    var AuthorizationHeader = new Buffer(client_id + ':' + client_secret).toString('base64');
    
    var https = require('https');
    var options = {
        host :  'api.fitbit.com',
        port : 443,
        path : '/oauth2/token?grant_type=authorization_code&code='+code,
        method : 'Post',
        headers: {'Authorization': 'Basic '+ AuthorizationHeader, 'Content-Type': 'application/x-www-form-urlencoded'}
    };
    
//Get Fitbit Authorization
    var getReq = https.request(options, function(res) {
        res.on('data', function(data) {
            
            var json_result = JSON.parse(data);
            var createtopic_data;
           
             var item = {
                "Mobile": {'S': mobile},
                "Authorization_Code": {'S': code},
                "Access_Token": {'S': json_result.access_token},
                "Refresh_Token": {'S': json_result.refresh_token},
                "Token_Type": {'S': json_result.token_type},
                "Device_Details": {'S': 'empty'},
                "User_ID": {'S': json_result.user_id},
                "Active": {'S': '0'}
            };
        
            
            
            ddb.putItem({'TableName': table,'Item': item }, function(err, data) {
                if (err){ console.log(err); console.log(item);}
                else {
                    
                    sns.publish({
                        Message: mobile,
                        Subject: "Mobile to create SNS",
                        TopicArn: 'SNS_TOPIC_TO_SEND_TO_NEXT_FUNCTION'}, function(err, data) {
                        if (err) {console.log(err.stack);
                        return;
                        }
                        else{
                            console.log("sent to sns") ;
                            context.done(null, {"Code":code, "Mobile":mobile});
                            
                        }
                    });
                }
         
            });
            
             
        });
    });
    
    //end the request
    getReq.end();
    getReq.on('error', function(err){
        console.log("Error: ", err);
    });
}Related Posts
- Working Demo
- Part 1 – Overview
- Part 2 – Authentication Flow
- Part 3 – Notification Flow (coming Mon, Feb 22)
 
					