How to pass bearer token into request header - c#

It's my first time building a web api. I've successfully set up the model view controller and enabled token generation. However, I am stuck on how to pass the access token through the request header. After I have logged in and attempt to view another page, there is nothing in the header in regards to the authorization therefore I receive a 401 error. I've looked at several blogs, forums and articles over the past couple days and cannot come to a conclusion on how this is done. I have my jquery storing the header in a variable, but I am unsure on where that is stored and how to reference it or where to put the reference. I've messed around with setting it in global.asax and some of the config files, also at the top of the controller class. My next thought is to create a web page for each controller and storing the authorization there, even still I don't know how to dynamically place a token that would vary for other users. I feel like there is something very simple that I'm missing. I suppose my question is how do I store my javascript variable in each request header? Here is my javascript for reference:
$("#btnLogin").on('click', function () {
//var data = { Email: $("#loginEmail").val().trim(), Password: $("#textPwd").val().trim(), ConfirmPassword: $("#loginPwd").val().trim() };
$.ajax(
{
url: "/TOKEN",
type: "POST",
data: $.param({ grant_type: 'password', username: $("#loginEmail").val(), password: $("#loginPwd").val() }),
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
success: function (resp) {
sessionStorage.setItem('userName', resp.userName);
sessionStorage.setItem('accessToken', resp.access_token);
var authHeaders = {};
authHeaders.Authorization = 'Bearer ' + resp.access_token;
$.ajax({
url: "https://localhost:44327/api/values",
type: "GET",
headers: authHeaders,
success: function (response) {
$("#loginEmail").val(),
$("#loginPwd").val(),
$("#msg").text(response)
}
});
},
error: function () {
$("#msg").text("Authentication failed");
}
})
});

Related

Angular Post Request Cors issue

I got CORS issue when I am trying to make post request to c# web api.
Below is the error:
Access to XMLHttpRequest at 'api url in different domain' from origin
'client url' has been blocked by CORS policy: Response to preflight
request doesn't pass access control check: No
'Access-Control-Allow-Origin' header is present on the requested
resource.
The same API call with GET request is working.
Both sites are deployed with windows authentication enabled.
I am using Angular io, 1.7.** with typescript. Below is how I call the api with post request in typescript.
let httpHeader = new HttpHeaders();
httpHeader = httpHeader.set('Content-Type', 'application/json');
this.http.post(this.apiUrl, this.bodyObject,
{
headers: httpHeader,
withCredentials:true
}).pipe(map(response => {
return response;
})).subscribe(result => {
console.log(result);
}, function (err) {
console.log(err);
});
I first thought that it might be api cors issue and tested with below jquery code and it is working.
<script>
$.ajax({
url:apiUrl,
type: 'post',
data: {
serviceName: "Country"
},
xhrFields: {
withCredentials: true
},
dataType: 'json',
success: function (data) {
console.info(data);
},
error: function (err) {
console.error(err);
}
});
</script>
So I think, I have something to do with my angular code. Can you guy highlight me what could be the issue.
try to add this in $.ajax
headers: {
'Access-Control-Allow-Origin': '*',
'Content-Type':'application/json'
},
crossDomain: true,

Call server method without page reload with razor page

