I am a bit of a javascript newbie.
I am trying access a REST endpoint that requires authorization. I've authorized correctly. The documentation on this endpoint says
"Successful authentication returns HTTP code 200, AccessToken cookie set to the proper value (if called from a browser the cookie will be automatically set so no extra work needed)"
So I authenticate, but then when i send a GET request to the URL I am getting a response saying that I am not authenticated. How do I access the token that's in the cookie so i can authenticate? thanks
there was a bug in the code. The cookie should, indeed, be submitted when "withCredentials" is set to true on the XMLHttpRequest object.
Related
I have a Nuxt.js frontend application, which performs an authentication request. There is a Laravel/Sanctum application on the backend. It uses built-in cookie-based session authentication. The authentication request fails because no X-XSRF-TOKEN HTTP header is provided in the /login request. Can anybody help to clarify why the header is not created from the cookie provided by the backend?
Note: Everything works properly on my laptop. It fails only when deployed to test enveronment (GCP VM instance + Gitlab Pages).
Auth code in Nuxt.js:
this.$axios.defaults.withCredentials = true; await
this.$axios.get("/sanctum/csrf-cookie");
console.log(document.cookie);
await this.$axios.post("/login", credentials);
I can see that XSRF-TOKEN cookie is returned by server
I also see that the XSRF-TOKEN cookie is provided in the /login POST request, while no X-XSRF-TOKEN HTTP header is created
Cookie details
I also debuged the axios source code and see the it tries to create X-XSRF-TOKEN header taking the XSRF token from the document.cookie. But document.cookie doesn't contain the token cookie as of that moment. Why?
I have found the reason. The session domain was incorrect. I have set .my-domain.co.uk and it works now.
I stored jwt in a http only cookie. I can access it automatically in java controller classes as it gets included in the request. However, I can't find a way to get the token for JavaScript ajax in order to post a request to the APIs. Those APIs require the token in authorization header. Am I doing it the wrong way?
The whole point to set a cookie as http-only so that it can not be assessed by client-side javascript. If you want the token to be included in the header from the client-side request
you can set the header Authorization: Bearer 'your token goes here'
I have just learned about JWT for authentification. Storing the JWT token in localStorage/sessionStorage is exposed to XSS. Storing it in a cookie is vulnerable to CSRF. I have been researching this and I thought of this solution, but I'm not sure how secure is this and if I should be using it in production.
The soulution is to get the JWT token from server, store it in cookie. Generate a CSRF token (that will be stored in JWT) that will be sent with each HTML page, either in a hidden HTML field of as a global JS variable (). That CSRF token will be sent with every request using JS/AJAX. This way we can rule out CSRF first then verify the JWT token.
I'm not sure whether a new token should be sent with each loaded page, or a single token should be held per session. The 1st case would mean that only the last loaded page/form would be able to submit (which could be problematic if the user is having multiple tabs of other pages open).
Is this a secure solution that might be used in production ?
Also, what other solutions would be viable to reach the same goal ?
Here is my understanding of the issue.
JWT Token - stored in httponly/secure cookie - this ensures any Javascript does not have access to it
CSRF Token - stored by JS - on login, attach the claims as a header (including your CSRF value)
When the JS gets the header, it can store the claim in a cookie, localstorage, or session storage. Because no JS has access to the JWT token in the cookie, by attaching the CSRF with every request and making sure it matches what's in the JWT, you're ensuring that it's your JS sending the request and that it was your backend that issued the token.
A hidden field isn't a great solution because you'll have to add it to each request. Depending on what framework you're using, you should be able to load the CSRF token into whatever is responsible for sending the token as a header on each request when the page is refreshed. The benefit to having all the claims in local storage or a cookie is you can preserve the users front end state. Having the exp claim means you can tell when the user no longer has a valid token in the secure jwt token cookie and you can redirect to a login page.
sessionstorage - is specific to the tab only
localstorage - is specific to the domain across tabs
cookie - is specific to the domain across tabs
Add CSFR to AJAX request:
$.ajax({
type:"POST",
beforeSend: function (request)
{
request.setRequestHeader("CSRF-TOKEN", csrfToken);
},
url: "entities",
data: "json=" + escape(JSON.stringify(createRequestObject)),
processData: false,
success: function(msg) {
$("#results").append("The result =" + StringifyPretty(msg));
}
});
Even though you're not using Angular, this still applies. You should attach the token as a header with the JS and it's fine to get that value from a cookie.
From the Angular JS Documentation
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 can read the cookie, your server can be assured that the XHR came from JavaScript running on your domain.
I am using the OAuth server flow for Google.
It starts with the user clicking a link that runs javascript to open a popup with the following request in the URI which is all working great:
var endpoint = "https://accounts.google.com/o/oauth2/auth";
endpoint = endpoint + "?scope="+encodeURIComponent(googlecalendar.SCOPES);
endpoint = endpoint + "&redirect_uri="+encodeURIComponent("https://myserver/google/");
endpoint = endpoint + "&response_type=code";
endpoint = endpoint + "&access_type=offline";
endpoint = endpoint + "&approval_prompt=force";
endpoint = endpoint + "&client_id="+encodeURIComponent(googlecalendar.CLIENT_ID);
endpoint = endpoint + "&state="+encodeURIComponent(googlecalendar.USER_ID);
On the server side, I get the state which contains the user_id for my DB and the authorisation code.
Now I want to exchange the authorisation code for access token (and renew token). This will be a HTTP request with a redirect URI, no state parameter is included.
The problem is that when I get those, I will need to store them against a user in my DB, but I don't have any way to check which user the callback is for.
The best I was able to come up with is using the token to query the google user's identity it belongs to but this still won't help me to find the user in the DB.
Can anyone help me with this flow? There must be some way to do. I don't want to use client libraries because later when I need to create watchers the PHP client library does not include this for the calendar API.
Short Answer
Despite the presence of a redirect parameter, the access token will generate a standard 200 response, not a 301 redirect. Depending on how you issue and handle the request/response, you can preserve your state.
More Detailed Answer
According to section 4.1.4 of the OAuth 2.0 spec document (RFC 6749), the response to an Access Token Request should be an "HTTP/1.1 200 OK".
In other words, the server will not perform a redirect, meaning you can issue a request and process the response in the same scope (either in the client or server, whatever your situation), so your database user ID need only be in local memory.
This is different from the Authorization Request, which is supposed to result in an "HTTP/1.1 302 Found" (redirect). See section 4.1.2.
So why is the redirect_uri parameter required?
According to section 4.1.3, the server must:
ensure that the "redirect_uri" parameter is present if the "redirect_uri" parameter was included in the initial authorization request as described in Section 4.1.1, and if included ensure that their values are identical.
In other words, the redirect_uri acts as a sort of secret or password which the server must use to verify the access token request. If the client fails to provide a redirect_uri parameter, or the parameter value is different from the original request, then the server must reject the access token request.
I am trying to do Facebook authentication in same window of my web application's login page.
I am using following code when user clicked login button to go to authentication page.
function loginUsingOAUTH()
{
top.location = 'https://graph.facebook.com/oauth/authorize?client_id=839846246064537&scope=email&redirect_uri=http://www.olcayertas.com/testqa/result.html';
}
1) After authentication Facebook redirects me to my redirect url and returns a parameter "code".
At this point I want to access Facebook user information but I don't know how to do that.
What is this "code" parameter for?
2) Is there any other way to access user information?
3) Do you have any other advice facebook authentication with same window login?
Thank you in advance for your help
When you get the code you should make a server side request to get an access token and than pass the access token to user. It is explained in Facebook Developer page:
Exchanging code for an access token
To get an access token, make an HTTP GET request to the following
OAuth endpoint:
GET https://graph.facebook.com/v2.3/oauth/access_token?
client_id={app-id}
&redirect_uri={redirect-uri}
&client_secret={app-secret}
&code={code-parameter}
This endpoint has some required parameters:
client_id. Your app's IDs
redirect_uri. This argument is required and must be the same as the original request_uri that you used when starting the OAuth login
process.
client_secret. Your unique app secret, shown on the App Dashboard. This app secret should never be included in client-side code or in
binaries that could be decompiled. It is extremely important that it
remains completely secret as it is the core of the security of your
app and all the people using it.
code. The parameter received from the Login Dialog redirect above.
Response
The response you will receive from this endpoint will be returned in
JSON format and, if successful, is
{“access_token”: <access-token>, “token_type”:<type>, “expires_in”:<seconds-til-expiration>}
If it is not successful, you will receive an explanatory error
message.