Browse Source

Updating instaegram-auth and linked-auth to useing firebase-admin

Change-Id: I25fdf2011bcb9e872e4fd68e96ff180526c73828
ryanpbrewster-patch-1
Nicolas Garnier 8 years ago
parent
commit
f17d32d52b
  1. 91
      instagram-auth/functions/index.js
  2. 1
      instagram-auth/functions/package.json
  3. 12
      instagram-auth/public/main.js
  4. 44
      instagram-auth/public/popup.html
  5. 112
      linkedin-auth/functions/index.js
  6. 1
      linkedin-auth/functions/package.json
  7. 12
      linkedin-auth/public/main.js
  8. 49
      linkedin-auth/public/popup.html

91
instagram-auth/functions/index.js

@ -18,9 +18,12 @@
const functions = require('firebase-functions');
const cookieParser = require('cookie-parser');
const crypto = require('crypto');
const firebase = require('firebase');
firebase.initializeApp({
serviceAccount: require('./service-account.json'),
// Firebase Setup
const admin = require('firebase-admin');
const serviceAccount = require('./service-account.json');
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: `https://${process.env.GCLOUD_PROJECT}.firebaseio.com`
});
@ -54,20 +57,16 @@ exports.redirect = functions.https().onRequest((req, res) => {
const oauth2 = instagramOAuth2Client();
cookieParser()(req, res, () => {
try {
const state = req.cookies.state || crypto.randomBytes(20).toString('hex');
console.log('Setting verification state:', state);
res.cookie('state', state.toString(), {maxAge: 3600000, secure: true, httpOnly: true});
const redirectUri = oauth2.authorizationCode.authorizeURL({
redirect_uri: OAUTH_REDIRECT_URI,
scope: OAUTH_SCOPES,
state: state
});
console.log('Redirecting to:', redirectUri);
res.redirect(redirectUri);
} catch (e) {
res.status(500).send(e.toString());
}
const state = req.cookies.state || crypto.randomBytes(20).toString('hex');
console.log('Setting verification state:', state);
res.cookie('state', state.toString(), {maxAge: 3600000, secure: true, httpOnly: true});
const redirectUri = oauth2.authorizationCode.authorizeURL({
redirect_uri: OAUTH_REDIRECT_URI,
scope: OAUTH_SCOPES,
state: state
});
console.log('Redirecting to:', redirectUri);
res.redirect(redirectUri);
});
});
@ -95,12 +94,17 @@ exports.token = functions.https().onRequest((req, res) => {
redirect_uri: OAUTH_REDIRECT_URI
}).then(results => {
console.log('Auth code exchange result received:', results);
const token = createFirebaseToken(results.user.id);
res.jsonp({
token: token,
displayName: results.user.full_name,
photoURL: results.user.profile_picture,
instagramAccessToken: results.access_token
// We have an Instagram access token and the user identity now.
const accessToken = results.access_token;
const instagramUserID = results.user.id;
const profilePic = results.user.profile_picture;
const userName = results.user.full_name;
// Create a Firebase account and get the Custom Auth Token.
createFirebaseAccount(instagramUserID, userName, profilePic, accessToken).then(firebaseToken => {
// Serve an HTML page that signs the user in and updates the user profile.
res.jsonp({token: firebaseToken});
});
});
});
@ -110,16 +114,41 @@ exports.token = functions.https().onRequest((req, res) => {
});
/**
* Creates a Firebase custom auth token for the given Instagram user ID.
* Creates a Firebase account with the given user profile and returns a custom auth token allowing
* signing-in this account.
* Also saves the accessToken to the datastore at /instagramAccessToken/$uid
*
* @returns String The Firebase custom auth token.
* @returns {Promise<string>} The Firebase custom auth token in a promise.
*/
function createFirebaseToken(instagramUID) {
function createFirebaseAccount(instagramID, displayName, photoURL, accessToken) {
// The UID we'll assign to the user.
const uid = `instagram:${instagramUID}`;
const uid = `instagram:${instagramID}`;
// Create the custom token.
const token = firebase.app().auth().createCustomToken(uid);
console.log('Created Custom token for UID "', uid, '" Token:', token);
return token;
// Save the access token tot he Firebase Realtime Database.
const databaseTask = admin.database().ref(`/instagramAccessToken/${uid}`)
.set(accessToken);
// Create or update the user account.
const userCreationTask = admin.auth().updateUser(uid, {
displayName: displayName,
photoURL: photoURL
}).catch(error => {
// If user does not exists we create it.
if (error.code === 'auth/user-not-found') {
return admin.auth().createUser({
uid: uid,
displayName: displayName,
photoURL: photoURL
});
}
throw error;
});
// Wait for all async task to complete then generate and return a custom auth token.
return Promise.all([userCreationTask, databaseTask]).then(() => {
// Create a Firebase custom auth token.
const token = admin.auth().createCustomToken(uid);
console.log('Created Custom token for UID "', uid, '" Token:', token);
return token;
});
}

1
instagram-auth/functions/package.json

@ -4,6 +4,7 @@
"dependencies": {
"cookie-parser": "^1.4.3",
"crypto": "0.0.3",
"firebase-admin": "^4.0",
"firebase": "^3.6",
"firebase-functions": "https://storage.googleapis.com/firebase-preview-drop/node/firebase-functions/firebase-functions-preview.latest.tar.gz",
"request": "^2.74.0",

12
instagram-auth/public/main.js

@ -52,11 +52,8 @@ Demo.prototype.onAuthStateChanged = function(user) {
// Initiates the sign-in flow using LinkedIn sign in in a popup.
Demo.prototype.signIn = function() {
// This is the URL to the HTTP triggered 'redirect' Firebase Function.
// See https://firebase.google.com/preview/functions/gcp-events#handle_a_cloud_http_firebase_function_event.
var redirectFunctionURL = 'https://us-central1-' + Demo.getFirebaseProjectId() + '.cloudfunctions.net/redirect';
// Open the Functions URL as a popup.
window.open(redirectFunctionURL, 'name', 'height=585,width=400');
// Open the popup that will start the auth flow.
window.open('popup.html', 'name', 'height=585,width=400');
};
// Signs-out of Firebase.
@ -76,10 +73,5 @@ Demo.prototype.deleteAccount = function() {
});
};
// Returns the Firebase project ID of the default Firebase app.
Demo.getFirebaseProjectId = function() {
return firebase.app().options.authDomain.split('.')[0];
};
// Load the demo.
new Demo();

44
instagram-auth/public/popup.html

@ -18,7 +18,6 @@
<meta name="description" content="Demonstrates how to authorize Firebase with Instagram auth using Firebase Functions">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Authenticate with Instagram</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/es6-promise/4.0.5/es6-promise.auto.min.js"></script>
</head>
<body>
@ -50,50 +49,23 @@ Please wait...
*/
function tokenReceived(data) {
if (data.token) {
signInFirebase(data.token, data.displayName, data.photoURL, data.instagramAccessToken);
firebase.auth().signInWithCustomToken(data.token).then(function() {
window.close();
});
} else {
console.error(error);
console.error(data);
document.body.innerText = 'Error in the token Function: ' + data.error;
}
}
/**
* - Signs the user in Firebase using the given token
* - Updates the user profile (photoURL and displayName)
* - Saves the Instagram AccessToken in the Realtime Database
* - Closes the popup
*/
function signInFirebase(token, displayName, photoURL, instagramAccessToken) {
// We sign in via a temporary Firebase app to update the profile.
var tempApp = firebase.initializeApp(config, '_temp_');
tempApp.auth().signInWithCustomToken(token).then(function(user) {
// Saving the Instagram API access token in the Realtime Database.
const tasks = [tempApp.database().ref('/instagramAccessToken/' + user.uid).set(instagramAccessToken)];
// Updating the displayname and photoURL if needed.
if (displayName !== user.displayName || photoURL !== user.photoURL) {
tasks.push(user.updateProfile({displayName: displayName, photoURL: photoURL}));
}
// Wait for completion of above tasks.
return Promise.all(tasks).then(function() {
// Delete temporary Firebase app and sign in the default Firebase app, then close the popup.
Promise.all([tempApp.delete(), firebase.auth().signInWithCustomToken(token)]).then(function() {
window.close();
});
});
}).catch(function(error) {
console.error(error);
document.body.innerText = 'Error While using the Firebase Auth token to sign in: ' + error.message;
});
}
var code = getURLParameter('code');
var state = getURLParameter('state');
var error = getURLParameter('error');
if (!code) {
if (error) {
document.body.innerText = 'Error back from the Instagram auth page: ' + error;
} else if(!code) {
// Start the auth flow.
window.location.href = 'https://us-central1-' + getFirebaseProjectId() + '.cloudfunctions.net/redirect';
} else {
// Use JSONP to load the 'token' Firebase Function to exchange the auth code against a Firebase custom token.
const script = document.createElement('script');

112
linkedin-auth/functions/index.js

@ -18,9 +18,12 @@
const functions = require('firebase-functions');
const cookieParser = require('cookie-parser');
const crypto = require('crypto');
const firebase = require('firebase');
firebase.initializeApp({
serviceAccount: require('./service-account.json'),
// Firebase Setup
const admin = require('firebase-admin');
const serviceAccount = require('./service-account.json');
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: `https://${process.env.GCLOUD_PROJECT}.firebaseio.com`
});
@ -62,49 +65,88 @@ exports.redirect = functions.https().onRequest((req, res) => {
exports.token = functions.https().onRequest((req, res) => {
const Linkedin = linkedInClient();
cookieParser()(req, res, () => {
if (!req.cookies.state) {
throw new Error('State cookie not set or expired. Maybe you took too long to authorize. Please try again.');
}
console.log('Received verification state:', req.cookies.state);
Linkedin.auth.authorize(OAUTH_SCOPES, req.cookies.state); // Makes sure the state parameter is set
console.log('Received auth code:', req.query.code);
console.log('Received state:', req.query.state);
Linkedin.auth.getAccessToken(res, req.query.code, req.query.state, (error, results) => {
if (error) {
throw error;
try {
cookieParser()(req, res, () => {
if (!req.cookies.state) {
throw new Error('State cookie not set or expired. Maybe you took too long to authorize. Please try again.');
}
console.log('Received Access Token:', results.access_token);
const linkedin = Linkedin.init(results.access_token);
linkedin.people.me((error, userResults) => {
console.log('Received verification state:', req.cookies.state);
Linkedin.auth.authorize(OAUTH_SCOPES, req.cookies.state); // Makes sure the state parameter is set
console.log('Received auth code:', req.query.code);
console.log('Received state:', req.query.state);
Linkedin.auth.getAccessToken(res, req.query.code, req.query.state, (error, results) => {
if (error) {
throw error;
}
console.log('Auth code exchange result received:', userResults);
const token = createFirebaseToken(userResults.id);
res.jsonp({
token: token,
displayName: userResults.formattedName,
photoURL: userResults.pictureUrl,
email: userResults.emailAddress,
linkedInAccessToken: results.access_token
console.log('Received Access Token:', results.access_token);
const linkedin = Linkedin.init(results.access_token);
linkedin.people.me((error, userResults) => {
if (error) {
throw error;
}
console.log('Auth code exchange result received:', userResults);
// We have an Instagram access token and the user identity now.
const accessToken = results.access_token;
const instagramUserID = userResults.id;
const profilePic = userResults.pictureUrl;
const userName = userResults.formattedName;
const email = userResults.emailAddress;
// Create a Firebase account and get the Custom Auth Token.
createFirebaseAccount(instagramUserID, userName, profilePic, email, accessToken).then(
firebaseToken => {
// Serve an HTML page that signs the user in and updates the user profile.
res.jsonp({token: firebaseToken});
});
});
});
});
});
} catch (error) {
return res.jsonp({error: error.toString});
}
});
/**
* Creates a Firebase custom auth token for the given LinkedIn user ID.
* Creates a Firebase account with the given user profile and returns a custom auth token allowing
* signing-in this account.
* Also saves the accessToken to the datastore at /linkedInAccessToken/$uid
*
* @returns String The Firebase custom auth token.
* @returns {Promise<string>} The Firebase custom auth token in a promise.
*/
function createFirebaseToken(linkedInID) {
function createFirebaseAccount(linkedinID, displayName, photoURL, email, accessToken) {
// The UID we'll assign to the user.
const uid = `linkedin:${linkedInID}`;
const uid = `linkedin:${linkedinID}`;
// Create the custom token.
const token = firebase.app().auth().createCustomToken(uid);
console.log('Created Custom token for UID "', uid, '" Token:', token);
return token;
}
// Save the access token tot he Firebase Realtime Database.
const databaseTask = admin.database().ref(`/linkedInAccessToken/${uid}`)
.set(accessToken);
// Create or update the user account.
const userCreationTask = admin.auth().updateUser(uid, {
displayName: displayName,
photoURL: photoURL,
email: email,
emailVerified: true
}).catch(error => {
// If user does not exists we create it.
if (error.code === 'auth/user-not-found') {
return admin.auth().createUser({
uid: uid,
displayName: displayName,
photoURL: photoURL,
email: email,
emailVerified: true
});
}
throw error;
});
// Wait for all async task to complete then generate and return a custom auth token.
return Promise.all([userCreationTask, databaseTask]).then(() => {
// Create a Firebase custom auth token.
const token = admin.auth().createCustomToken(uid);
console.log('Created Custom token for UID "', uid, '" Token:', token);
return token;
});
}

1
linkedin-auth/functions/package.json

@ -4,6 +4,7 @@
"dependencies": {
"cookie-parser": "^1.4.3",
"crypto": "0.0.3",
"firebase-admin": "^4.0",
"firebase": "^3.6",
"firebase-functions": "https://storage.googleapis.com/firebase-preview-drop/node/firebase-functions/firebase-functions-preview.latest.tar.gz",
"node-linkedin": "^0.5.4"

12
linkedin-auth/public/main.js

@ -54,11 +54,8 @@ Demo.prototype.onAuthStateChanged = function(user) {
// Initiates the sign-in flow using LinkedIn sign in in a popup.
Demo.prototype.signIn = function() {
// This is the URL to the HTTP triggered 'redirect' Firebase Function.
// See https://firebase.google.com/preview/functions/gcp-events#handle_a_cloud_http_firebase_function_event.
var redirectFunctionURL = 'https://us-central1-' + Demo.getFirebaseProjectId() + '.cloudfunctions.net/redirect';
// Open the Functions URL as a popup.
window.open(redirectFunctionURL, 'name', 'height=585,width=400');
// Open the popup that will start the auth flow.
window.open('popup.html', 'name', 'height=585,width=400');
};
// Signs-out of Firebase.
@ -78,10 +75,5 @@ Demo.prototype.deleteAccount = function() {
});
};
// Returns the Firebase project ID of the default Firebase app.
Demo.getFirebaseProjectId = function() {
return firebase.app().options.authDomain.split('.')[0];
};
// Load the demo.
new Demo();

49
linkedin-auth/public/popup.html

@ -18,7 +18,6 @@
<meta name="description" content="Demonstrates how to authorize Firebase with LinkedIn auth using Firebase Functions">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Authenticate with LinkedIn</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/es6-promise/4.0.5/es6-promise.auto.min.js"></script>
</head>
<body>
@ -50,55 +49,23 @@ Please wait...
*/
function tokenReceived(data) {
if (data.token) {
signInFirebase(data.token, data.email, data.displayName, data.photoURL, data.linkedInAccessToken);
firebase.auth().signInWithCustomToken(data.token).then(function() {
window.close();
});
} else {
console.error(error);
console.error(data);
document.body.innerText = 'Error in the token Function: ' + data.error;
}
}
/**
* - Signs the user in Firebase using the given token
* - Updates the user profile (photoURL and displayName)
* - Saves the LinkedIn AccessToken in the Realtime Database
* - Closes the popup
*/
function signInFirebase(token, email, displayName, photoURL, linkedInAccessToken) {
// We sign in via a temporary Firebase app to update the profile.
var tempApp = firebase.initializeApp(config, '_temp_');
tempApp.auth().signInWithCustomToken(token).then(function(user) {
// Saving the LinkedIn API access token in the Realtime Database.
const tasks = [tempApp.database().ref('/linkedInAccessToken/' + user.uid).set(linkedInAccessToken)];
// Updating the displayname and photoURL if needed.
if (displayName !== user.displayName || photoURL !== user.photoURL) {
tasks.push(user.updateProfile({displayName: displayName, photoURL: photoURL}));
}
// Updating the email if needed.
if (email !== user.email) {
tasks.push(user.updateEmail(email));
}
// Wait for completion of above tasks.
return Promise.all(tasks).then(function() {
// Delete temporary Firebase app and sign in the default Firebase app, then close the popup.
Promise.all([tempApp.delete(), firebase.auth().signInWithCustomToken(token)]).then(function() {
window.close();
});
});
}).catch(function(error) {
console.error(error);
document.body.innerText = 'Error While using the Firebase Auth token to sign in: ' + error.message;
});
}
var code = getURLParameter('code');
var state = getURLParameter('state');
var error = getURLParameter('error');
if (!code) {
if (error) {
document.body.innerText = 'Error back from the LinkedIn auth page: ' + error;
} else if(!code) {
// Start the auth flow.
window.location.href = 'https://us-central1-' + getFirebaseProjectId() + '.cloudfunctions.net/redirect';
} else {
// Use JSONP to load the 'token' Firebase Function to exchange the auth code against a Firebase custom token.
const script = document.createElement('script');

Loading…
Cancel
Save