Authentication Header for HTML Post form - forms

Is it possbile to parse/add an authentication on the submit from a standard HTML for? E.g. I'm using oAuth to authentication logged-in users, and have a usecase where I need to use a standard HTML form with the action and method attributes. But I can't seem to find a way to parse the JWT Token I'm using for authentication. Is this possbile?
Thanks in advance.

No, you can't do it with a regular HTML form. If you need to add an Authorization header to the request, the only thing you can do is to make a request from the Javascript (as is shown in Subhashis's answer). It doesn't have to be jQuery though, you can use plain JS and fetch or some libraries for making http calls (e.g. axios). Whichever you use, remember that it will be an AJAX call, so your JS will have to handle the response properly (the response will not be handled by the browser automatically).

You may use JQuery form submit to send authorization header
var form = $('#form-id').get(0);
var formData = new FormData(form);
var xhr = new XMLHttpRequest();
xhr.open("POST", "url");
xhr.setRequestHeader("Authorization", "jwt token");
xhr.send(formData);

Related

How Do I Authenticate an API Request Using a Token With Postman

I am trying to test a Web API using Postman on a project which I have inherited from previous developers. All I know so far is that Authentication has been configured using ASP.Net Identity and Identity Server 4.0 which implements OAuth and issues short lived JSON Web Tokens (JWT) and Refresh Tokens.
If I navigate to the development website, log in (successfully), and use Chrome Developer Tools to inspect the initial log in request I can see that the body of the request contains a Form with 3 fields; userName, password and returnUrl. If I right-click on the request I can copy the request as cURL (bash) and in Postman I can import the data to create a new request. If I send the request I get a status 200 OK back and the response includes 6 cookies. However the body of the response contains an htlm page which Postman can't render and a message You need to enable JavaScript to run this app.
I'm lost now as to how I can use the response to authenticate a request for some data. Is the Token I need contained within one of the cookies? How do I extract the Token and use it within a request for some data? Any advice or suggestions would be very welcome.
Normally, with JavaScript enabled in the browser, <form> would be automatically posted to its' destination defined in action, using method. JavaScript would do somethign like the following:
window.addEventListener('load', function(){document.forms[0].submit();});
So without JavaScript, you would need to somehow parse the form that you received and recreate equivalent request.
The form, received upon successful login, contains data that should be sent back to your origin website, to authenticate the end-user.
For example, form's body contains hidden input fields, defined by OpenID protocol:
...
<input type='hidden' name='token_type' value='Bearer' />
<input type='hidden' name='expires_in' value='600' />
...
Form action attribute points back to sign-in endpoint on your website. For example:
<form method='post' action='https://{hostname:post}/signin-oidc'>

How to read server set cookie in angular 2 application, and how to send same cookie in request from angular 2 application?

Requirement : Our application needs to support same user opening our web application as separated session.
The problem is not how to use cookies in angular 2, but how can sever get cookie from HTTPServletRequest object when angular 2 application makes a rest call to server.
Implementation: Server side restful application has one filter to set user's browser session in cookie and then in HttpServletResponse. Angular client is making one call upon application bootstrap, which is going through server filter to set user's browser session in cookie.
Problem statement: angular client is making first rest call which goes through server filter to set the browser session cookie. When i open chrome developer tool, i do see that rest api response has "set-cookie" which has cookie set by server, but when i open the application tag in developer tool, i do not see any cookie set.
After that if I make any other rest call through angular application, it does not send the cookie in either request or request headers. Now, our application rest api depends on this cookie value to be present in HttpServletRequest and now it is failing.
Can someone please guide me here? I must have done something wrong on angular 2 application side, which i am not able to catch.
I have tried passing "withCredentials =true", but no change.
Another thing I noticed, if i make "GET" request, then i do see cookie in request header, but for "POST" request, I do not see anything for cookie.
Please advice.
server side code to set cookie
String uniqueId = RandomStringUtils.randomAlphanumeric(32);
Cookie userSessionCookie = new Cookie("userSessionId", uniqueId);
if (getDefaultDomain() != null) {
userSessionCookie.setDomain(getDefaultDomain());
}
httpServletResponse.addCookie(userSessionCookie); httpServletResponse.addHeader("Access-Control-Allow-Credenti‌​als", "true"); httpServletResponse.addHeader("access-control-allow-methods"‌​, "GET, POST, PUT, PATCH, DELETE, OPTIONS");
httpServletResponse.addHeader("Access-Control-Allow-Headers"‌​, "Content-Type, token,withCredentials");
angular 2 post request which expects server to get cookie from HttpServletRequest
renderFF() {
//prepare renderFInput object
var fcRenderInput = {};
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers, withCredentials: true
});
this._http.post('/api/v1/render/feature/fc',fcRenderI‌​nput,options)
.subscribe((res) => {
console.log(res.json());
});
}
Just a suggestion if this is about only one browser and multiple tabs, in this case you can use the local storage while setting some flag in it. Also when you try to open the same application in the new tab. you check if the flag is there and user is trying to open the same web application in some other tab of the same browser. You also need to delete the local storage you had set after some point.
I hope if you can get some trick to solve this issue :)

Get location fragment with Fetch API redirect response

