Following the example for https://github.com/auth0/socketio-jwt , I couldn't get the authentication failure to fire.
How are you supposed to handle and configure authentication errors using this library? I see in the source code that it is supposed to throw an UnauthorizedError but I just can't seem to trigger it.
Server side
io
.on('connection', socketioJwt.authorize({
secret: 'test',
timeout: 7000
}))
.on('authenticated', (socket) => {
console.log('connected user: ' + socket.decoded_token.name);
});
Client side
socket.on('connect', function () {
socket.emit('authenticate', {token: 'badtoken'}); //send the jwt
});
socket.on("error", function(error) {
// this never fires
if (error.type == "UnauthorizedError" || error.code == "invalid_token") {
alert("User's token has expired");
}
});
Do I need to add an .on('error, function(error)) on the server code as well?
Looking at the source code for jwt, they are actually emitting "unauthorized", not "error". Change to
socket.on("unauthorized", function(error) {
// this should now fire
if (error.data.type == "UnauthorizedError" || error.data.code == "invalid_token") {
alert("User's token has expired");
}
});
This bug in the doc and examples was also reported here.
Related
This is my first webRTC project so I'm very inexperienced in tracing these sorts of errors. Especially since I'm using this NPM package, I don't know exactly what to do with this error message. If you follow that link, I've just copy/pasted the "usage" demo code but replaced some of it with sockets using Laravel echo to transfer the peer-to-peer connection data. In the "usage" demo, they generate an "offer" object and have you paste it into the other peers form. Then that client generates an "answer" object and when you paste it into the form on the initiating client, the connection is made. If I do it that way, everything works fine. But I'm trying to establish an auto-connection when all the clients are ready. Here is my code:
var Peer = require("simple-peer");
window.p = new Peer({
initiator: location.hash === "#1",
trickle: false
});
p.on("error", err => console.log("error", err));
p.on("signal", data => {
if (location.hash === "#1") {
$.ajax({
url: "/autoCon",
type: "get",
data: {
connectionData: JSON.stringify(data)
},
success: function() {
console.log("sent: " + JSON.stringify(data));
}
});
}
});
p.on("connect", () => {
console.log("CONNECT");
});
And then on the blade file, I'm listening with Echo like this:
Echo.channel('myChannel')
.listen('MyEvent', (e) => {
p.signal(e.connectionData)
});
And now for the error:
Failed to execute 'setRemoteDescription' on 'RTCPeerConnection': Failed to set remote offer sdp: Failed to apply the description for 0: Failed to setup RTCP mux.
If I console log p.signal(e.connectionData), it shows "undefined", which is strange because it's generating the "answer" object and displaying to the page in text. So what I've tried to do is ajax send the initial "offer" object to the second peer, then take its "answer" object and signal for the initiating peer to connect when the data is received by socket. But it's giving me that error. Can anyone help?
I ended up figuring this out. This is my final code. It might be messy but it took me like 6 hours into the night and it made my brain hurt XD . If anyone can offer some advice on how to clean it up, I'll gladly take it but this works as is.
in app.js:
p.on("signal", data => {
//document.querySelector("#outgoing").textContent = JSON.stringify(data);
$.ajax({
url: "/autoCon",
type: "get",
data: {
conData: JSON.stringify(data)
}
});
});
And in my blade file using Echo:
var signalData = []
Echo.channel('myChannel')
.listen('MyEvent', (e) => {
signalData.push(e.conData)
if(e.conData.includes('offer') && location.hash !== '#1'){
console.log('received offer')
p.signal(JSON.parse(e.conData))
} else {
if(e.conData.includes('answer') && location.hash === '#1' ){
console.log('received answer')
p.signal(JSON.parse(signalData[1]))
}
}
});
I am implementing JWT into my Vue application for authorization and I refresh my tokens once they are used.
I have used axios interceptors so I can intercept every request to my API backend and this seems to work on login etc... but once I refresh the page the request is made as normal using the last token.
The problem is the axios interceptors don't seem to work at this point, so once the token has been used I can't update it with the new one.
Here's how I'm setting my interceptors:-
window.axios.interceptors.request.use(function (config) {
console.log("Sent request!");
return config;
}, function (error) {
console.log("Failed sending request!");
return Promise.reject(error);
});
window.axios.interceptors.response.use(function (response) {
console.log("Got headers:", response.headers);
if (response.headers.hasOwnProperty('authorization')) {
console.log("Got authorization:", response.headers.authorization);
Store.auth.setToken(response.headers.authorization);
}
return response;
}, function(err){
console.log("Got error", err);
});
I don't get any of the console.log's on page load.
I am setting my interceptors in the root app's beforeMount method. I've tried moving them to beforeCreate and I still get the same issue.
try this
window.axios.interceptors.request.use(function (config) {
console.log("Sent request!");
if(localStorage.getItem('id_token')!=undefined){
config.headers['Authorization'] = 'Bearer '+localStorage.getItem('id_token')
}
return config;} , function (error) {
console.log("Failed sending request!");
return Promise.reject(error); });
I am using React, React-Router and Superagent. I need authorization feature in my web application. Now, if the token is expired, I need the page redirect to login page.
I have put the ajax call functionality in a separated module and the token will be send on each request's header. In one of my component, I need fetch some data via ajax call, like below.
componentDidMount: function() {
api.getOne(this.props.params.id, function(err, data) {
if (err) {
this.setErrorMessage('System Error!');
} else if (this.isMounted()) {
this.setState({
user: data
});
}
}.bind(this));
},
If I got 401 (Unauthorized) error, maybe caused by token expired or no enough privilege, the page should be redirected to login page. Right now, in my api module, I have to use window.loication="#/login" I don't think this is a good idea.
var endCallback = function(cb, err, res) {
if (err && err.status == 401) {
return window.location('#/login');
}
if (res) {
cb(err, res.body);
} else {
cb(err);
}
};
get: function(cb) {
request
.get(BASE_URL + resources)
.end(endCallback.bind(null, cb));
},
But, I can't easily, call the react-router method in my api module. Is there an elegant way to implemented this easy feature? I don't want to add an error callback in every react components which need authorized.
I would try something like this:
Use the component's context to manipulate the router (this.context.router.transitionTo()).
Pass this method to the API callout as a param.
// component.js
,contextTypes: {
router: React.PropTypes.func
},
componentDidMount: function() {
api.getOne(this.props.params.id, this.context.router, function(err, data) {
if (err) {
this.setErrorMessage('System Error!');
} else if (this.isMounted()) {
this.setState({
user: data
});
}
}.bind(this));
},
// api.js
var endCallback = function(cb, router, err, res) {
if (err && err.status == 401) {
return router.transitionTo('login');
}
if (res) {
cb(err, res.body);
} else {
cb(err);
}
};
get: function(cb, router) {
request
.get(BASE_URL + resources)
.end(endCallback.bind(null, cb, router));
},
I know you didn't want a callback on each authenticated component, but I don't think there's any special react-router shortcuts to transition outside of the router.
The only other thing I could think of would be to spin up a brand new router on the error and manually send it to the login route. But I don't think that would necessarily work since it's outside of the initial render method.
I am extending Ember Simple Auth's base authentication class to allow authentication with Google. So far, it works on Safari 8 and Chrome 41 (both on Yosemite) with no errors. However, on Firefox 35, it throws an Error that does not occur on the other browsers. Here is my Google authenticator class:
App.GoogleAuthenticator = SimpleAuth.Authenticators.Base.extend({
// constants for Google API
GAPI_CLIENT_ID: 'the client id',
GAPI_SCOPE: ['email'],
GAPI_TOKEN_VERIFICATION_ENDPOINT: 'https://www.googleapis.com/oauth2/v2/tokeninfo',
// method for scheduleing a single token refresh
// time in milliseconds
scheduleSingleTokenRefresh: function(time) {
var self = this;
return new Ember.RSVP.Promise(function(resolve, reject) {
Ember.run.later(self, function() {
gapi.auth.authorize({
client_id: self.GAPI_CLIENT_ID,
scope: self.GAPI_SCOPE,
immediate: true
}, function(data) {
if (data && !data.error) {
resolve(data);
} else {
reject((data || {}).error);
}
});
}, time);
});
},
// WIP: recursive method that reschedules another token refresh after the previous scheduled one was fulfilled
// usage: scheduleTokenRefreshes(time until token should refresh for the first time, time between subsequent refreshes)
// usage: scheduleTokenRefreshes(time between refreshes)
scheduleTokenRefreshes: function(time1, time2) {
var self = this;
// if there is a time2, schedule a single refresh, wait for it to be fulfilled, then call myself to schedule again
if (!Ember.isEmpty(time2)) {
self.scheduleSingleTokenRefresh(time1)
.then(function() {
self.scheduleTokenRefreshes(time2);
});
// if there isn't a time2, simply schedule a single refresh, then call myself to schedule again
} else {
self.scheduleSingleTokenRefresh(time1)
.then(function() {
self.scheduleTokenRefreshes(time1);
});
}
},
// method that restores the session on reload
restore: function(data) {
var self = this;
return new Ember.RSVP.Promise(function(resolve, reject) {
console.log(data);
if (Ember.isEmpty(data.access_token)) {
reject();
return;
}
// schedule a refresh 15 minutes before it expires or immediately if it expires in < 15
var timeNow = Math.floor(Date.now() / 1000);
var expiresAt = +data.expires_at;
var timeDifference = expiresAt - timeNow;
var schedulingDelay = Math.floor(timeDifference - 15 * 60);
schedulingDelay = schedulingDelay < 0 ? 0 : schedulingDelay;
self.scheduleTokenRefreshes(schedulingDelay * 1000, 45 * 60);
resolve(data);
});
},
// method that authenticates
authenticate: function() {
var self = this;
return new Ember.RSVP.Promise(function(resolve, reject) {
gapi.auth.authorize({
client_id: self.GAPI_CLIENT_ID,
scope: self.GAPI_SCOPE
}, function(data) {
if (data && !data.error) {
// schedule a refresh in 45 minutes
var schedulingDelay = 45 * 60;
self.scheduleTokenRefreshes(schedulingDelay * 1000);
resolve(data);
} else {
reject((data || {}).error);
}
});
});
},
// method that logs the user out and revokes the token
invalidate: function(data) {
var self = this;
return new Ember.RSVP.Promise(function(resolve, reject) {
// send a GET request to revoke the token
Ember.$.ajax({
type: 'GET',
url: 'https://accounts.google.com/o/oauth2/revoke?token=' + self.get('session.access_token'),
contentType: 'application/json',
dataType: 'jsonp'
})
.done(function(successData) {
resolve(successData);
})
.fail(function(error) {
reject(error);
});
});
}
});
When the popup window closes after a successful login on Google's end, this error appears on Firefox's console:
Error: Assertion Failed: Error: Permission denied to access property 'toJSON' ember.js:13749
"__exports__.default<.persist#http://127.0.0.1/~jonchan/test/bower_components/ember-simple-auth/simple-auth.js:1524:1
__exports__.default<.updateStore#http://127.0.0.1/~jonchan/test/bower_components/ember-simple-auth/simple-auth.js:1195:11
__exports__.default<.setup#http://127.0.0.1/~jonchan/test/bower_components/ember-simple-auth/simple-auth.js:1149:9
__exports__.default<.authenticate/</<#http://127.0.0.1/~jonchan/test/bower_components/ember-simple-auth/simple-auth.js:1066:13
tryCatch#http://127.0.0.1/~jonchan/test/bower_components/ember/ember.js:47982:16
invokeCallback#http://127.0.0.1/~jonchan/test/bower_components/ember/ember.js:47994:17
publish#http://127.0.0.1/~jonchan/test/bower_components/ember/ember.js:47965:11
#http://127.0.0.1/~jonchan/test/bower_components/ember/ember.js:29462:9
Queue.prototype.invoke#http://127.0.0.1/~jonchan/test/bower_components/ember/ember.js:848:11
Queue.prototype.flush#http://127.0.0.1/~jonchan/test/bower_components/ember/ember.js:913:13
DeferredActionQueues.prototype.flush#http://127.0.0.1/~jonchan/test/bower_components/ember/ember.js:718:13
Backburner.prototype.end#http://127.0.0.1/~jonchan/test/bower_components/ember/ember.js:143:11
createAutorun/backburner._autorun<#http://127.0.0.1/~jonchan/test/bower_components/ember/ember.js:546:9
" ember.js:29488
Here is the version information:
DEBUG: Ember : 1.9.1
DEBUG: Ember Data : 1.0.0-beta.14.1
DEBUG: Handlebars : 2.0.0
DEBUG: jQuery : 2.1.3
DEBUG: Ember Simple Auth : 0.7.2
The most confounding thing is that this only appears on Firefox. Is it a bug in Ember Simple Auth or Ember? How do I fix it?
I do not know about only Firefox throwing an error (I've had a similar error with Chrome 40), but there is a bug in ember-simple-auth 0.7.2 with Ember 1.9 that prohibits sending an actual error response in the authenticate method in the authenticator.
If you return reject() in the rejection function of authenticate it will not throw an additional error. This will however not propagate the errorstatus or message, so I consider this a bug.
A work-around was proposed on github about this issue by setting Ember.onerror=Ember.K temporarily so additional errors will not be propagated, although it will propagate the original authenticate rejection with the error-status.
The issue in the github repo only mentions problems with testing this, but I've had this problem in normal code.
see: https://github.com/simplabs/ember-simple-auth/issues/407
Turns out the error was on the resolve part of the authenticate method. Here is what fixed it:
App.GoogleAuthenticator = SimpleAuth.Authenticators.Base.extend({
authenticate: function() {
return new Ember.RSVP.Promise(function(resolve, reject) {
gapi.auth.authorize({
client_id: 'the client id',
scope: ['the scopes'],
}, function(data) {
if (data && !data.error) {
resolve({
access_token: data.access_token // !! passing the entire 'data' object caused the error somehow
});
} else {
reject((data || {}).error);
}
});
});
},
// ...
});
I'm still not quite sure why this caused the error. Perhaps the Google API's response (in its entirety) is somehow incompatible with Ember Simple Auth.
I am developing a mobile application using PhoneGap, and I have to access some services from another project.
I am using jquery-2.0.0.js and jquery-mobile-1.3.2.js.
$.ajax({
url: 'http://localhost:62465/api/account?email=johndoe#yahoo.com',
dataType: 'json',
success: function (data) {
alert(data.Name);
},
error: function (xhr, type) {
alert("Failed to load data");
alert(xhr + " " + type);
}
});
This ajax call fails everytime. In the config.xml I have the following line: <access origin="*" />
Where I might be going wrong!
The problem is that your phonegap application is requesting a local file from something that isn't a webserver. The local file is delivered with NO HTTP HEADERS - that means no "200 OK" header and no "404 Not Found" errors. So, the status code is assumed to be 0.
Straight javascript XHR will need to ignore status and perform your action on readystate == 4 (finished and ready). Like this:
var myrequest = new XMLHttpRequest();
myrequest.open('GET','localfile.html');
myrequest.onreadystatechange = function(){
if(myrequest.readyState == 4) {
var result = myrequest.responseText;
}
}
myrequest.send();
In MooTools, it's a relatively straightforward task of implementing an altered status test in the Request class - altering the return code test to also accept 0 for true. Like this:
Request.implement({
isSuccess: function(){
var status = this.status;
return ((status >= 200 && status < 300) || status === 0);
}
});
jQuery.... I have some things I'd like to say about jQuery - but I'll hold my tongue because this seems like a classy place.
To prepare jQuery for status == 0, you need to use the always event instead of the success event, you can test the status code there.
$.ajax({
url: '/echo/html/',
type: 'PUT',
data: "email=a#b.com"
}).always(function(data, textStatus, jqXHR){
switch(textStatus) {
case 200:
case 0:
alert('Success.');
break;
case 404:
alert('oops');
break;
}
});
Ajax in Cordova/Phonegap - Yay!
url of your query is localhost, thant means- the same device (android emulator or physical). I'm sure that this is your problem. You should use IP (or domain) of your api json server, maybe 192.168.1.1 (depending on your network configuration)
Are you using a physical device or an emulator ? iOS ? Android ?
I might be wrong, but if you're running your app on a mobile device you can't access to your localhost.
I solved the problem with the "GET" call, but now I am trying to make a "PUT" call and it's the same problem, always fails.
$.ajax({
url: '/echo/html/',
type: 'PUT',
data: "email=a#b.com",
success: function(data) {
alert('Success.');
}
});
If the url: 'http://localhost:62465/api/account?email=johndoe#yahoo.com' is not reachable from your mobile, there's a very useful trick to use.
With www.ngrok.com, you can assign an internet domain to your locally unreachable port.
Just signup, get an access token, and then you can use:
ngrok -authtoken myauthtoken -subdomain=mysubdomainname 62465
And then you can access your computer with the url http://mysubdomainname.ngrok.com/api/account?email=johndoe#yahoo.com
(For people with similiar problems)
Use ajax error to know what is wrong:
error: function(jqXHR, exception){
var msg = '';
if (jqXHR.status === 0) {
msg = 'Not connect.\n Verify Network.';
} else if (jqXHR.status == 404) {
msg = 'Requested page not found. [404]';
} else if (jqXHR.status == 500) {
msg = 'Internal Server Error [500].';
} else if (exception === 'parsererror') {
msg = 'Requested JSON parse failed.';
} else if (exception === 'timeout') {
msg = 'Time out error.';
} else if (exception === 'abort') {
msg = 'Ajax request aborted.';
} else {
msg = 'Uncaught Error.\n' + jqXHR.responseText;
}
console.log(msg);
}