Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
*.ppk
*.glue
firebase.json
config.js

.DS_Store

Expand Down
4 changes: 2 additions & 2 deletions core/endpoints.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ var endpoints = {
sendVerificationEmailUrl: "https://www.googleapis.com/identitytoolkit/v3/relyingparty/getOobConfirmationCode?key={0}",
verifyEmailUrl: "https://www.googleapis.com/identitytoolkit/v3/relyingparty/setAccountInfo?key={0}",
sendPasswordResetEmailUrl: "https://www.googleapis.com/identitytoolkit/v3/relyingparty/getOobConfirmationCode?key={0}",
verifyPasswordResetcodeUrl: "https://www.googleapis.com/identitytoolkit/v3/relyingparty/resetPassword?key={0",
deleteAccountUrl: "https://www.googleapis.com/identitytoolkit/v3/relyingparty/deleteAccount?key={0}",
resetPasswordUrl: "https://www.googleapis.com/identitytoolkit/v3/relyingparty/resetPassword?key={0}",
changePasswordUrl: "https://www.googleapis.com/identitytoolkit/v3/relyingparty/setAccountInfo?key={0}",
accountInfoUrl:"https://www.googleapis.com/identitytoolkit/v3/relyingparty/getAccountInfo?key={0}",
Expand All @@ -25,7 +25,7 @@ endpoints.getSignUpUrl = (apiKey) => endpoints.signUpUrl.format(apiKey);
endpoints.getsendVerificationEmailUrl = (apiKey) => endpoints.sendVerificationEmailUrl.format(apiKey);
endpoints.getverifyEmailUrl = (apiKey) => endpoints.verifyEmailUrl.format(apiKey);
endpoints.getsendPasswordResetEmailUrl = (apiKey) => endpoints.sendPasswordResetEmailUrl.format(apiKey);
endpoints.getverifyPasswordResetcodeUrl = (apiKey) => endpoints.verifyPasswordResetcodeUrl.format(apiKey);
endpoints.getDeleteAccountUrl = (apiKey) => endpoints.deleteAccountUrl.format(apiKey);
endpoints.getresetPasswordUrl = (apiKey) => endpoints.resetPasswordUrl.format(apiKey);
endpoints.getchangePasswordUrl = (apiKey) => endpoints.changePasswordUrl.format(apiKey);
endpoints.getAccountInfoUrl = (apiKey) => endpoints.accountInfoUrl.format(apiKey);
Expand Down
86 changes: 86 additions & 0 deletions core/instagram.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/**
* Creates a Firebase account with the given user profile and returns a custom auth token allowing
* signing-in this account.
*
* @returns {Promise<string>} The Firebase custom auth token in a promise.
*/

var admin = require("firebase-admin");
exports.init = function (serviceAccount) {
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: 'https://' + serviceAccount.project_id + '.firebaseio.com'
});
};

exports.logInstagramUserIntoFirebase = function(instagramID, displayName, photoURL, callback) {
if (!admin){
callback('Not initialized');
return;
}

// The UID we'll assign to the user.
const uid = 'instagram:' + instagramID;
console.log('this is the user uid: ', uid)

// Create or update the user account.
var userInfo = {
displayName: displayName,
photoURL: photoURL
};
console.log('this is the user info: ', userInfo)

updateFirebaseUserOrCreateNewUser(uid, userInfo, function(err){
if (err){
console.log('this is the UPDATE ERROR: ', err)
callback(err);
return;
}
else{
const token = admin.auth().createCustomToken(uid);
console.log('this is the your TOKEN: ', token)
callback(token);
}
});
};

function updateFirebaseUserOrCreateNewUser(uid, userInfo, callback) {
admin.auth().updateUser(uid, userInfo)
.then(function(userRecord){
callback(null);
})
.catch(function(error){
if (error.code === 'auth/user-not-found') {
createFirebaseUser(uid, userInfo, callback);
}
else {
callback(error);
}
});
}

function createFirebaseUser(uid, userInfo, callback){
userInfo.uid = uid;
admin.auth().createUser(userInfo)
.then(function(userRecord){
callback(null);
})
.catch(function(error){
callback(error);
})
}

// function createCustomToken(uid, callback){
// uid = uid;
// admin.auth().createCustomToken(uid)
// .then(function(token){
// console.log('this is the your TOKEN: ', token)
// callback(token);
// })
// .catch(function(error){
// console.log('this is the user error: ', error)

// callback(error);
// })
// }
// }
14 changes: 12 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
const emailPasswordProvider = require('./providers/email-password-provider');
const socialProviders = require('./providers/social-providers');
const account = require('./user/account');
const instagram = require('./providers/insta_redirect');