I am trying to get the redirect response location fragment of a fetch API request. But I can't figure how to access it, if possible.
The context is that I am doing an OpenID Connect request in implicit flow, for a WebRTC Identity Proxy assertion generation.
OIDC specs define the answer of the request as:
When using the Implicit Flow, all response parameters are added to the
fragment component of the Redirection URI
HTTP/1.1 302 Found
Location: https://client.example.org/cb#
access_token=SlAV32hkKG
...
So I'm making the request with fetch set in manual mode. But the response is then an opaque-redirect filtered response, which hides the location header. (https://fetch.spec.whatwg.org/#concept-filtered-response-opaque-redirect)
Other mode for fetch are error and follow which would not help. While XHR automatically follows the redirect so would not help either. I may be missing something from the fetch API, but it seems to be something hidden on purpose.
Could someone gives me a way to access this information (or a confirmation it's impossible) ?
Is there any alternative to fetch and XHR to make this request, which would allow to access the redirect location header?
Since XHR automatically / opaquely follows redirects (in the event you're using the whatwg-fetch polyfill for example), one possible solution is to check the response.url of the fetch resolution, to see if it matches a redirect location that you expect.
This only helps if the possible redirect locations are limited or match some pattern --- for instance, if you could expect at any time to be redirect to /login:
function fetchMiddleware(response) {
const a = document.createElement('a');
a.href = response.url;
if (a.pathname === '/login') {
// ...
} else {
return response;
}
}
fetch(`/api`)
.then(fetchMiddleware)
.then(function (response) {
// ...
});
fetch isn't able to polyfill the entire standard. Some notable differences include:
Inability to set the redirect mode.
See David Graham comment on the Disable follow redirect:
This is a nice addition to the Fetch API, but we won't be able to polyfill it with XMLHttpRequest. The browser navigates all redirects before returning a result, so there is no opportunity to interrupt the redirect flow.
My Solution:
1). First solution: we are sending 200 status and redirect url(in the http header) from the server and client is redirecting based on that.
2). Second solution: Server could also redirect to with 301 and redirect url. I think, This is the best solution(i.e if we consider SEO).

Force POST form submission to send cookies

I'm working on a feature for a Chrome extension which requires making a same-origin POST request to an endpoint. For brevity, I'll leave out the particular details of the website. This request creates a resource of a given kind. I've succeeded in being able to create many kinds of these resources, but there's one type in particular that always fails.
When you use the website's own UI to create this kind of resource, I noticed that the resulting POST request is sent with the cookie header, along with some other stuff that looks unfamiliar to me. Here's an excerpt of the request headers:
:authority:www.example.com
:method:POST
:path:/path/to/endpoint
:scheme:https
[...]
cookie: [...]
The cookies are not sent for any other resource type, just this one.
Now, since this passes along cookies, the website's own javascript can't be using ajax. In fact, the site is posting to an <iframe> by linking a <form> to an <iframe> of a particular name.
So, I modified my Chrome extension code to use forms to post to iframes instead of making an ajax request, just like it's done natively on the website. However, the resulting POST requests still do not pass cookies. I have found nothing unique about the parts of the website's UI which create these special resources which might cause the requests to pass cookies.
How does Chrome decide when to pass cookies in a web request? How can I force it to do this for a <form> submission?
EDIT: Here are some more details, as requested.
To create a resource, just POST multipart data to /resource-endpoint. In jQuery you might do something like
var data = new FormData();
data.append('property', 'value'); // Add payload values
$.ajax({
url: '/resource-endpoint'
type: 'POST',
cache: false,
contentType: false,
processData: false,
data: data
});
Doing it this way will create most resources, except for the "special" resource. Since AJAX requests cannot pass along cookies, and the request to create the "special" resource must include cookies, I have to mimic the website's UI more closely.
var id = 'some-id';
var iframe = $('<iframe name="' + id + '"></iframe>');
$(document.body).append(iframe);
var form = $('<form></form>');
form.attr({
target: id,
action: '/resource-endpoint,
method: 'POST',
enctype: 'multipart/form-data'
});
// Add payload values
form.append('<input name="property" value="value" />');
$(document.body).append(form);
form.submit();
This still sends along requests, but there appears to be something missing, because requests to create the "special" resource do not include cookies. I'm not sure how the native website javascript is doing this, as I can't find any difference between the forms that create regular resources and the form that creates "special" resources.
EDIT: Nevermind, I saw a native "special resource" POST request from the UI which doesn't pass along these cookies, so the secret must not be the cookies.

backbone.js is failing with basic auth rest api

I am new to backbone.js. I built a rest api with php and I want to connect to it with backbone.js. I am having a tough time with passing the http basic auth that my rest api uses for authentication.
I can access my rest api easily by using curl from the command line like this
curl -u username:password -X GET http://api.mysite.com/user
But when I try to do a fetch (which is pretty much all I am trying to do) I get a response from my rest api that the authentication failed.
Here is my call from backbone.js
user.fetch({headers:{'Authorization':'Basic username:password'}});
With backbone.js I am getting back the response I would expect when the basic auth fails. My question is, since I know my rest api with authenticate with curl, why won't it authenticate with the above javascript?
Also, when I look at the headers sent in the js console I don't see anything about Authorization.
UPDATE
I tried the plugin listed in the comment below but got the same result
Here is my code
var User=Backbone.Model.extend({
url: 'http://api.mysite.com/user'
});
var user=new User();
user.credentials = {
username: 'username',
password: 'password'
};
user.fetch();
The username and password need to be encoded with Baes64 before being sent.
One easy way to do this (at least for testing) is to configure all jQuery ajax requests to send the info (Backbone uses jQuery for the ajax calls):
$.ajaxSetup(
beforeSend: function(xhr){
xhr.setRequestHeader("Authorization", "Basic " + btoa("USERNAME" + ":" + "PASSWORD"));
}
);
Note that btoa is the function that will encode the params with Base64. Now you can call user.fetch() and it should work properly: you don't need to provide the credentials, because we've configured jQuery to send them for us (all the time).
Of course, depending on your situation (e.g. using multiple APIs), you might prefer to specify the beforeSend attribute within each request, or have it defined within a Backbone syncfunction.
I added "Authorization" to the allowed headers list and that did the trick.
header("Access-Control-Allow-Headers: Authorization, Origin, X-Requested-With, Content-Type, Accept");