How can I safely implement my login routes? - javascript

I am currently making a login and registration system as a project for a website, but I am uncertain of how I can safely implement the routes/logic for it. Currently, in my client side code I send a fetch request to my login or register route, and do the logic there, and then send a JSON object back, which is manipulated whether there is an error or not, and I have implemented CORS and Header (Origin and Referrer headers) authorization middleware within my POST routes, so no external script can mass produce users/login [aka brute force]. Is there another safer and better way of handling this?

What you want to do is, to use either JWT or Session Cookies.
Algorithm ->
User visits the /login page
User enters user id and password
U send a fetch or Axios request to your servers POST API route
axios(`/<api_route_here>`,{
method: "POST",
headers: {
Authorization: `Basic ${btoa(`${username}:${password}`)}`
}
})
In the above code, we are encoding the username and password with base64 and then sending them back to the server with the Authorization header. username:password
Note: Make sure u are using an HTTPS connection
In the server u decode the Authorisation value from the header. Then create a hash of the password with username as its salt. Then query your database if the hash matches the user's password's hash.
We are hashing here to prevent leaking passwords in case of a database hack.
It is obvious, that you will store the password for the user using the same hashing technique.
If the query is positive then send a 200 response else send a 401.
In the Axios promise resolution check for the headers status code to figure out if the sign-in was successful
To prevent asking the user their password every time. U must use session cookies. i.e in step 4 if the password is correct add a Set-Cookie header property with a session token value. Store that session token to your database. Next time you API is hit, check for the cookie. if the cookie exists then check that session token with your database. otherwise, send a 401
To prevent route spamming, implement a captcha.

Related

JWT Invalidate Token

I am using express js with mongodb
Using jsonwebtoken for authentication
after successful login i put a token in cookies
For incoming requested data i check the token in cookies. if token is valid i
re-generate token and puts new token in cookies and response
requested data (just like refreshing token for each request).
Till now everything working fine and no use of db
I want to invalidate old token without db, but seems that it is impossible So doing thing as mentioned below.
For successful login i set the cookies with jwt token. Also store
that token in an array and user's info document in db too.
For each request for data i validate the token and check the token
present in array matching or not, if match i delete that token from
array generate new token put new token in array and user's info
document in db, again set new token in cookies and response data.
Above step also working fine and i am able to invalidate old token
But what if server down?? If server down all token for each users lost and all are forcefully logout
For preventing that issue i check the token in user's info document in db if token for matching token
By doing this step, no need to go in db and check for valid token or not. Db lookup only when token not present in array.
My question is for security and speed performance
Question is this implementation good? Is speed performance will be good as users increase and so many token in array for each user. Means need looping all token for matching a token in array.
Sorry for bad english

Creating a login with AWS cognito and javascript

I am creating a login page. The idea is to take the username and password then use that to get an id token from AWS cognito user pool.
Then I need to store the token in a database and transfer that token to index.html along with the username. This is because index.html needs the token to make a post request to an API gateway using the same id token and it needs to know the user name to keep track of which user is currently logged in.
Now the index.html has to check if the token transferred to it matches the token in the database or not.
If it does and the token is not expired, then there is no redirection, otherwise, the index.html redirects to login.html.
The problem is my back-end completely relies on Amazon Lambda functions and API gateways because my company does not want me to use any back-end language. Now, I found that lambda functions could not set browser cookies nor read browser cookies.
This left me no choice but to use javascript cookies, sessions and local storage to transfer the token and username to index.html. However, this approach is considered to be insecure.
There aren't any tutorials on a secure login system using cognito.
Note: Any other secure login system will do the work, but remember I need to pass username and password to user pool to get an ID token which means, if I use any other login method, then I would now need to pass username and password both to index so that index can make a request to user pool to get an id token and make a request to the API gateway.
Now my question is, is there a way to actually transfer data to index from login without compromising security? Can I use lambdas in any other way to transfer the tokens?
Please help. Thanks in advance.
Now, I found that lambda functions could not set browser cookies nor read browser cookies.
I don't think this is strictly true.
Using Lambda Proxy Integration gives your Lambda function visibility into and control over many aspects of the HTTP request. This includes setting and reading arbitrary headers (including set-cookie).
To demonstrate, you can set a function like this up and attach an API Gateway trigger (with Lambda Proxy Integration enabled) to it:
exports.handler = (event, context, callback) => {
var returnobj = {
"statusCode": 200,
"headers": {
"Content-Type": "application/json", "access-control-allow-origin": "*",
"Set-Cookie": "testcook=testval; path=/; domain=xxxxxxxxxx.execute-api.us-east-1.amazonaws.com; secure; HttpOnly"
},
"body": JSON.stringify({})
};
console.log("headers", event.headers.Cookie);
callback(null, returnobj);
};
This function returns a Set-Cookie header that the browser will respect and send along with future requests to this domain. If you hit this in a browser twice, you'll see the cookie sent by the browser and logged by the lambda on the second request.
If you aren't willing to use Lambda Proxy Integration, you can probably still pull this off by mapping part of your Lambda response to a header in API Gateway.