function firebaseAuth(apiKey){
if (typeof(apiKey) !== 'string' || apiKey.trim().length === 0)
Expand Down Expand Up @@ -56,8 +58,12 @@ firebaseAuth.prototype.refreshToken = function(refreshToken, callback) {
account.refreshToken(this.apiKey, refreshToken, callback);
};

firebaseAuth.prototype.registerWithEmail = function(email, password, extras, callback) {
emailPasswordProvider.register(this.apiKey, email, password, extras, callback);
firebaseAuth.prototype.deleteAccount = function(token, callback) {
account.deleteAccount(this.apiKey, token, callback);
};

firebaseAuth.prototype.registerWithEmail = function(email, password, name, photoUrl, callback) {
emailPasswordProvider.register(this.apiKey, email, password, name, photoUrl, callback);
};

firebaseAuth.prototype.loginWithProviderID = function(providerToken, providerId, callback) {
Expand All @@ -80,4 +86,8 @@ firebaseAuth.prototype.loginWithTwitter = function(providerToken, callback) {
socialProviders.loginWithTwitter(this.apiKey, providerToken, callback);
};

firebaseAuth.prototype.processInstagramAuthCode = function(serviceAccount, instagramAuthCode, redirectUri, callback){
instagram.processInstagramAuthCode(serviceAccount, instagramAuthCode, redirectUri, callback);
};

module.exports = firebaseAuth;
2 changes: 1 addition & 1 deletion middlewares/protector.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
'use strict'
'use strict';

const user = require('../models/firebase-user');
const validator = require('validator');
Expand Down
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"author": "Rudigo",
"name": "firebaseauth",
"version": "0.1.0",
"version": "0.1.1",
"description": "Firebase authentication library - a node js wrapper around the Firebase REST API. It can generate Firebase auth token based on given email-password combination or OAuth token (issued by Google, Facebook, Twitter or Github). This Firebase token can then be used with REST queries against Firebase Database endpoints or for protecting resources on a server.",
"main": "index.js",
"scripts": {
Expand All @@ -12,10 +12,11 @@
},
"license": "ISC",
"dependencies": {
"firebase-admin": "^5.2.1",
"firebase-admin": "^5.4.1",
"node-rest-client": "^3.1.0",
"request": "^2.81.0",
"request-promise": "^4.2.1",
"simple-oauth2": "^1.3.0",
"string-format": "^0.5.0",
"validator": "^8.0.0"
}
Expand Down
5 changes: 2 additions & 3 deletions providers/email-password-provider.js
Original file line number Diff line number Diff line change
Expand Up @@ -278,8 +278,7 @@ exports.resetPassword = function(apiKey, oobCode, newPassword, callback){
var error = utils.processFirebaseError(err);
callback(error);
    });

}
};

