Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Security authentication cross-origin with cookies vs Authorization header

I am using Spring Security for authentication of my REST API. The authentication is working fine and Spring Security returns a token with Set-Cookie. The rememberMe feature is turned on and the same is returned in the cookie.

When I make subsequent requests, the authentication fails unless I send the user name / password in the Authorization header, whereas when I test in postman it works. I see that it adds JSESSIONID in the cookie in the request.

Since the cookie as Http-Only cookie, I do not think that I can read them in my JavaScript function.

So how do I authenticate the user? I was under the assumption that if the server returns a cookie with set-cookie, the browser should automatically append it for each request.

Login client request:

context.$http.get(url, {
    headers:
    {
      'Access-Control-Allow-Origin': '*',
      'Access-Control-Allow-Methods': 'GET,PUT,POST,DELETE',
      'Authorization': auth
    }
  }

Request headers:

Accept:*/*
Accept-Encoding:gzip, deflate, br
Accept-Language:en-GB,en;q=0.8,fr;q=0.6,en-US;q=0.4
Access-Control-Request-Headers:access-control-allow-methods,access-control-allow-origin,authorization
Access-Control-Request-Method:GET
Connection:keep-alive
DNT:1
Host:localhost:9000
Origin:http://localhost:8080
Referer:http://localhost:8080/login?redirect=%2F
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36

Response headers:

Access-Control-Allow-Credentials:true
Access-Control-Allow-Origin:http://localhost:8080
Cache-Control:no-cache, no-store, max-age=0, must-revalidate
Content-Length:13
Content-Type:application/json;charset=UTF-8
Date:Fri, 18 Aug 2017 05:40:55 GMT
Expires:0
Pragma:no-cache
Set-Cookie:remember-me=dTVTMi94dnVkQzJtYXRFYmJkR1VKZz09OjA1T1F4RXVOV0RiTEx4VFdUSVByeGc9PQ; Max-Age=86400; Expires=Sat, 19-Aug-2017 05:40:55 GMT; Path=/; Secure; HttpOnly
Set-Cookie:JSESSIONID=4A856E0216191E8601100B600E4A227B; Path=/; HttpOnly
Vary:Origin
X-Content-Type-Options:nosniff
X-Frame-Options:DENY
X-XSS-Protection:1; mode=block

Subsequent request to get data:

this.$http.get(url).then(function (res) {
          this.items = res.data
        })

Client request:

Accept:application/json, text/plain, */*
Accept-Encoding:gzip, deflate, br
Accept-Language:en-GB,en;q=0.8,fr;q=0.6,en-US;q=0.4
Connection:keep-alive
DNT:1
Host:localhost:9000
Origin:http://localhost:8080
Referer:http://localhost:8080/Languages
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36

Server response:

HTTP/1.1 401
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Access-Control-Allow-Origin: http://localhost:8080
Vary: Origin
Access-Control-Allow-Credentials: true
WWW-Authenticate: Basic realm="Realm"
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Fri, 18 Aug 2017 05:43:26 GMT

{timestamp: 1503038407254, status: 401, error: "Unauthorized",…}
error :
"Unauthorized"
message:"Full authentication is required to access this resource"
path:"/languages"
status:401
timestamp:1503038407254

Adding withCredentials : true:

GET /languages HTTP/1.1
Host: 192.168.16.142:12345
Connection: keep-alive
Access-Control-Allow-Origin: *
Accept: application/json, text/plain, */*
Origin: http://localhost:8080
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36
Access-Control-Allow-Methods: GET,PUT,POST,DELETE
DNT: 1
Referer: http://localhost:8080/languages
Accept-Encoding: gzip, deflate
Accept-Language: en-GB,en;q=0.8,fr;q=0.6,en-US;q=0.4

Response:

Access-Control-Allow-Origin:*
Cache-Control:no-cache, no-store, max-age=0, must-revalidate
Content-Type:application/json;charset=UTF-8
Date:Mon, 21 Aug 2017 06:26:24 GMT
Expires:0
Pragma:no-cache
Transfer-Encoding:chunked
Vary:Origin
WWW-Authenticate:Basic realm="Realm"
X-Content-Type-Options:nosniff
X-Frame-Options:DENY
X-XSS-Protection:1; mode=block

FYI: I use vuejs in the frontend.

like image 581
Sam Avatar asked Aug 17 '17 16:08

Sam


People also ask

What is the problem when using cookies for authentication?

Limitations of cookie-based authenticationIt is vulnerable to Cross-site request forgery attack. It often needs other security measures such as CSRF tokens for protection. You need to store the session data in a database or keep it in memory on the server.

Are cookies sent cross origin?

With Strict , the cookie is sent only to the same site as the one that originated it; Lax is similar, except that cookies are sent when the user navigates to the cookie's origin site, for example, by following a link from an external site; None specifies that cookies are sent on both originating and cross-site requests ...

Can cookies be used for user authentication?

Specific cookies like HTTP cookies are used to perform cookie-based authentication to maintain the session for each user. The entire cookie-based authentication works in the following manner: The user gives a username and password at the time of login.

How do you prevent CORS from spring boot?

To code to set the CORS configuration globally in main Spring Boot application is given below. Now, you can create a Spring Boot web application that runs on 8080 port and your RESTful web service application that can run on the 9090 port.


1 Answers

After carefully looking at your response/request flow, you are originating requests from port 8080 to port 9000 which trigger same-origin policy(CORS) rules. CORS requests, by default, will not send credentials/cookies as documented in the link below. To enable credentials/cookies propagation, you need to set the "withCredentials" flag in your AJAX call.

Moreover, it looks like you are using vuejs. To enable withcredentials, you need to use the setting below.

Vue.http.options.credentials = true;

MDN - Request with credentials

like image 62
Newbie Avatar answered Oct 25 '22 11:10

Newbie