I have created a bearer token using ASP.net Identity. In AngularJS I wrote this function to get authorized data.
$scope.GetAuthorizeData = function () {
$http({
method: 'GET',
url: "/api/Values",
headers: { 'authorization': 'bearer <myTokenId>' },
}).success(function (data) {
alert("Authorized :D");
$scope.values = data;
}).error(function () {
alert("Failed :(");
});
};
So I want to store this token into Browser cookies. If this token is present there , then take the token and get the data from IIS server Otherwise redirect to login page to login to get a new token.
Similarly, if user click onto log out button, it should remove the token from browser cookie.
How to do this ? It it possible ? Is it proper way to authenticate and authorize a user ? What to do if there are multiple users token ?
There is a $cookies service available in the AngularJS API using the
ngCookies module. It can be used like below:
function controller($cookies) {
//set cookie
$cookies.put('token', 'myBearerToken');
//get cookie
var token=$cookies.get('token');
//remove token
$cookies.remove('token');
}
controller.$inject=['$cookies'];
For your case it would be:
//inject $cookies into controller
$scope.GetAuthorizeData = function () {
$http({
method: 'GET',
url: "/api/Values",
headers: { 'authorization': 'bearer <myTokenId>' },
})
.success(function (data) {
$cookies.put('token', data);
}).error(function () {
alert("Failed :(");
});
};
You will also have to add the angular-cookies module code. And add it to your angular app: angular.module('myApp', ['ngCookies']);. Docs for Angular Cookies.
I would also like to suggest the usage of a Http interceptor which will set the bearer header for each request, rather than having to manually set it yourself for each request.
//Create a http interceptor factory
function accessTokenHttpInterceptor($cookies) {
return {
//For each request the interceptor will set the bearer token header.
request: function($config) {
//Fetch token from cookie
var token=$cookies.get['token'];
//set authorization header
$config.headers['Authorization'] = 'Bearer '+token;
return $config;
},
response: function(response) {
//if you get a token back in your response you can use
//the response interceptor to update the token in the
//stored in the cookie
if (response.config.headers.yourTokenProperty) {
//fetch token
var token=response.config.headers.yourTokenProperty;
//set token
$cookies.put('token', token);
}
return response;
}
};
}
accessTokenHttpInterceptor.$inject=['$cookies'];
//Register the http interceptor to angular config.
function httpInterceptorRegistry($httpProvider) {
$httpProvider.interceptors.push('accessTokenHttpInterceptor');
}
httpInterceptorRegistry.$inject=['$httpProvider'];
//Assign to module
angular
.module('myApp')
.config(httpInterceptorRegistry)
.factory('accessTokenHttpInterceptor', accessTokenHttpInterceptor)
Having the http interceptor in place you do not need to set the Authorization header for each request.
function service($http) {
this.fetchToken=function() {
//Authorization header will be set before sending request.
return $http
.get("/api/some/endpoint")
.success(function(data) {
console.log(data);
return data;
})
}
}
service.$inject=['$http']
As stated by Boris: there are other ways to solve this. You could also use localStorage to store the token. This can also be used with the http interceptor. Just change the implementation from cookies to localStorage.
function controller($window) {
//set token
$window.localStorage['jwt']="myToken";
//get token
var token=$window.localStorage['jwt'];
}
controller.$inject=['$window'];
I would advise against keeping the data in a cookie, for security purposes you should set the cookies to secure and HttpOnly (not accessible from javascript). If you're not using SSL, I would suggest moving to https.
I would pass the token from the auth endpoint in a json response:
{
tokenData: 'token'
}
You can save the token data in sessionStorage by using the $window service:
$window.sessionStorage.setItem('userInfo-token', 'tokenData');
It will be cleared once the user closes the page, and you can manually remove it by setting it to empty string:
$window.sessionStorage.setItem('userInfo-token', '');
Edit:
Interceptor implementation for catching data, adapted from cbass (not tested, you can inspect the objects for response/request to fiddle with the information):
//Create a http interceptor factory
function accessTokenHttpInterceptor($window) {
return {
//For each request the interceptor will set the bearer token header.
request: function($config) {
//Fetch token from cookie
var token=$window.sessionStorage.getItem('userInfo-token');
//set authorization header
$config.headers['Authorization'] = 'Bearer '+token;
return $config;
},
response: function(response) {
//if you get a token back in your response you can use
//the response interceptor to update the token in the
//stored in the cookie
if (response.config.url === 'api/token' && response.config.data.tokenData) {
//fetch token
var token=response.config.data.tokenData;
//set token
$window.sessionStorage.setItem('userInfo-token', token);
}
return response;
}
};
}
accessTokenHttpInterceptor.$inject=['$window'];
Related
I want to fetch googlesheet data. Through my code I am able to get the access token but now I don't know how can I fetch all the records in a googlesheet using that particular access token in javascript.
I have given the scope in manifest as spreadsheet.readonly.
I have my token in a particular variable and also googlesheeetId in another variable now what headers and what url do I need to paas so that I can get the googlesheet data.
Please help with some reference or links or sample code so that I can get a glimpse of what process do I need to follow to do this.
Here is the code
var gSheetId;
chrome.identity.getAuthToken({ 'interactive': true }, function (token) {
if (chrome.runtime.lastError) {
console.log(chrome.runtime.lastError);
return;
}
console.log(token);
//getting googlesheetId from user
gSheetId = prompt("Please provide your googlesheet Id");
if (!gSheetId) {
alert("Operation Cannot be Performed! Please refresh");
}
else {
//read googlesheetdata
var headers = {
'Authorization':'Bearer '+token
}
//here I need to read the googlesheet data using the token
chrome.debugger.onEvent.addListener(onEvent);
}
});
Thanks in advance!
Solution
Brought to you by #StayAtOrbit , owner of the oiginal question. (this is a community wiki answer)
Useful resources for this issue:
Google sheets API documentation for JavaScript
Sending access token to an API
Making authentificated requests with a token
var gSheetId;
chrome.identity.getAuthToken({ 'interactive': true }, function (token) {
if (chrome.runtime.lastError) {
console.log(chrome.runtime.lastError);
return;
}
console.log(token);
//getting googlesheetId from user
gSheetId = prompt("Please provide your googlesheet Id");
if (!gSheetId) {
alert("Operation Cannot be Performed! Please refresh");
}
else { //read googlesheetdata
var obj = {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Host': 'sheets.googleapis.com',
'Authorization': 'Bearer '+token
}
}
fetch('https://sheets.googleapis.com/v4/spreadsheets/<sheetID>/values/<range>', obj)
.then(function (res) {
return console.log(res.json());
}).then(function (resJson) {
return console.log(resJson);
})
//here I need to read the googlesheet data using the token
chrome.debugger.onEvent.addListener(onEvent);
}
});
I'm using the Fetch API to Login to my Webapp using Baisc Authentication. After a successful login the server returns a token as a json object. I am then using this token to make requests to other API Endpoints. Those endpoints just show a webpage if the request contains a valid token.
Everything works fine but nothing shows up in the browser after I make a successful call with the fetch API..
If I call the API endpoint in a REST Client it returns the html which seems to be fine. The problem seems to be that the browser should call the url instead of just fetch the html..
Here is my code. I am getting the "Success"-Alert - so everything seems to work fine. But I need the browser to show the result as a new page (some kind of a direct call of the url with the token in the header).
function login(event) {
event.preventDefault();
let username = document.getElementById("username").value;
let password = document.getElementById("password").value;
let url = URL + 'login';
let headers = new Headers();
headers.append('Authorization', 'Basic ' + btoa(username + ":" + password));
fetch(url, {method:'GET',
headers: headers,
})
.then(function(response)
{
if (response.ok) {
return response.json();
} else {
let error = document.getElementById("login-error");
error.innerHTML = "Username/Password incorrect.";
}
})
.then(function(json)
{
if (typeof(json) !== "undefined") {
startWebapp(json.token);
}
})
.catch(error => console.error('Error:', error));
}
function startWebapp(token) {
let url = URL + 'webapp/overview';
let headers = new Headers();
headers.append('Authorization', 'Bearer ' + token);
fetch(url, {method:'GET',
headers: headers,
})
.then(function(response) {
alert("Success!");
return response;
});
}
How can I achieve that the browser actually calls the url with the API token and opens it if the fetch is successful?
For anyone searching for a solution:
This is actually not possible with JavaScript nor the fetch API. For me the (easiest) solution is to save the token in a cookie. The server then searches for a token in the cookie and uses it for authentication/authorization. This works pretty well and I don't need to send the token on every request.
Hope that helps.
I have an issue at the moment with the google url shortener.
I have set up this service:
angular.module('widget.core').service('urlShortener', service);
function service($log, $q, $http) {
var gapiKey = '<MyApiKey>';
var gapiUrl = 'https://www.googleapis.com/urlshortener/v1/url';
return {
shorten: shorten
};
//////////////////////////////////////////////////
function shorten(url) {
console.log(url);
var data = {
method: 'POST',
url: gapiUrl + '?key=' + gapiKey,
headers: {
'Content-Type': 'application/json',
},
data: {
longUrl: url,
}
};
return $http(data).then(function (response) {
$log.debug(response);
return response.data;
}, function (response) {
$log.debug(response);
return response.data;
});
};
};
As far as I can tell, this should work. I have put in the correct API key and when I run this method I get this error:
{
error: {
code: 401,
message: 'Invalid credentials'
}
}
But, if I use postman and set it up exactly like this method:
Make it post
Add the content-type header and set it to application/json
set the url to https://www.googleapis.com/urlshortener/v1/url?key=myapikey
set the body to:
{
longUrl: 'myreallylogurl.com'
}
When I post this, it works with no issues.
I have checked my application on the google console and it is definitely set to unrestricted.
Has anyone come across this issue before? Does anyone know how to solve it?
I figured this out, it was nothing to do with the code above, but I thought I would answer my own question because someone else may run into the same issue.
In the project I have an httpInterceptor set up that adds the authetentication token to each request for talking to my API. This was what was causing the issue.
It so happened that I already defined a constant for my apiUrl, so I just updated the interceptor to check to make sure that the request url was my api before trying to append the token.
Like this:
angular.module('widget.core').factory('authInterceptor', factory);
function factory($q, $location, $localStorage, apiUrl) {
// The request function
var request = function (config) {
// If we are querying our API
if (config.url.indexOf(apiUrl) > -1) {
// Get our stored auth data
var authData = angular.fromJson($localStorage.get('authorizationData'));
// Set our headers to the request headers or a new object
config.headers = config.headers || {};
// If we have any auth data
if (authData && authData.authenticated) {
// Set our authorization header
config.headers.Authorization = 'Bearer ' + authData.token;
}
}
// Return our config
return config;
};
return {
request: request
};
};
I hope that helps someone else. Took me hours to figure it out :/
I'm trying to add the 'Authorization' header containing a token for future HTTP request. Retrieval of the token seems to be fine however when making a get request it fails with an Unauthorized error message. After checking the request headers Authorization header does not exist in the request block...
window.crUtil = /*window.crUtil ||*/ (function() {
// Angular Services
var $injector = angular.injector(['ng']);
var $http = $injector.get('$http');
// getting the CFF data
function get_data() {
getJWTAWS();
var url = '/AWS/getDATA/555';
console.log('AUTH header before call: ' + $http.defaults.headers.common.Authorization);
$http.get(url,httpHeader).then(function successCallback(response) {
var data = response.data;
var cff = initCff();
alert(data.itemId);
}, function errorCallback(response) {
initCff();
alert("Error while getting data ");
});
}
function getJWTAWS() {
var httpConfig = {
cache: true,
params: {}
};
$http.get('/AWS/token', httpConfig).then(
function(response) {
if (response.data.accessToken) {
// add jwt token to auth header for all requests made by the $http service
$http.defaults.headers.common.Authorization = response.data.tokenType + ' ' + response.data.accessToken;
}
},
function(error) {
alert('jwt token could not be retrieved.');
}
);
}
})();
var result = util.get_data();
console.log ('called search function ' + result);
Function getToken() returns a value but as I'm new on that topic I'm not quite sure if the way I added the token to the headers is proper.
Could you please advise on the proper way to include the headers in the request. I also tried to add it to the get request like
$http.get(URL,httpHeaders)...
but it also didn't work.
I'm not sure I understand your problem completely as you did not provide what you call
httpConfig
If you're struggling to declare the headers, try making the get request like this:
$http({
method: 'GET',
url: YOUR_URL,
headers: {
'Content-Type': 'application/json',
'Authorization': AUTH_STRING_HERE
}
}).then(function (response) { ... });
You can add any headers you like in the headers object there.
Try adding this in your config block and set the token in your rootscope
$httpProvider.interceptors.push({
request: function (config) {
config.headers.Authorization = $rootScope.token;
return config;
}
})
I am trying to pass my api authtoken via the header. I am new to angular js so i am not able to do that. My code:
$scope.init=function(authtoken,cityname){
$scope.authtoken=authtoken;
$scope.cityname=cityname;
$http({method: 'GET', url: '/api/v1/asas?city='+$scope.cityname+'&auth='+$scope.authtoken}).success(function(data) {
Right now I am passing the authtoken in the api url. But I want to pass the token via the header.
usually you pass auth token in headers. Here is how i did it for one of my apps
angular.module('app', []).run(function($http) {
$http.defaults.headers.common.Authorization = token;
});
this will add auth token to headers by default so that you wont have to include is every time you make a request. If you want to include it in every call then it will be something like this
$http({
method: 'GET',
url: '/api/v1/asas?city='+$scope.cityname,
headers:{
'Authorization': $scope.authtoken
}
}).success(function(data) {
//success response.
}).error(function(error){
//failed response.
});
You can configure on application run
youapp.run(function($http) {
$http.defaults.headers.common.Authorization = 'Basic YmVlcDpib29w'
});
or pass it throw each request
$http({
url:'url',
headers:{
Authorization : 'Basic YmVlcDpib29w'
}
})
Angular $Http reference