exports.changePassword = function(apiKey, token, password, callback){
if (typeof(callback) !== 'function'){
Expand All @@ -291,7 +290,7 @@ exports.changePassword = function(apiKey, token, password, callback){
password: password,
idToken: token,
returnSecureToken: true
}
};

if (!validator.isLength(password, {min: 6})){
callback(utils.invalidArgumentError('Password. Password must be at least 6 characters'));
Expand Down
92 changes: 92 additions & 0 deletions providers/insta_redirect.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
'use strict';

const insta = require('../core/instagram');

// Instagram OAuth 2 setup
// const credentials = {
// client: {
// id: config.instagram.clientId,
// secret: config.instagram.clientSecret
// },
// auth: {
// tokenHost: 'https://api.instagram.com',
// tokenPath: '/oauth/access_token'
// }
// };

// var oauth2;
// exports.init = function (credentials) {
// oauth2 = require('simple-oauth2').create(credentials);
// };

// const OAUTH_REDIRECT_PATH = '/redirect';
// const OAUTH_CALLBACK_PATH = '/instagram-callback';
// const OAUTH_MOBILE_CALLBACK_PATH = '/instagram-mobile-callback';
// const OAUTH_CODE_EXCHANGE_PATH = '/instagram-mobile-exchange-code';

// Custom URI scheme for Android and iOS apps.
// const APP_CUSTOM_SCHEME = 'instagram-sign-in-demo';

// Instagram scopes requested.
// const OAUTH_SCOPES = 'basic';

/**
* Exchanges a given Instagram auth code passed in the 'code' URL query parameter for a Firebase auth token.
*/
//d6ae06a0ee134e9ea7c485c449e8d157
exports.processInstagramAuthCode = function(credentials, serviceAccount, instagramAuthCode, redirectUri, callback) {
const oauth2 = require('simple-oauth2').create(credentials);

const oauthParams = {
code: instagramAuthCode,
redirect_uri: redirectUri
};


oauth2.authorizationCode.getToken(oauthParams)
.then(function (results) {
console.log('Auth code exchange result received:', results);
// We have an Instagram access token and the user identity now.
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.
insta.init(serviceAccount);
insta.logInstagramUserIntoFirebase(instagramUserID, userName, profilePic, callback);
})
.catch(function (error) {
console.log('Auth code exchange error received:', error);
});
};

/**
* Passes the auth code to your Mobile application by redirecting to a custom scheme URL. This serves as a fallback in
* case App Link/Universal Links are not supported on the device.
* Native Mobile apps should use this callback.
*/
// exports.handleMobileRedirect = function(req, res){
// res.redirect(APP_CUSTOM_SCHEME + ':/' + OAUTH_CALLBACK_PATH + '?' + req.originalUrl.split + '?' + [1]);
// };

/**
* Exchanges a given Instagram auth code passed in the 'code' URL query parameter for a Firebase auth token and returns
* a Firebase Custom Auth token, Instagram access token and user identity as a JSON object.
* This endpoint is meant to be used by native mobile clients only since no Session Fixation attacks checks are done.
*/
// exports.handleTokenRedirect = function (req, res){
// console.log('Received auth code:', req.query.code);
// oauth2.authCode.getToken({
// code: req.query.code,
// redirect_uri: req.protocol + '://' + req.get('host') + OAUTH_MOBILE_CALLBACK_PATH
// }).then(function (results){
// console.log('Auth code exchange result received:', results);

// // Create a Firebase Account and get the custom Auth Token.
// insta.createFirebaseAccount(results.user.id, results.user.full_name, results.user.profile_picture, firebaseToken)
// .then(function (firebaseToken){
// // Send the custom token, access token and profile data as a JSON object.
// res.send(firebaseToken);
// });
// });
// };
14 changes: 7 additions & 7 deletions providers/social-providers.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
'use strict'
'use strict';

const utils = require('../core/utils');
const endpoints = require('../core/endpoints');
Expand All @@ -8,7 +8,7 @@ const ids = {
Google: "google.com",
Github: "github.com",
Twitter: "twitter.com"
}
};

function loginWithProviderID(apiKey, providerToken, providerId, callback){
if (typeof(callback) !== 'function'){
Expand Down Expand Up @@ -38,7 +38,7 @@ function loginWithProviderID(apiKey, providerToken, providerId, callback){
requestUri: "http://localhost",
returnSecureToken: true,
returnIdpCredential: true
}
};
var signInEndpoint = endpoints.getSocialIdentityUrl(apiKey);

endpoints.post(signInEndpoint, payload)
Expand All @@ -59,16 +59,16 @@ exports.loginWithProviderID = loginWithProviderID;

exports.loginWithFacebook = function (apiKey, providerToken, callback){
loginWithProviderID(apiKey, providerToken, ids.Facebook, callback)
}
};

exports.loginWithGoogle = function (apiKey, providerToken, callback){
loginWithProviderID(apiKey, providerToken, ids.Google, callback)
}
};

exports.loginWithGithub = function (apiKey, providerToken, callback){
loginWithProviderID(apiKey, providerToken, ids.Github, callback)
}
};

exports.loginWithTwitter = function (apiKey, providerToken, callback){
loginWithProviderID(apiKey, providerToken, ids.Twitter, callback)
}
};
29 changes: 28 additions & 1 deletion user/account.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ exports.getProfile = function(apiKey, token, callback){
var error = utils.processFirebaseError(err);
callback(error);
})
}
};

exports.updateProfile = function(apiKey, token, name, photoUrl, callback){
if (photoUrl && typeof(photoUrl) === 'function'){
Expand Down Expand Up @@ -105,4 +105,31 @@ exports.refreshToken = function(apiKey, refreshToken, callback) {
var error = utils.processFirebaseError(err);
callback(error);
})
}

exports.deleteAccount = function(apiKey, token, callback) {
if (typeof(callback) !== 'function'){
throw new Error('No valid callback function defined');
return;
}

if (typeof(token) !== 'string' || token.trim().length === 0){
callback(utils.invalidArgumentError('Token'));
return;
}

var payload = {
idToken: token,
}

var deleteAccountEndpoint = endpoints.getDeleteAccountUrl(apiKey);
endpoints.post(deleteAccountEndpoint, payload)
.then(function(userInfo){
var authResult = ({status: "SUCCESS"});
callback(null, authResult);
})
.catch(function(err){
var error = utils.processFirebaseError(err);
callback(error);
})
}