Web Api 2 subdomain Token authentication - angularjs

I am creating a site using AngularJS and the out-the-box WebApi2 token authentication template (Individual User Accounts). I am trying to get two sites to be logged in at the same time, one at www.domain.com and the other at sub.domain.com
Currently I use the following code in angular to authenticate the user:
$http({
method: 'POST',
url: '/Token',
data: serializedData,
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}).success(function (data, status, headers, config) {
$window.sessionStorage.token = data.access_token;
});
and append the authorization header for every request after:
app.factory('authInterceptor', function ($rootScope, $q, $window) {
return {
request: function (config) {
config.headers = config.headers || {};
if ($window.sessionStorage.token) {
$window.sessionStorage.loggedIn = true;
config.headers.Authorization = 'Bearer ' + $window.sessionStorage.token;
}
return config;
}
};
});
app.config(function ($httpProvider) {
$httpProvider.interceptors.push('authInterceptor');
});
The above code allows each site to login individually, however sessionstorage doesn't persist across other windows/tabs so it will not log the user in to the subdomain.
There are some comments in this blog post regarding this issue (half way down): http://blog.auth0.com/2014/01/07/angularjs-authentication-with-cookies-vs-token/
However it seems way too complicated to implement (and have the undesired effect of the user getting redirected). I was hoping for something as easy as setting a domain, just like with cookies:
app.UseCookieAuthentication(new CookieAuthenticationOptions()
{
CookieDomain = ".domain.com"
});
I'm starting to doubt whether I should be using token authentication over cookies in the current scenario...

This was explained in a follow up post: Local/session storage won't work across domains, use a marker cookie.
You can create a cookie for .domain.com from javascript to store the token. Cookies, local storage and session storage are the ways the browser has to store information:
... we are not using the cookie as an authentication mechanism, just as a
storage mechanism that happens to support storing information across
different domains.

Related

Authenticate and Authorise in Both MVC and Http AuthorizeAttribute

I get follow scenario which is working now:
MVC controller using System.Web.Mvc.AuthorizeAttribute to authenticate user is authenticated or not, it will be using cookie.
API controller using System.Web.Http.AuthorizeAttribute to authorise with bearer token.
I do also have angular http interceptor that verify and get bearer token for API purpose that can use among all angular $http request. But I am confusing how to achieve both after user has login?
This is current workflow
User click login, angular verify and store bears token in local storage.
After complete, manually trigger MVC controller so that it will get cookie for MVC authenticate.
This seem to me really double job, or I should focusing on using one AuthorizeAttribute?
You need you use Authorize key to give permission to those functions where authorization is needed. And those functions can only be accessed when authorization token is generated and passed with http request.
module.service('tokenservice', function ($http) {
this.get = function () {
var accesstoken = sessionStorage.getItem('accessToken');
var logged_in = localStorage.getItem('logged_in').toString().trim() === 'false' ? false : true;
var authHeaders = {};
if (accesstoken && logged_in) {
authHeaders.Authorization = 'Bearer ' + accesstoken;
}
return authHeaders;
};
});
module.controller('yourControllerName', function ( $http, tokenservice) {
$http({
method: "POST",
url: '/Controller/MyFucntion',
headers: tokenservice.get(),
});
});
This will help you to get generated token in user login. After that You need to work with your controller
[Authorize]
public JsonResult MyFucntion()
{
//Your logic and calculation
//return
}
Hope that will help

AngularJS 1.3 to 1.5 transformRequest broke, solution for my specific situation?

