Node.js - How to use access / auth tokens? - node.js

I have built my first Node.js app that is supposed to be installed on a Shopify store. If you want to see what my actual code looks like (app.js) you can view it here. It's really basic so reading through won't be hard.
I know how to authenticate the installation of the app (following the Shopify instructions) but I don't how to authenticate all subsequent requests using the permanent access token that a successful installation provides me with.
By subsequent requests I'm referring to requests to either render the app or requests to install the app, even though the app is already installed.
Right now, I'm storing the shop's name (which is unique) along with the permanent token that Shopify sends me in my database. But I don't know if that's necessary. If I'm not mistaken, simply using the browser's session will do ? But how do I do that ? And how do I use this token every time a request comes through to check if it is a valid one?
Thank you for any help/suggestions!
The code below is sort of a representation of what my actual code looks like in order to give you an idea of what my issues are :
db.once('open', function(callback)
{
app.get('/', function (req, res)
{
var name = getNameFrom(req);
if (existsInDB(name) && tokenExistsInDBfor(name))
{
res.redirect('/render');
/*
Is checking that the shop (along with a permanent token)
exists in my DB enough ?
Shouldn't I check whether the current request comes with
a token that is equal to the one in my DB ?
What if the token received with this request is different
from the one stored in my DB ?
*/
}
else res.redirect('/auth');
});
app.get('/auth', function (req, res)
{
if (authenticated(req))
{
var token = getPermanentToken();
storeItInDB(nameFrom(req), token);
res.redirect('/render');
/*
aren't I supposed to do anything more
with the token I've received ? send it
back/store it in the browser session as well maybe?
is storing it in the db necessary ?
*/
}
});
app.get('/render', function (req, res)
{
/*
How do I check that this request is coming
from an authorised shop that has the necessary token ?
Simply checking my DB will not do
because there might be some inconsistency correct ?
*/
res.sendFile(*file that will build app on the client*);
});
});

Getting access token from Shopify is once time process.
Save access token and shop's name in your DB, and also generate and save 'auth token' based on some algorithm. Return generated auth token to Client. Make sure client sends this auth token in every request.
Now when client hit your server verify auth token; once verified make call to Shopify API using appropriate 'access token' and shop name.
Authentication flow could be as follows:
Get Access token from Shopify
Generate token(i am refering this as auth token) for the Shopify Shop, refer this
Now save shopify's access token, shopify store name and your generated token into DB
Now send your generated token to client(save it in cookie or local storage)
Validation flow:
Clients hits your server to get data with your auth token
Verify this auth token in your DB, and get access token and shop name for that auth token
Now make calls to Shopify API using this access token and shop name
Hope this method helps

Related

firebase.auth().currentUser returning null

In the html file that I have for the sign-in page, I perform the authentication using Firebase and on successful authentication, I redirect the given user to the homepage. When I call firebase.auth().currentUser in the express file, I use for rendering and routing pages, I get undefined or null for the current user.
Can anyone help me understand what the issue might be?
This is how I perform the authentication:
firebase
.auth()
.signInWithEmailAndPassword(temail, tpass)
.then(function(firebaseUser) {
window.location.href = "http://localhost:5000/homepage";
})
.catch(function(error) {
window.alert("incorrect pass");
});
This is the code that I have in my express file:
app.get("/homepage", (req, res) => {
var user = firebase.auth().currentUser;
console.log("USER IS " + user);
res.render("menu", { title: "Welcome" });
});
Backend code doesn't have a sense of "current user". When you sign in on the frontend, the current user is only known on that client. It isn't known on the backend. If you want the backend to know which user is signed in, the client will have to send an ID token to the backend for it to verify. The documentation for the Firebase Admin SDK is used for that on the backend. The client must send the ID token to in the request to your route, and the code handling that route must verify the token in order to know the user that made the request. From the documentation:
If your Firebase client app communicates with a custom backend server, you might need to identify the currently signed-in user on that server. To do so securely, after a successful sign-in, send the user's ID token to your server using HTTPS. Then, on the server, verify the integrity and authenticity of the ID token and retrieve the uid from it. You can use the uid transmitted in this way to securely identify the currently signed-in user on your server.
When the user lands on a new page, Firebase automatically restores their previous authentication state. But to do so, it may have to contact the server, which means that it may take a few moments. While Firebase is restoring the state, auth().currentUser will be null.
To ensure you get the correct authentication state, you should use an authentication state listener, as shown in the documentation on getting the current user:
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
// User is signed in.
} else {
// No user is signed in.
}
});

how to verify a firebase admin on backend

I'm trying to implement middleware in an express server that sets custom uid/admin headers on the incoming request. This modified request will then be used after the middleware to see if an authenticated user/admin is accessing that particular resource.
To do this for a client, I just grab the token on the Authorization header and feed it into the firebase admin api's verifyIdToken method. If a uid exists, I set the header. For example:
app.use((req, res, next) => {
/* get rid of headers sent in by malicious users. */
delete req.headers._uid;
try {
const token = req.headers.authorization.split(' ')[1];
_dps.fb_admin.auth().verifyIdToken(token).then(claims => {
if (claims.uid) { req.headers._uid = claims.uid; }
next();
}).catch(err => next());
} catch(err) { next(); }
});
Two questions:
1) As an admin with a service account on another server, how would I send a request to this server such that this server can determine an admin sent the request?
2) How would I identify the admin on this server?
You will need to create your own custom Firebase token to include custom fields such as isAdmin: true in the JWT. See https://firebase.google.com/docs/auth/admin/create-custom-tokens
See (1)
Use the setCustomUserClaims() API to add a special "admin" claim to all admin user accounts, and check for it when verifying ID tokens. You can find a discussion and a demo of this use case here (jump ahead to the 6:45 mark of the recording).
Perhaps a solution would be to simply generate an API key of decent length and set it as an environment variable on each of my servers. I could then send this in the Authorization header whenever i want to make an admin https request and verify it in the middleware of the receiver by doing a simple string compare. The only people that could see this API key are those that have access to my servers (AKA admins). Let me know if something is wrong with this approach. It sure seems simple.

GCP Consume a REST API after OAuth in Node.js

I am working to implement a Node.js webapp to be deployed on GCP App Engine.
Following the Node.js Bookshelf App sample, I did manage to implement a basic user authentication flow using the passport-google-oauth20 and retrieve basic profile information. I basically just got rid of what was not needed for my purposes
My custom code is available at: gist.github.com/vdenotaris/3a6dcd713e4c3ee3a973aa00cf0a45b0.
However, I would now like to consume a GCP Cloud Storage API to retrieve all the storage objects within a given buckets with the logged identity.
This should be possible by:
adding a proper scope for the request.
authenticating the REST requests using the user session token obtained via OAuth.
About the post-auth handler, the documentation says:
After you obtain credentials, you can store information about the
user. Passport.js automatically serializes the user to the session.
After the user’s information is in the session, you can make a couple
of middleware functions to make it easier to work with authentication.
// Middleware that requires the user to be logged in. If the user is not logged
// in, it will redirect the user to authorize the application and then return
// them to the original URL they requested.
function authRequired (req, res, next) {
if (!req.user) {
req.session.oauth2return = req.originalUrl;
return res.redirect('/auth/login');
}
next();
}
// Middleware that exposes the user's profile as well as login/logout URLs to
// any templates. These are available as `profile`, `login`, and `logout`.
function addTemplateVariables (req, res, next) {
res.locals.profile = req.user;
res.locals.login = `/auth/login?return=${encodeURIComponent(req.originalUrl)}`;
res.locals.logout = `/auth/logout?return=${encodeURIComponent(req.originalUrl)}`;
next();
}
But I do not see where the token is stored, how can I retrieve it and how to use it to consume a web-service (in my case, GCP storage).
I am not at all a node.js expert, so it would be nice having a bit more clarity on that: could someone explain me how to proceed in consuming a REST API using the logged user credentials (thus IAM/ACL privileges)?
If you want to access Cloud Storage through the use of a token obtained with OAuth, when the application requires user data, it will prompt a consent screen, asking for the user to authorize the app to get some of their data. If the user approves, an access token is generated, which can be attached to the user's request. This is better explained here.
If you plan to run your application in Google App Engine, there will be a service account prepared with the necessary authentication information, so no further setup is required. You may need to generate the service account credentials (generally in JSON format), that have to be added to the GOOGLE_APPLICATION_CREDENTIALS environment variable in gcloud.
Here is an example of how to authenticate and consume a REST API with the token that was obtained in the previous step. This, for example, would be a request to list objects stored in a bucket:
GET /storage/v1/b/example-bucket/o HTTP/1.1
Host: www.googleapis.com
Authorization: Bearer [YOUR_TOKEN]

How to programmatically login to Facebook oauth2 api

