I have an API that I want to secure, I'm thinking of use Firebase ID tokens and include a token in every request, using:
firebase.auth().currentUser.getToken(/* forceRefresh */ true).then(function(idToken) {
// Send token to your backend via HTTPS
}).catch(function(error) {
// Handle error
});
and then verify the token.
Could this slow down the request to the API?
The answer is of course, yes, authentication will always slow down the request to the API. But it should be pretty minimal.
Related
I'm trying to figure out how to use the token event as specified in Google's OAuth 2.0 documentation for server side applications (using Node.js):
Here's the code for the token event:
oauth2Client.on('tokens', (tokens) => {
if (tokens.refresh_token) {
// store the refresh_token in your secure persistent database
console.log(tokens.refresh_token);
}
console.log(tokens.access_token);
});
I actually get this event to fire, but am unsure about when to check for a valid token. If I do this one every request (let's say Google Docs API request), the token event fires after I'm requesting the API, so credentials are not set correctly.
How would you go about making sure that the correct access token is set BEFORE making a request?
Google says "Once the client has a refresh token, access tokens will be acquired and refreshed automatically in the next call to the API.", which is also kind of the case, but too late.
So my question once again: How do I, in my call, wait for the token event to finish updating my access token in order to set credentials BEFORE making the request?
Thank you!
Before I have to say that I've found some post related this question but not fully answered.
So I implement a nodejs REST API server, DB with mongoDB, however about authentication i understand the idea, with jwt token it work perfect.
/api/login
you get response with token. now you can request resource with this token
for example.
api/posts/:user_id
get all your posts...No problem! query with mongoose findBy.. bla bla!
so for authorization in this case it's easy, check for query param user_id is equal to token (token parse with user_id). boom resources is secure.
but in case that I have some resources they're not reference by user_id, What is best practice to protect this resources?!
example
api/settings/:settings_id/emails
imagine that I know the setting_id of other user, and i authenticated with token. so how server will know this resources is not allowed for me?
First, you should do more to protect the token in the first place. When you issue a token after a user logs in you should store their token on either web storage like sessionStrorage if https is enforced or use an httpOnly cookie (You can add a user-agent/geoip fingerprint in addition to the user_id upon signing this token to add an additional layer of security). Then, when a user makes a request for a protected resource, you can match the fingerprint and user_id you signed the token with to the user they are making the request in behalf of.
You could use something like passport-jwt as a middleware in express to require authentication on routes. In passport, you define an extractor handler that basically tells it where to look to see if the user has a token and if they do and it validates it adds the req.user property that you can use on subsequent requests to determine the user_id of the token bearer. So basically with this approach, you know the user_id on every request which lets you compare that with the user information they are requesting.
app.post('/settings/:settings_id/emails', passport.authenticate('jwt', { session: false }),
function(req, res) {
res.send(req.user.id);
}
);
I'm using web firebase javascript to authenticate by email and password. This process generates a token which I use to verify on my nodejs backend using firebase-admin. Once this token is generated, I store it on the browser local/session storage.
The front end is AngularJs which I intercept the http request to inject the token stored within the browser.
This is working fine, however after a while this token expire. So what would be the best way to refresh this token before it sends to the nodejs api?
Note: should I requet the currentUser.getToken() every request?
The currentUser.getIdToken() only refreshes the token when the current token has expired! So it doesn't create unneeded traffic or requests to Firebase!
firebase.auth().currentUser.getIdToken(true) // here we force a refresh
.then(function(token) {
// ... do stuff!
}).catch(function(error) {
if (error) throw error
});
You'll see that I added true as an argument to the getIdToken() function. This forces a refresh!
Here is the Firebase Documentation for the getIdToken() function.
I hope that helps!
In my application,while registering the users i am saving username,password and jwt generated token with these fields in MONGO DB.When user tries to login with correct credentials then i will send the response with stored token.Then at client side(In my controller) i am using the localstorage to store the token so that i can send the same token for each and every request sent by the client.But I found some issues regarding this procedure:
I am generating same token for one user every time.So if any third person is able to get the token then he can access the restricted page.
Am i wasting space in db by storing the generated token in MONGODB
Can Anyone access the token stored in localstorage other than the user.
for each and every request in my single page application,I am again querying mongodb to get the token for that user and validating.Here,I am checking both client side and server side.
I am using jwt to generate tokens,Node,Express,Mongoose in my application
Am i following the good procedure.If not,can you please provide the solution for my approach or any new approach.
I have searched many sites for token based authorization and session based authorization,But nothing worked for me.
Note:I am beginner for Nodejs,AngularjS
You should store token in advanced key-value cache tool like: Redis
That would improve performance remarkably.
You will get token from database for 1st time then it should be stored in Redis. I used to set token as key and username as value. Next request , the token will be given from cache. with Redis you can set expire for token.
When a user registers, you would need to generate a JWT like you're doing now. That's OK. You don't need to save it to the database however. You didn't ask but I assume that the password should not be stored in clear text. You can use something bcrypt to encrypt before saving it to the database.
When user tries to login with correct credentials then i will send the response with stored token
Yes, that's correct way to do.
Then at client side(In my controller) i am using the localstorage to store the token so that i can send the same token for each and every request sent by the client.
Yes, on the client side, you can save the JWT to local storage and send it in subsequent requests to the server.
Now your bullet points:
So that you won't have the same JWT each time, you can include an "exp" claim in the payload (I'm assuming you're using something like jwt-simple to generate a JWT). Something like:
var payload = {
sub: account.username,
exp: moment().add(10, 'days').unix()
};
var token = jwt.encode(payload, "secret");
You don't need to store the JWTs in the database. In some cases, the token issuers (the authorization servers) are not the same as the resource servers. The resource servers only receives the JWTs in a request but there's no way for the resource servers to touch the database used by the authorization servers. Side note: If you eventually need to support refresh tokens, i.e. the JWTs that you hand to the clients will need to eventually expire, then you can store the refresh token in a database. Refresh tokens are not the same as JWTs (access tokens). The complexity to support refresh tokens will increase.
Local storage is not where you store passwords, but it can be used to store JWTs. For that very reason, a JWT must and should expire after a certain time.
Not sure what you mean by saying you check both client side and server side. When the client needs to access a resource (again it's fair to assume that the resource server might not be the same as the authorization server), the only thing that the resource server is passed is the JWT. Anyone can decode a JWT. For example, try to paste your JWT on this site http://jwt.io/. That's why a JWT should not contain any sensitive data. But if the resource server knows the secret that the authorization server uses when it encode the JWT, the resource server can verify the signature. Back to your third bullet, that's why it's OK to store the JWT in local storage of the client.
Update I'm updating this to answer to some of your questions in the comment box.
User clicks on 'Login' button triggers the Angular controller to post a request to the server, something like:
$http.post(url, {
username: $scope.username,
password: $scope.password
}).success(function(res) { ... })
Server receives the POST request, it checks username/password, then it generates a JWT, and sends back to the browser. Note that it does not have to save the JWT to the database. The code would be something like
var payload = {
sub: account.username,
exp: moment().add(10, 'days').unix()
};
var token = jwt.encode(payload, "secret");
res.status(200).json({
token: token
});
Back on the client side, in the success() callback above, now you can save the JWT in local storage:
.success(function(res) { $window.localStorage.setItem('accessJWT', res.token) })
The user is now authenticated. Now when user wants to access a protected resource, user don't have to provide username/password. With the JWT which can be retrieved from local storage, the client can now put the JWT in the Authorization header of the request using the bearer scheme, and sends the request to the server. In code, it would like:
headers.Authorization = 'Bearer ' + token;
The server receives the request. Again, this server receiving this request does not have to be the same as the server which generates the JWT above. The 2 servers can be in 2 different continents. Even if you save the JWT above, that does not do any good to this server which can not access the database where the JWT is stored. But this server can pull out the bearer token from the header of the request, validates the token and carries on with the normal tasks.
Hope this helps.
You do not want to store the JWT in mongoose because it appears in headers when logging in. You first generate a token then hash it using a module like crypto.
There are different ways to do this and they all use Passport which handles the tokens. Here's an example project Satellizer
I would recommend you generate the angular-fullstack project. Then go through the server/auth folder and the client/account folder. You will see how to securely handle authentication in a MEAN based app.
I am trying to create a login procedure with the Parse and Facebook Javascript SDK. The authentication works without a problem on the client side, but I need to access the user object (created by Parse SDK) on the server side too. How can I do this the most elegant way? I thought when I log in into Facebook via Parse a cookie is set and so I can access the user object from the server. Or should I do the login process server side? Any recommendations?
I'm facing the same problem. Turns out that you can use either server-side auth or client-side auth. You cannot mix-and-match the two. Have a look at their official blog post about sessions.
var parseExpressCookieSession = require('parse-express-cookie-session');
// In your middleware setup...
app.use(express.cookieParser('YOUR_SIGNING_SECRET'));
app.use(parseExpressCookieSession({ cookie: { maxAge: 3600000 } }));
// Making a "login" endpoint is SOOOOOOOO easy.
app.post("/login", function(req, res) {
Parse.User.logIn(req.body.username, req.body.password).then(function() {
// Login succeeded, redirect to homepage.
// parseExpressCookieSession will automatically set cookie.
res.redirect('/');
},
function(error) {
// Login failed, redirect back to login form.
res.redirect("/login");
});
});
Also, I came across this when digging through the doc:
You can add Parse.User authentication and session management to your
Express app using the parseExpressCookieSession middleware. You just
need to call Parse.User.logIn() in Cloud Code, and this middleware
will automatically manage the user session for you.
You can use a web form to ask for the user's login credentials, and
log in the user in Cloud Code when you receive data from this form.
After you call Parse.User.logIn(), this middleware will automatically
set a cookie in the user's browser. During subsequent HTTP requests
from the same browser, this middleware will use this cookie to
automatically set the current user in Cloud Code.
...
When you work with user data, you should use HTTPS whenever possible.
To protect your app and your users, the parseExpressCookieSession
middleware requires you to use HTTPS. For your convenience, we also
provide a parseExpressHttpsRedirect middleware for redirecting all
HTTP requests to HTTPS.