Long story short. I am really not an AngularJS guru. Our site upgraded from 1.3 to 1.5. This one thing is breaking.
We used to inject an HTTP header via transformRequest in a factory named 'api':
.factory('api', function($resource) {
function add_auth_header(data, headersGetter) {
var headers = headersGetter();
headers['Authorization'] = ('Basic ' + btoa(data.username +
':' + data.password));
}
// defining the endpoints.
return {
auth: $resource('/api/v1/auth/', {}, {
login: {method: 'POST', transformRequest: add_auth_header},
logout: {method: 'DELETE'},
}),
Later on in the same file, this is called like so:
.service('auth', function($cookies, $rootScope, api) {
this.user = null;
this.login = function(credentials) {
var log = api.auth.login(credentials);
log.$promise.then(function(data){
// on good username and password
this.user = data;
});
As you can see, it calls api.auth.login with the credentials. I have verified that the transform request is being called, the headers are being fetched properly by headersGetter(), and that hanging the headers[] object no longer changes it like it used to in 1.3. Fiddler verifies that the request no longer has an Authorization header in it like it did in 1.3, and the Django server that gets the request also agrees.
I've read in a few places that the transformRequest functionality 'broke' in 1.4, but those posts have always been in the context of making an $http request, not providing an api service through a factory, and haven't made much sense to an AngularJS newb like me. I have no idea where I would start changing how Authorization is injected.
Can anyone point me the right way?
If anyone else is still facing this, the change was under breaking changes in the changelog for 1.4.
I feel the fix speaks for itself. Note that the function add_auth_header is not invoked but rather is passed.
.factory('api', function($resource) {
function add_auth_header(data) {
// as per HTTP authentication spec [1], credentials must be
// encoded in base64. Lets use window.btoa [2]
return 'Basic ' + btoa(data.data.username + ':' + data.data.password);
}
// defining the endpoints.
return {
auth: $resource('/api/v1/auth/', {}, {
login: {method: 'POST', headers: { 'Authorization': add_auth_header }},
logout: {method: 'DELETE'},
}),

How to Upload file to S3 using Angular/Node ng-file-upload

Unable to get file upload to S3 working. That being said, I know the problem is on my end.
At the moment I can upload a file to S3 using: https://s3.amazonaws.com/doc/s3-example-code/post/post_sample.html
Now if I copy and paste the form to my app, and just Post the form, it works.
Next step I'm doing is to move the hardcoded values into the Angular controller to attempt uploading the file through there before implementing server side creation of policy and signature, although it doesn't seem to work.
Error I'm getting is the Authorization: Bearer issue.
After reading it, I've tried setting Authorization to undefined, and that still isn't working and I'm at a loss.
Any help would be appreciated.
Code below:
var mypolicy = "HardcodedPolicy;
var mysignature = "HardcodedSignature";
var s3url = "https://myBucket.s3.amazonaws.com/";
Upload.upload({
url: s3url,
method: 'POST',
headers: {
'Authorization': undefined
},
data: {
key: 'testfile.txt',
acl: 'public-read',
"Content-Type": 'text/plain',
AWSAccessKeyId: 'XXX',
policy: mypolicy,
signature: mysignature,
file: uploadfile
}
}).error(function(err) {
console.log("err: ", err);
})
I have spent ages trying to find a solution to this and finally got it to work. I hope this solution helps others. In my case the problem was caused by our app using jwt tokens to authenticate users whenever they make calls to our api. The code which added the token was in an angular factory like this:
App.factory('authInterceptor', ['$rootScope', '$q', '$cookieStore', '$location','$window',
function ($rootScope, $q, $cookieStore, $location, $window) {
return {
// Add authorization token to headers
request: function (config) {
config.headers = config.headers || {};
if ($cookieStore.get('token')) {
config.headers.Authorization = 'Bearer ' + $cookieStore.get('token');
}
return config;
}
}]);
The solution we used was to amend the conditon statement so the authorization header was only added if required. We changed the 'if' statement to
if ($cookieStore.get('token') && config.url != "https://yourbucket.s3.amazonaws.com/")
Hope this helps someone else.

Oauth 2.0 token based authentication AngularJS (Beginner)

I have gone through multiple documents , Including ng-cordova and oauth-ng but I still can't find any resource which deals with a basic token based authentication in angularjs/Ionic
I am having trouble about how to make this curl call in angularjs
curl -X POST -vu sampleapp:appkey http://sampleurl/oauth/token -H "Accept: application/json" -d "password=pwd&username=sampleuname&grant_type=password&scope=read%20write&client_secret=appkey&client_id=sampleapp"
I am doing this and it's giving me a 401 error. However a curl call works just fine.
$scope.login = function() {
$http({
method: "post",
url: "http://sampleurl/oauth/token",
data: "client_id=" + clientId + "&client_secret=" + clientSecret + "password=pwd&username=sampleuser&grant_type=password" + "&scope=read%20write",
withCredentials: true,
headers: {
'Content-Type': 'application/json; charset=utf-8'
}
})
.success(function(data) {
accessToken = data.access_token;
$location.path("/secure");
})
.error(function(data, status) {
alert("ERROR: " + data);
});
}
I realise that once I get the token , I have to do something similar to
$http.get('http://apiurl/api/v1/users',
{headers: { Authorization: ' Token api_key=xxxxxxxxxxxxxxxxxxxxxxxxxxxx'}})
.then(function(response) {
service.currentUser = response.data.user;
console.log(service.currentUser);
});
But so far I've been unable to figure out a way to make a call to the server and save the access token in my localstorage. All resources on the internet are primarily catered towards 3rd party logins (google,facebook,twitter etc ) or JWT tokens.
I am fairly new at this but I've found out that I need to worry about password grant flow where the user gives his/her credentials to the consumer and the consumer exchanges these for an access and refresh token. Still I don't believe I am making the right call.
UPDATE : As #DanielCottone in the answer below has mentioned , oauth-ng seemed like a good solution but their documentation from what I've seen confuses me as I want to send the username and password to the url too and the sample is not implementing it or has a provision for it from what I can tell?
This is what they have in their documentation :
<oauth
site="http://oauth-ng-server.herokuapp.com"
client-id="d6d2b510d18471d2e22aa202216e86c42beac80f9a6ac2da505dcb79c7b2fd99"
redirect-uri="http://localhost:9000"
profile-uri="http://oauth-ng-server.herokuapp.com/api/v1/me"
scope="public">
</oauth>
Again , this is a first time I'm trying integration of any kind and it makes sense for me to think that the call will have credentials sent with it? How do I send it then ?
The best way to solve this is by storing the token in localStorage after authentication, and then using an interceptor to inject the token into your request headers:
$http authentication promise (you need to inject $localStorage)
.success(function(data) {
$localStorage.accessToken = data.access_token;
$location.path("/secure");
})
Authentication interceptor
.factory('AuthInterceptor', function ($q, $localStorage, $rootScope) {
return {
request: function (config) {
if ($localStorage.access_token) {
config.headers['Authorization'] = 'Token api_key=' + $localStorage.token;
}
return config;
},
responseError: function (response) {
if (response.status === 401 || response.status === 403) {
delete $localStorage.access_token;
// Do some kind of redirect to login page here...
}
return $q.reject(response);
}
};
});
To logout, you would just delete the token from localStorage, and all further requests would be redirected to the login page if you get a 401 or 403 from the API.

AngularJS interceptor not putting JWT Bearer in every request of node.js app

I put a JWT authentication system in a node app.
I used an interceptor to put the Bearer in every request. It works well if I call a restricted route within Angular or if I curl and specify the token in the header.
But if I enter the restricted route directly in my address bar, it doesn't work. There is no Bearer in the header, it doesn't go through the interceptor.
Here is my interceptor (client-side):
angular.module('myApp).factory('authInterceptor', function ($rootScope, $q, $window) {
return {
request: function (config) {
config.headers = config.headers || {};
if ($window.localStorage.token) {
config.headers.Authorization = 'Bearer ' + $window.localStorage.token;
}
return config;
},
responseError: function (rejection) {
if (rejection.status === 401) {
// handle the case where the user is not authenticated
}
return $q.reject(rejection);
}
};
});
angular.module('myApp').config(function ($httpProvider) {
$httpProvider.interceptors.push('authInterceptor');
});
Here is my restricted route (server-side):
router.get('/restricted', expressJwt({secret: 'SecretStory'}), function(req, res) {
res.json({
name: 'You are allowed here !!'
});
})
How to make the bearer to be added to my request header on every request, even in typing the restricted route directly into the address bar?
When you enter a URL directly in the address bar you are circumventing your Angular code and, as you've discovered, the interceptor will not run.
You could try detecting when the URL in the address bar changes and try to work around the problem, but I would recommend against this.
Instead, I would approach this problem server-side by detecting a GET /restricted request with an Accept header of text/html (anything that is not application/json really). Then respond with HTML that includes your Angular code and request /restricted again using application/json when the page loads. This would be a good way to distinguish between explicit URL navigation and Angular requests and offers better hypermedia support to your API.

Resources