Last active
December 24, 2018 10:35
-
-
Save nathanvogel/15ed311258b91d7ec3d25f44047780e2 to your computer and use it in GitHub Desktop.
IFTTT OAuth token fake example with Firebase Cloud Functions
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This gist is based on thie example from IFTTT | |
// https://github.com/IFTTT/connect_with_ifttt_auth_sample | |
// which was originally made for the mobile SDKs, but I adapted | |
// it to run it in a Firebase Cloud Function using UIDs. | |
const functions = require("firebase-functions"); | |
var express = require("express"); | |
var int_encoder = require("int-encoder"); | |
var crypto = require("crypto"); | |
var bodyParser = require("body-parser"); | |
// The Firebase Admin SDK to access the Firebase Realtime Database. | |
const admin = require("firebase-admin"); | |
admin.initializeApp(); | |
const APP_URL = "http://localhost:3000"; | |
const ENCRYPTION_KEY = "xyz123"; | |
int_encoder.alphabet(); | |
function encrypt_string(string) { | |
var cipher = crypto.createCipher("aes-256-cbc", ENCRYPTION_KEY); | |
var crypted = cipher.update(string, "utf8", "hex"); | |
crypted += cipher.final("hex"); | |
return int_encoder.encode(crypted, 16); | |
} | |
function decrypt_string(string) { | |
key = int_encoder.decode(string, 16); | |
var decipher = crypto.createDecipher("aes-256-cbc", ENCRYPTION_KEY); | |
var dec = decipher.update(key, "hex", "utf8"); | |
dec += decipher.final("utf8"); | |
return dec; | |
} | |
function random(max) { | |
return Math.floor(Math.random() * max + 1); | |
} | |
function getTokenWithUid(uid) { | |
const token = uid + ":" + random(100); | |
// console.log("Generated token:" + token); | |
const encrypted_token = encrypt_string(token); | |
// console.log("uid:" + uid + " -> Token:" + encrypted_token); | |
return encrypted_token; | |
} | |
function getUidFromToken(token) { | |
const user_random = decrypt_string(token); | |
// console.log("user_random_t: " + user_random); | |
const uid = user_random.split(":")[0]; | |
// console.log("Token:" + token + " -> uid:" + uid); | |
return uid; | |
} | |
function getAuthCodeWithUid(uid) { | |
const authcode = uid + "." + random(100); | |
// console.log("Generated authocode:" + authcode); | |
const encrypted_authcode = encrypt_string(authcode); | |
// console.log("uid:" + uid + " -> Code:" + encrypted_authcode); | |
return encrypted_authcode; | |
} | |
function getUidFromAuthCode(authcode) { | |
const user_random = decrypt_string(authcode); | |
// console.log("user_random_c: " + user_random); | |
const uid = user_random.split(".")[0]; | |
// console.log("Code:" + authcode + " -> uid:" + uid); | |
return uid; | |
} | |
var app = express(); | |
// parse application/x-www-form-urlencoded | |
app.use(bodyParser.urlencoded({ extended: false })); | |
// parse application/json | |
app.use(bodyParser.json()); | |
// ****************** START OAUTH SERVER ****************** | |
// Since I'm not using the Connect with IFTTT SDK, I'm not calling | |
// /generate_oauth_code from the client, but rather redirecting the user | |
// to the app, which will then redirect to /oauth/authorize_user with the UID. | |
// PS: I'm not sure if it's a good clean idea. | |
app.get("/oauth/authorize", (req, res) => { | |
console.log(req.url); | |
// Redirect my user to my app (in the auth popup opened by IFTTT) | |
// and indicate to my app where to redirect the user if the user authorizes | |
// IFTTT to access his account. | |
// The actual code generation is done in /oauth/authorize_user, to which my | |
// app redirects my user once they've authorized IFTTT access. | |
// redirect_uri and state are carried over from | |
res.redirect( | |
APP_URL + | |
"/authorize_ifttt?state=" + | |
req.query.state + | |
"&redirect_uri=" + | |
encodeURIComponent(req.query.redirect_uri) | |
); | |
}); | |
// After having authorized IFTTT access, the client makes this request. | |
// Now that we have the UID, we can generate an auth code for IFTTT and | |
// redirect with the state that IFTTT gave us at the beginning. | |
// We should probably check that he did set the permissions, | |
// in the RTDB for example. | |
app.get("/oauth/authorize_user", (req, res) => { | |
console.log(req.url); | |
var code = getAuthCodeWithUid(req.query.uid); | |
var redirect_uri = "https://ifttt.com/channels/mltest/authorize"; | |
res.redirect( | |
redirect_uri + | |
"?code=" + | |
encodeURIComponent(code) + | |
"&state=" + | |
req.query.state | |
); | |
}); | |
// Our standard OAuth token exchange endpoint. | |
// We'll take a code that was generated previously in the | |
// /generate_oauth_code or /oauth/authorize_user endpoint | |
app.post("/oauth/token", (req, res) => { | |
console.log(req.url); | |
console.log("Body code: " + req.body.code); | |
try { | |
// Decrypt the uid from the code | |
var uid = getUidFromAuthCode(req.body.code); | |
} catch (e) { | |
res.json(401, { error: "Invalid auth code" }); | |
return; | |
} | |
// Re-encrypt our uid as the app OAuth access token | |
res.json({ | |
token_type: "bearer", | |
access_token: getTokenWithUid(uid) | |
}); | |
}); | |
// ****************** END OAUTH SERVER ****************** | |
// ****************** START IFTTT API ****************** | |
app.get("/ifttt/v1/user/info", (req, res) => { | |
var bearer_token = req.header("Authorization").split(" ")[1]; | |
try { | |
// Decrypt the uid from the code | |
var decrypted = getUidFromToken(bearer_token); | |
} catch (e) { | |
res.json(401, { error: "Invalid access token" }); | |
} | |
var uid = decrypted; | |
console.log("Asking user info for " + uid); | |
admin | |
.auth() | |
.getUser(uid) | |
.then(userRecord => { | |
return res.json({ | |
data: { | |
name: userRecord.displayName, | |
url: APP_URL, | |
id: userRecord.uid | |
} | |
}); | |
}) | |
.catch(e => { | |
return res.status(400).json({ | |
errors: [ | |
{ | |
message: "Error: couldn't retrieve user " + uid + ". " + e.message | |
} | |
] | |
}); | |
}); | |
}); | |
// ****************** END IFTTT API ****************** | |
exports.iftttapi = functions.https.onRequest(app); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment