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!
Related
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.
I am trying to access Adyen test API that requires basic authentication credentials. https://docs.adyen.com/developers/ecommerce-integration
My credentials work when accessing the API page through browser.
But I get an 401 Unauthorized response when trying to access the API with XMLHttpRequest POST request.
Javascript Code
var url = "https://pal-test.adyen.com/pal/servlet/Payment/v25/authorise";
var username = "ws#Company.CompanyName";
var password = "J}5fJ6+?e6&lh/Zb0>r5y2W5t";
var base64Credentials = btoa(username+":"+password);
var xhttp = new XMLHttpRequest();
xhttp.open("POST", url, true);
xhttp.setRequestHeader("content-type", "application/json");
xhttp.setRequestHeader("Authorization", "Basic " + base64Credentials);
var requestParams = XXXXXXXX;
xhttp.send(requestParams);
Result
That screenshot shows “Request Method: OPTIONS”, which indicates the details displayed are for a CORS preflight OPTIONS request automatically made by your browser—not for your POST.
Your browser doesn’t (and can’t) send the Authorization header when it makes that OPTIONS request, and that causes the preflight to fail, so the browser never moves on to trying your POST.
As long as https://pal-test.adyen.com/pal/servlet/Payment/v25/authorise requires authentication for OPTIONS requests, there’s no way you can make a successful POST to it.
The reason is because what’s happening here is this:
Your code tells your browser it wants to send a request with the Authorization header.
Your browser says, OK, requests with the Authorization header require me to do a CORS preflight OPTIONS to make sure the server allows requests with that header.
Your browser sends the OPTIONS request to the server without the Authorization header—because the whole purpose of the OPTIONS check is to see if it’s OK to send that.
That server sees the OPTIONS request but instead of responding to it in a way that indicates it allows Authorization in requests, it rejects it with a 401 since it lacks that header.
Your browser expects a 200 or 204 response for the CORS preflight but instead gets that 401 response. So your browser stops right there and never tries the POST request from your code.
The PAL is a Payment Authorisation API. You never want to call it from a browser. You only want to expose your username and password to send in payments in your backend code.
In Client-side encryption, the encryption is done in the browser. You then send the encrypted data to your own server. On your server you then create a payment authorization request (of which the encrypted data is one of the elements, along side payment amount, etc).
If you would be able to manage to make this run from your browser, your end solution will allow your shoppers to change amounts, currency's, payment meta data etc from the JavaScript layer. This should never be the case.
The authorization is for that reason part of the "Server side" integration part of documentation: https://docs.adyen.com/developers/ecommerce-integration?ecommerce=ecommerce-integration#serverside
Depending on your server side landscape the CURL implementation in your favorite language differs, but most of the time are easy to find.
Kind regards,
Arnoud
I am having a bit trouble understanding the following code
run.$inject = ['$http'];
function run($http) {
$http.defaults.xsrfHeaderName = 'X-CSRFToken';
$http.defaults.xsrfCookieName = 'csrftoken';
}
as I always thought that csrf is injected into html forms or ajax calls and not cookie, since csrf is a protection against any adversary trying to use your cookie for authentication.
Can someone give a detail explanation on how angular is handling csrf and how does it get the token from the backend?
I can't answer this better than the angular docs themselves do, so I'll just quote:
Cross Site Request Forgery (XSRF) Protection
XSRF is a technique by which an unauthorized site can gain your user's private data.
Angular provides a mechanism to counter XSRF. When performing XHR
requests, the $http service reads a token from a cookie (by default,
XSRF-TOKEN) and sets it as an HTTP header (X-XSRF-TOKEN). Since only
JavaScript that runs on your domain could read the cookie, your server
can be assured that the XHR came from JavaScript running on your
domain. The header will not be set for cross-domain requests.
To take advantage of this, your server needs to set a token in a
JavaScript readable session cookie called XSRF-TOKEN on the first HTTP
GET request. On subsequent XHR requests the server can verify that the
cookie matches X-XSRF-TOKEN HTTP header, and therefore be sure that
only JavaScript running on your domain could have sent the request.
The token must be unique for each user and must be verifiable by the
server (to prevent the JavaScript from making up its own tokens). We
recommend that the token is a digest of your site's authentication
cookie with a salt for added security.
The name of the headers can be specified using the xsrfHeaderName and
xsrfCookieName properties of either $httpProvider.defaults at
config-time, $http.defaults at run-time, or the per-request config
object.
The $http.defaults.xsrfCookieName is just allowing you to specify what the name of the cookie is, otherwise it's going to look for the default XSRF-TOKEN.
On the server side implementation, I'd recommend using some node.js middleware to handle the setting of the initial cookie instead of rolling your own. Take a look at csurf in particular as it seems to be the most popular. You could also try senchalab's csrf middleware. Either of those ought to be enough to get you started.
I am currently in the process of implementing a server-side OAuth2 flow in order to authorize my application.
The JS application will be displaying YouTube Analytics data on behalf of a registered CMS account to an end user (who own's a channel partnered with the CMS account). As a result of this, the authorization stage needs to be completely hidden from the user. I am attempting to authorize once, then use the 'permanent' authorization code to retrieve access tokens as and when they're needed.
I am able to successfully authorize, and retrieve an access code. The problem begins when i attempt to exchange the access code for a token.
The HTTP POST Request to achieve this needs to look like this...
POST /o/oauth2/token HTTP/1.1
Host: accounts.google.com
Content-Type: application/x-www-form-urlencoded
code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7&
client_id=8819981768.apps.googleusercontent.com&
client_secret={client_secret}&
redirect_uri=https://oauth2-login-demo.appspot.com/code&
grant_type=authorization_code
I am using this code to achieve this:
var myPOSTRequest = new XMLHttpRequest();
myPOSTRequest.open('POST', 'https://accounts.google.com/o/oauth2/token', true);
myPOSTRequest.setRequestHeader('content-type', 'application/x-www-form-urlencoded');
myPOSTRequest.send('code=' + myAuthCode + '&redirect_uri=http%3A%2F%2Flocalhost%2FCMSAuth3.html&client_id=626544306690-kn5m3vu0dcgb17au6m6pmr4giluf1cle.apps.googleusercontent.com&scope=&client_secret={my_client_secret}&grant_type=authorization_code');
I can successfully get a 200 OK response to this Request however no access token is returned, and myPOSTRequest.responseText returns an empty string.
I have played with Google's OAuth Playground - and can successfully get a token using my own credentials.
Am i missing something here?
You cannot do this, because there is the same origin policy. This is a security concept of modern browsers, which prevents javascript to get responses from another origin, than your site. This is an important concept, because it gives you the ability, to protect you against CSRF. So don't use the code authorization flow, use instead the token authorization flow.
Try and build up the full URL. Then dump it in a webbrowser. If its corect you will get the json back. You have the corect format.
https://accounts.google.com/o/oauth2/token?code=<myAuthCode>&redirect_uri=<FromGoogleAPIS>&client_id=<clientID>&client_secret={my_client_secret}&grant_type=authorization_code
Other things to check:
Make sure that you are using the same redirect_uri that is set up in google apis.
How are you getting the Authcode back? If you are riping it from the title of the page i have had issues with it not returning the full authcode in the title try checking the body of the page. This doesnt happen all the time. I just ocationally.
I am interested in how you would determine using XMLHttpRequest if the user had already authenticated with a server? I can send my request and return data but if I refresh the page and request the data again my logon form is firing even though the session time out has not expired.
Any thoughts?
Thanks
Chris
There are a couple options here. Often times a serve will respond with a login form to any unauthenticated request. Thus, if you're making an AJAX request that fetches JSON, you can just look at the content-type of the response, ala xhr.getResponseHeader('Content-Type'). Authenticated responses should be something like application/json, while unauthenticated responses will be text/html (or something like that.)
But... you can also look at document.cookie to see if the user has a session cookie defined. While this isn't a bullet-proof check (the cookie may be invalid, or the server may have additional checks in place that could still fail the request), it's not an unreasonable check to do.