Background:
I have written a Node.JS script that successfully connects to the Facebook Graph API through my facebook app. I can read data when I give it an oauth access_token, I want this script to run on my server every night to store some data. I have done a lot of research of both the facebook api, oauth and similar questions on stack overflow. I am searching the /search/?type=event&q=query endpoint
Problem:
However, Facebook returns a 60 day access_token through the oauth2 login process that required me to create an express server that simply initiates the oauth2 process, allows the user to login, and receives the access_token code and I am storing it.
I want the script to save data so that my server can provide access to updated data every day. I don't want to have to remember to login to generate the key once every 60 days.
Question:
Is there anyway to receive a oauth2 access_token without setting up an http or express server?
More importantly, how do I get the access_token without manually having to running that server every ~60 days.
Code:
The Module I am using requires the access_token and client_secret
fs.readFile('./facebookAuthServer/oauth.txt', function read(err, data) {
if (err) {
throw err;
}
fbNode.setAuthorization({token: data, clientSecret: authSettings.clientSecret});
// Use the auth for next call
fbNode.fetchItems(displayItems);
});
Is there some way to spoof headers? or could I use a short lived access token and refresh it? Anyway to refresh a 60 day token? Has anyone created a server side implementation of Oauth2 that does not require visiting the FB login more than the first time?
Here is how you can refresh your own access token using Grant and request.
First you need an OAuth client server up and running:
var express = require('express')
var session = require('express-session')
var Grant = require('grant-express')
var grant = new Grant({
server:{host:'dummy.com:3000', protocol:'http'},
facebook:{
key:'[APP_ID]',
secret:'[APP_SECRET]',
scope:['user_about_me','user_birthday'],
callback:'/callback'
}
})
var app = express()
app.use(session({secret:'very secret'}))
app.use(grant)
app.get('/callback', function (req, res) {
res.end(JSON.stringify(req.query))
})
app.listen(3000, function () {
console.log('Oh Hi', 3000)
})
Next you need an HTTP client that will simulate the browser request:
var request = require('request')
request.get({
uri:'http://dummy.com:3000/connect/facebook',
headers:{
'user-agent':'Mozilla/5.0 ...',
cookie:'datr=...; lu=...; p=-2; c_user=...; fr=...; xs=...; ...'
},
jar:request.jar(),
json:true
}, function (err, res, body) {
if (err) console.log(err)
console.log(body)
})
How you use it:
Register OAuth app on Facebook and set your Site URL (I'm assuming http://dummy.com:3000)
Add 127.0.0.1 dummy.com to your hosts file
Configure and start the server from above
Navigate to dummy.com:3000 in your browser
Open up the Developer Tools and navigate to the Network tab, make sure Preserve log is checked
Navigate to http://dummy.com:3000/connect/facebook and authenticate as usual
Take a look at the authorize request in the Network tab and copy the relevant headers to the HTTP client example (the user-agent and the cookie)
Run the HTTP client code (that's the code you are going to execute from time to time, the server should be running as well)
Resources:
Introduction about how to use Grant
Grant documentation
Request documentation - see the options section
Module:
I wrapped the above code into a module https://github.com/simov/facebook-refresh-token
Start with reading the docs, it's all described there, instead of guessing:
https://developers.facebook.com/docs/facebook-login/access-tokens
https://developers.facebook.com/docs/facebook-login/access-tokens#refreshtokens
https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow/v2.4#login
It's somehow a pity that you don't write WHAT you want to query via the Graph API, because depending on that you could either use a non-expiring page access token or an app access token, which also doesn't have to be renewed, instead of an user access token.
There's no way to automatically extend the long-lived access token. The user must visit your app again.

Phonegap + Hello.js (server side authentication)

I have a Phonegap application that is communicating with Nodejs server.
Also for the Facebook\Twitter login I'm using Hello.js library (which is very easy to use by the way).
Unfortunately this library only makes client side login (authentication), so at server side I don't know if the user is valid or not (have been looged in with Facebook\Twitter).
Edit:
After the user is logged in (client side), Hello.js provides the user credentials, with a Facebook unique user ID, but I don't know how to pass it safely to the server, or generally if its a good idea to use it as a user id in my DB.
I'm looking for a simple example that will check the validity of the login at server side too.
Thanks.
If you are using https then sending the id to your server will be fine. What you can do is just check to see if that unique id already exists in your DB and return that users data (if needed) or create a new account.
I would also recommend creating a JWT (JSON Web Token) on the server side and sending that back to the app to be stored in local storage and used to validate all future requests to your node server. You can implement that method pretty easily if you use the jwt.verify method as middleware on all of your routes.
Here is a quick example:
var jwt = require('jsonwebtoken');
var jwtValidation = function(req, res, next) {
var token = req.body.jwt_token;
if (token) {
jwt.verify(token, 'yourSecretKeyHere', function(err, decoded) {
if (err) {
// Error when checking JWT - redirect to unauthorized
res.redirect('/unauthorized');
} else if (decoded.id) {
// Token that was passed in has been decoded
// Check your DB for the decoded.id
// Complete any other needed tasks then call next();
next();
} else {
// Something else went wrong - redirect to unauthorized
res.redirect('/unauthorized');
}
});
} else {
// No token present - redirect to unauthorized
res.redirect('/unauthorized');
}
};
module.exports = jwtValidation;
This is the main idea as I figured:
In the Phonegap application, after the user has logged in, this function will be called:
hello.on('auth.login', function(r){
var token = r.authResponse.access_token;
}
now, you can send only the token to the server, and the server will get the user credentials directly from Facebook.
For example, in Facebook, call this usr:
https://graph.facebook.com/me?access_token={token}

Resources