In my .net core razor page project, i would like to call server side methods from a cshtml input without reloading the page. I'm still a newbie with razor pages.
.cshtml :
input type="submit" id="AddCart" asp-page-handler="AddToCart" hidden
Some JS to .click() the input.
.cs :
public async void OnPostAddToCart()
{
//code
}
So far i did not find a way to prevent the page reload and still access my server-side methods.
Thanks
EDIT :
Looking at the link provided by brad, i managed to make it work.
I added #Page "{handler?}" to write the url without the handler (not sure if it matters for ajax),
I set my ajax url to "thePage/theMethod",
I decorated my razor controller class with [ValidateAntiForgeryToken]
And mentioned the anti forgery token in ajax :
$.ajax({
url: "/mainPage/AddToCart",
type: "POST",
contentType: "application/json; charset=utf-8",
beforeSend: function (xhr) {
xhr.setRequestHeader("XSRF-TOKEN",
$('input:hidden[name="__RequestVerificationToken"]').val());
},
success: function () {
alert("success");
},
complete: function () {
alert("complete")
},
failure: function () {
alert("failure");
}
});
First ,change the naming of your Handler method like below :
public async void OnPostAddToCartAsync()
{
//code
}
Refer to Handler Methods in Razor Pages for more details on the nameing convention .
Second ,If you want to use ajax in Razor Pages , the URL pattern should be like "/mainPage?handler=AddToCart" .One thing to note down is, Razor Pages are designed to be protected from (CSRF/XSRF) attacks. Hence, Antiforgery token generation and validation are automatically included in Razor Pages. I believe that is the problem here. Your page may have antiforgery token present on the page if you have form tag in your HTML. But you need to pass the same in your Ajax request.
Add antiforgery token using #Html.AntiForgeryToken(), if not
present.
Modify your Ajax request to send the same in request header like
below:
<input type="button" id="AddCart" onclick="clickbtn()" value="Submit"/>
function clickbtn() {
$.ajax({
url: "/Test?handler=AddToCart",
type: 'POST',
beforeSend: function (xhr) {
xhr.setRequestHeader("X-XSRF-TOKEN",
$('input:hidden[name="__RequestVerificationToken"]').val());
},
success: function ()
{
alert("success");
},
complete: function ()
{
alert("complete")
},
failure: function ()
{
alert("failure");
}
});
}
Since the script sends the token in a header called X-XSRF-TOKEN,
configure the antiforgery service to look for the X-XSRF-TOKEN
header:
services.AddAntiforgery(option => option.HeaderName = "X-XSRF-TOKEN");
Read this post Handle Ajax Requests in ASP.NET Core Razor Pages to know more about making ajax request with ASP.NET Core razor pages.
If you do not want to reload the page you must use ajax or XMLHttpRequest , (the former being based on the latter).
<script>
window.onload=function()
{
window.click=function()
{
$.ajax({
url: '[baseUrl/OnPostAddToCart]',
data: JSON.stringify(postData), //your data
type: 'POST',
contentType: 'application/json',
dataType: 'json',
success: function (result) {
alert(result); //do something if successful
},
complete: function(){
//do something on complete
},
failure: function (err) {
alert(err); // Display error message
}
});
}
}
</script>
<input onclick="click()" type="button"/>
Using XMLHttpRequest:
window.click=function()
{
var xhr = new XMLHttpRequest();
xhr.open("POST", "[Your URL]");
xhr.onload=function()
{
if(xhr.status==200)
resolve(xhr.response);
else
reject("error:"+xhr.status);
}
var data=JSON.stringify({some_data});
xhr.send(data);
}
Controller method
public class MyController:Controller
{
[HttPost]
[Route("/OnPostAddToCart")]
public async Task AddToCart(object data)
{
}
}
P.S For more information on ajax

ASP.Net WebAPI Owin authentication token in Knockout

I am trying to create a demo project which uses .Net ASP.Net WebAPI and KnockoutJs as the front end. I have created the controller methods that listen for the /token post, and validates a user, and returns a token. This is done from an Ajax Post from the Knockout View Model.
This code works. However, when I get 200 back (Success) from the webApi, I then redirect to a controller method, decorated with a [Authorize]. And that's where I hit a 401 - not authorised.
Login()
{
var data = {
username : this.login.emailAddress(),
password : this.login.password(),
RememberMe: this.login.rememberMe(),
grant_type: "password"
}
return $.ajax({
type: "POST",
data: data,
dataType: "json",
url: "/token",
contentType: "application/json"
}).done((reply) => {
window.location.href = "/Home/AnotherThing";
});
}
I think the issue is - I get a response back from my /token (login) call, but do nothing with it. I'm not sure what to do with the token. I stupidly thought that OAuth would somehow put the token into my headers, and they would be there magically. I was wrong.
So, I've been looking for an example, and then best I can find is Here
But this means I am going to have a LOT of repeated code, on each view model
Extract:
function ViewModel() {
var self = this;
var tokenKey = 'accessToken';
var RefTokenKey = 'refreshToken';
self.result = ko.observable();
self.user = ko.observable();
self.token = ko.observable();
self.refreshToken = ko.observable();
function showError(jqXHR) {
self.result(jqXHR.status + ': ' + jqXHR.statusText);
}
self.callApi = function () {
self.result('');
var token = sessionStorage.getItem(tokenKey);
var headers = {};
if (token) {
headers.Authorization = 'Bearer ' + token;
}
$.ajax({
type: 'GET',
url: '/api/values',
headers: headers
}).done(function (data) {
self.result(data);
}).fail(showError);
}
self.callToken = function () {
self.result('');
var loginData = {
grant_type: 'password',
username: self.loginEmail(),
password: self.loginPassword()
};
$.ajax({
type: 'POST',
url: '/Token',
data: loginData
}).done(function (data) {
self.user(data.userName);
// Cache the access token in session storage.
sessionStorage.setItem(tokenKey, data.access_token);
var tkn = sessionStorage.getItem(tokenKey);
$("#tknKey").val(tkn);
}).fail(showError);
}
}
var app = new ViewModel();
ko.applyBindings(app);
This seems to be part of what I am missing:
sessionStorage.setItem(tokenKey, data.access_token);
var tkn = sessionStorage.getItem(tokenKey);
$("#tknKey").val(tkn);
Would I need every view model to have the code that then goes to the sessionStorage, and get the token?
So, this:
var token = sessionStorage.getItem(tokenKey);
var headers = {};
if (token) {
headers.Authorization = 'Bearer ' + token;
}
$.ajax({
type: 'GET',
url: '/api/values',
headers: headers
}).done(function (data) {
self.result(data);
}).fail(showError);
}
It seems like a lot of code.. Is this the right way to go?
Ok, so what you could do is attach the bearer token to each of your HTTP requests. I assume you're using jQuery there? If that's the case you could leverage the beforeSend config param.
Extract a reusable method such as this:
function onBeforeSend(xhr, settings) {
var token = sessionStorage.getItem(tokenKey);
if (token) {
xhr.setRequestHeader('Authorization', 'Bearer ' + token );
}
}
And then simply attach that method to each of your $.ajax calls that require the token, like this:
$.ajax({
type: 'GET',
url: '/api/values',
headers: headers,
beforeSend: onBeforeSend
}).done(function (data) {
self.result(data);
}).fail(showError);
The onBeforeSend function obviously needs to be accessible by your ajax call (I'm not a knockout guy so I don't know if it has any constructs such as services, but if not, you could namespace it for example to avoid making it a global function, but your code organization is up to you).
This way you'll only have to add the beforeSend: onBeforeSend bit to each request that requires auth and it will avoid unnecessary code duplication.

