0

I'm using Algolia to run my search requests on my Firebase Database. I have Algolia hosted on a Heroku server with a Node.js file. Algolia connects to Firebase via that Node.js app.js file.

For Firebase to authenticate Algolia I need a token which I generate after the user signs in and is authenticated on the client.

The Firebase docs says to send the token to my backend via Https-

Firebase: Get Tokens and Send to Https

I found a similar question asked on Stackoverflow but it doesn't give any code on how to do it. I'm not a Node.js dev and only lightly delved into it so I need more context

How to send Firebase token to backend?

In the function I created below func sendTokenToHerokuAppJsFile() I can send the token after it’s created. I can then use a url (it’s the second line inside the function) to send the token to but I don’t know where to get the url from.

How do I get the URL to send the token to my Heroku app.js file?

Update: @Freya in the comments very helpfully suggested I create an api on the Node side but I’m not a Node dev

How do I create a API in Node.js to receive the token?

iOS Client Swift File:

@IBAction fileprivate func signinButtonTapped(_ sender: UIButton) {

  Auth.auth().signIn(withEmail: emailTextField.text!, password: passwordTextField.text!, completion: {
            (user, error) in

            if error != nil {
                return
            }

            guard let currentUser = user else {
                return
            }

            currentUser?.getIDTokenForcingRefresh(true, completion: {
                (idToken, error) in

                if error != nil{
                    return
                }

                // Send token to your backend via HTTPS
                self.sendTokenToHerokuAppJsFile(idToken)
            })
  }
}

fileprivate func sendTokenToHerokuAppJsFile(_ idToken: String){

        let json: [String:Any] = ["token" : idToken]

        // HOW DO I GET THIS URL??
        let url = URL(string: "https://www.linkToMyHerokuAppJsFile")

        var request = URLRequest(url: url!)
        request.httpMethod = "POST"

        do {
            request.httpBody = try JSONSerialization.data(withJSONObject: json, options: .prettyPrinted)
        }catch let error as NSError{
            print(error.localizedDescription)
            return
        }

        let task = URLSession.shared.dataTask(with: request) {
            (data, response, error) in

            guard let data = data, error == nil else{
                //do something
                return
            }

            do{
                let result = try JSONSerialization.jsonObject(with: data, options: []) as? [String:Any]
                print(result as Any)

            }catch let error{
                print(error.localizedDescription)
            }
        }
        task.resume()
    }

Heroku App.Js Server file:

var idToken;     

//Firebase-Admin Initialization
var admin = require("firebase-admin");
admin.initializeApp({
  credential: admin.credential.cert({
    projectId: "********",
    clientEmail: "********",
    privateKey: "-----BEGIN PRIVATE KEY-----\n********\n-----END PRIVATE KEY-----\n"
  }),
  databaseURL: "https://********.firebaseio.com/"
});

//Firebase Initialization
var firebase = require('firebase');
var config = {
    apiKey: "********",
    authDomain: "********.firebaseapp.com",
    databaseURL: "https://********.firebaseio.com/",
    storageBucket: "********.appspot.com",
    messagingSenderId: "********"
 };
 firebase.initializeApp(config);

admin.auth().verifyIdToken(idToken)
.then(function(decodedToken) {
  var uid = decodedToken.uid;
  firebase.auth().authenticateWithCustomToken(uid)
}).catch(function(error) {
  // Handle error
});

//Algolia Initialization
var algoliasearch = require('algoliasearch');
var algolia = algoliasearch('********', '********');
Lance Samaria
  • 17,576
  • 18
  • 108
  • 256
  • I am not 100% clear of your question. I am a novice nodejs developer (working with an ios app developer), but maybe I can help. One way to do this is to create an API in node js where the swift code will send the request. From your node code, it does not seem that you have an API. Is your question about how to make the request from your swift code or how to get the token from your node code? (I can only help about the later) – Lazarus Rising Nov 02 '17 at 13:38
  • @Freya thanks for the help. You hit it exactly on the head. If you notice I have another SO link with a similar question and the answer was one way to do it was to create an API in Node.js. Since I’m not a Node dev I have no idea how to do that. A link to an article/blog/video would help but the person who left the answer didn’t leave a link. And you are correct, I don’t have an API in my Node code bcos I don’t know how. I know how to send it in Swift using **func sendTokenToHerokuAppJsFile()** but I don’t no how to receive it in Node. **My question is how to get the token from my Node code.** – Lance Samaria Nov 02 '17 at 13:48
  • 1
    I actually came from that other post, after seeing your comment. If all you want to do is expose your node code through an API in the most simple way, I would suggest you to use express. I prefer one of these two sources: https://scotch.io/tutorials/build-a-restful-api-using-node-and-express-4 or https://www.tutorialspoint.com/nodejs/nodejs_express_framework.htm. You can start from there and post your code if you need help. – Lazarus Rising Nov 02 '17 at 14:00
  • @Freya I updated the question and added another one. Thanks for pointing out I wasn’t clear. Please reread it over again. I’ll look those links over. Maybe you should post them as an answer instead of a comment and reword it to say “a simple way to do it is to use express... if you don’t know express (which I don’t) start with these links.... It might not be the answer code wise but it’ll help as a starting point. I’ll upvote it because it’s definitely a lead. Thank you! – Lance Samaria Nov 02 '17 at 14:01
  • @LanceSamaria, correct me if I am wrong, but based on the code, you are using the nodejs backend to authenticate the user using firebase auth. Once that the user is authenticated, you'd start the search? What is your exact use case? Maybe you could simplify your approach by using nodejs / firebase to authenticate the user. Once the user is authenticated, you return the token to the app. From the app you start your search using the native Algolia client, InstantSearch: https://github.com/algolia/instantsearch-ios https://github.com/algolia/instantsearch-ios-examples – Robert D. Mogos Nov 06 '17 at 09:46
  • @Robert D. Mogos Hey Robert thanks for reaching out. I noticed you work at Algolia and your forums are fantastic. To keep it short Firebase-Algolia Authentication is my use case. Instead of me explaining it here you can read my convo with a forum moderator here: https://discourse.algolia.com/t/firebase-rules-doesnt-let-algolia-run-node-js-searches-unless-rules-are-set-to-true/3516 .Please let me know what you think. Thanks for the help! – Lance Samaria Nov 06 '17 at 09:52

1 Answers1

1

I cannot test the whole node js code, but here is a start:

First install express and save it in the list of modules in package.json:

npm install express --save

var express = require('express'); //include express
var app = express(); //create your app
var idToken;     

//Firebase-Admin Initialization
var admin = require("firebase-admin");
admin.initializeApp({
  credential: admin.credential.cert({
    projectId: "********",
    clientEmail: "********",
    privateKey: "-----BEGIN PRIVATE KEY-----\n********\n-----END PRIVATE KEY-----\n"
  }),
  databaseURL: "https://********.firebaseio.com/"
});

//Firebase Initialization
var firebase = require('firebase');
var config = {
    apiKey: "********",
    authDomain: "********.firebaseapp.com",
    databaseURL: "https://********.firebaseio.com/",
    storageBucket: "********.appspot.com",
    messagingSenderId: "********"
 };
 firebase.initializeApp(config);

//here you expose the logic of token verification. From my experience, do not include the initialization (former line), or it will initialize firebase app every time you make the request
app.post('/verify_token', function (req, res) {   
    var idtoken = req.body.firebase_token; 
    admin.auth().verifyIdToken(idToken)
    .then(function(decodedToken) {
      var uid = decodedToken.uid;
      firebase.auth().authenticateWithCustomToken(uid)
    }).catch(function(error) {
      // Handle error
    });
})


//Algolia Initialization
var algoliasearch = require('algoliasearch');
var algolia = algoliasearch('********', '********');

Let's assume that the node server's url is http://mynodeserver.com. You can access this API as http://mynodeserver.com/verify_token, using post as a http method, sending firebase_token as a body param. I don't understand enough swift as to make a working code, and there are certainly variations to do this, but the essence is pretty much the same.

Based on this link: https://www.tutorialspoint.com/nodejs/nodejs_express_framework.htm

Lazarus Rising
  • 2,597
  • 7
  • 33
  • 58
  • thanks for help! I just upvoted it. I didn’t accept as answer only because you said you didn’t test it (I understand you don’t know Swift to test it). I’ll try it this weekend and if it works I’ll accept it as the answer. – Lance Samaria Nov 02 '17 at 14:19
  • can you add the links you included in your comments to your answer? It’ll help other people like me who don’t know where to start with express – Lance Samaria Nov 02 '17 at 14:24
  • 1
    @LanceSamaria No problem, I really did not post it to get upvoted or something . Cannot create an entire project with heroku and firebase to test this code for typos or different scenarios, but this is definitely one way to do it. Good luck with your project ;) – Lazarus Rising Nov 02 '17 at 14:25
  • thanks I’ll let you know when the app is live. Hopefully next week I’ll submit it to Apple. – Lance Samaria Nov 02 '17 at 14:26
  • Sorry for the late response. Thanks again ! – Lance Samaria Dec 08 '17 at 21:06