Setting Basic authorization details in request headers

In our application we validate user name/password. Once validation is done, credentials are encoded using base64 and then needs to be set at request header for subsequent rest calls.
Need to set below in request header.
Authorization:Basic AQNLzR69OFTNJE8X
In the response setting as below from the java code,
javax.ws.rs.core.Response.status(200).entity("").header("Authorization:","Basic AQNLzR69OFTNJE8X").build();
And in the javascript tried setting as below,
sessionStorage.setItem('Authorization:', 'Basic AQNLzR69OFTNJE8X');
But in the subsequent rest service calls in the same session can see the header request is not set with authorization. Request to provide some pointers on setting the Authorization in javascript, so that it is retained for the entire session.
I think you misunderstand how authentication works (or should work).
You are supposed to send the Authorization header only once during the authentication. If the authentication is successful, the server sends you back a session cookie and your session is marked as authenticated (server-side).
You never send back the content of the header, and you don't have to send it each request.
1) The Authorization header is not automatically added. But the cookie will be automatically sent.
2) You should not send the credential and return them: for security purposes, you want to transport them the less you can.
3) You don't want to store the credential in the sessionStorage, I don't know if this is a secure place for a password (i doubt it), but here, the password is only encoded in B64, and it's reversable. So it's as well as cleartext (which is bad for a password).
Hopes this helps!

What is the best way to update the accessToken in the app with the new accessToken?

Before getting to the actual question
Alright I have created my own authentication system that I am going to use on my API.
Simple explanation:
On /signup the user types in username, password etc... the API grants the user with tokens which are stored in the user document in the database. The API also returns with a response body with the new refreshToken and accessToken, my thought here is so the app easily can store the tokens on the phone for later calls to the API.
/login is pretty much the same thing except you only provide username and password.
One of the routes in the API is the /article which you can GET & POST.
Now if you try to for example GET the /article and your accessToken is expired the API will automatically call /token which requires the refreshToken in the header, the /token will then grant you a new accessToken and request the same route you were trying to get (in this case /article) with the new accessToken in the header.
The question:
What is the best way to update the accessToken in the app with the new accessToken?
router
.route('/article')
.get(
AuthenticateController.authenticate,
NewsController.getAllArticles,
AuthenticateController.sendAuthorize
);
This is how I do it now, AuthenticateController.authenticate authenticates the accessToken and checks if it is expired and all that then calls next().
The NewsController.getAllArticles gets all the articles and also calls next() so the AuthenticateController.sendAuthorize can run and return the new accessToken in the response header when a new one is granted (I thought this would make it easier to obatin the new token in the app). This is where my question comes in because I can't call next() on every route because on some routes the main function already returns a response and that means that next() cannot be called which means AuthenticateController.sendAuthorize will never run. I want the AuthenticateController.authenticate to be the only middleware required to authenticate the user.
Instead of waiting until the last route to send the new token, you should move the sendAuthorize middleware above the route's main response (or combine it with authenticate), and instead send a 401 Unauthorized response with the new token. Then, update the token on the client and resend the request.
It seems like a silly practice to send a valid response with an invalid accessToken anyway. You're going to want to invalidate tokens eventually (I.e on log out or password change), and you don't want users to be able to make unauthenticated requests.

Complete OpenIDConnect auth when requesting via Ajax

The normal OpenIDConnect server works like:
You go to a.com/secure-resource
You get a 302 back from the server
Your browser handles it and sends you to the identity server
You login there
It sends you back to a.com via a POST
You get logged in on a.com and get a.com/secure-resource back on your browser.
However I have a scenario that I'm trying to solve but I need your help.
The user is already logged in on idServer
The user is logged in on a.com
The user is NOT logged in on b.com
We need to send an ajax call to web server b.com (from another domain a.com)
b.com is configured to use OpenIDConnect.
But because the request to b.com is via Ajax, user cannot be redirected normally to idServer. (all we get in response is a 302)
We can go ahead and handle the 302 via Ajax (I'm still not sure whether that would work, security-wise).
BUT
Is there any scenario in IdentityServer/OpenIDConnect that is designed for these situations?
With IdentityServer in this scenario you setup server b.com to use Bearer Token Authentication, you then need to use the access token provided for a.com in the headers of your Ajax call
$.ajax({
url: 'http://b.com',
headers: {
Authorization: "Bearer " + Your Access Token
}
})
The JavaScript IdentityServer Client samples have ways of retrieving the Token from the Identity Server, see here
In a controller you can get the user and the token like this
// Get the claims values
var token= (User as ClaimsPrincipal).Claims
.Where(c => c.Type == "access_token")
.Select(c => c.Value).SingleOrDefault();
In other parts of your application you can use this
//Get the current claims principal
var identity = (ClaimsPrincipal)Thread.CurrentPrincipal;
// Get the claims values
var token = identity.Claims.Where(c => c.Type == "accept_token")
.Select(c => c.Value).SingleOrDefault();

Categories