JSON and other parameters in data property of AJAX PUT. ASP.net Web API

I want to send a JSON object and values from text boxes back to my controller, but I am having trouble. I can send just the JSON object successfully, but as soon as I add other parameters I get an error saying the requested resource does not support http method 'PUT'. I have tried commenting out the contentType and using Data: {viewModel: JSON.stringify(jsonData), userName: username}, without any success (I eventually will add more string parameters). Below is my ajax and controller signature. Thanks in advance.
$.ajax({
type: 'PUT',
contentType: 'application/json',
url: 'api/Label',
cache: false,
data: JSON.stringify(jsonData),
success: function (result) {
// TODO
},
error: function (HttpRequest, textStatus, err) {
var response = jQuery.parseJSON(HttpRequest.responseText);
$('#LabelInfo').show();
$('#LabelInfo').text('Error: ' + response.ModelState["viewModel.Pieces"][0]);
}
});
controller signature:
public HttpResponseMessage Put(Label viewModel, string
userName)

MVC4 model validation then submit JSON post to external URI using JQuery

I need to submit a simple form and validate the model. If the model is valid, I would like to serialize that model and send it via POST to an external (https) web service using custom headers. Finally I would handle the response that I get back from the request and display the appropriate message.
I am validating the model from the controller perfectly and serialize the object but can't seem to find a way to create a JSON post request to the external URI. Is there a way to do this using JQuery.ajax or $.post. Maybe I am missing a key ajax param to achieve this.
Thanks
So based on the clarification on the question this is what you can do:
Define the controller method that will validate the object
public ActionResult TestMethod() {
// do server-side validation
return Json(aValidObject);
}
You do an ajax post to your controller so you can validate your model then get back a json result.
$.ajax({
url: '#Url.Action("TestMethod")',
data: some_data,
type: "post",
success: function (result) {
// result is a valid json object
doExternalPost(result);
}
});
Add custom header and do the external post
function doExternalPost(o) {
$.ajax({
url: 'http://some_external_url',
data: o,
dataType: 'json',
beforeSend: function (xhr) {
xhr.setRequestHeader('custom_header', 'some_value');
},
success: function() {
// post is sucessful
},
error: function (xhr, errorType, exception) {
var errorMessage = exception || xhr.statusText || xhr.responseText;
alert('An error has occured: ' + errorMessage);
},
});
}
try this
var data = {jsonDataObjectHere};
var request = $.ajax({
url : 'externalUrl.com/something.whatever',
type : 'POST',
data : data // see above
});
request.success(function(response){
// the response is the stuff from the server
});
i'm sleepy so forgive typos
good luck
EDIT: for a bit of clarification, with MVC you really dont need to serialize the json object, mvc will accept it as it is.

Categories