Trying to add authorization to my real-time app, I get this message in chrome console:
socket.io-parser decoded 4{"message":"No Authorization header was found","code":"credentials_required", "type":"UnauthorizedError"}
Here is my code (I use angular-fullstack):
socket.service.js (client side)
'use strict';
angular.module('smthing')
.factory('socket', function(socketFactory, Auth) {
var ioSocket = io(null, {
//Auth.getToken() returns $cookieStore.get('token') from angular auth.service.js
'query': 'token=' + Auth.getToken()
});
...
socketio.js (server side)
socketio.use(require('socketio-jwt').authorize({
secret: 'smthing',
handshake: true
}));
socketio.on('connection', function (socket) {
console.log('smthing');
...
"smthing" never prints. If I remove the authorization part, everything works correctly. I thought it was pretty straight forward... Any help would be great !
I was able to resolve this in my own environment. I use this snippet, though I had issues until resolving the root issue.
io.set('authorization', socketioJwt.authorize({
secret: jwtSecret,
handshake: true
}));
The root issue was that the token required for socketio-jwt was not being added to the request query. If you inspect socketio-jwt/lib/index.js, you'll see some code like:
//get the token from query string
if (req._query && req._query.token) {
token = req._query.token;
}
else if (req.query && req.query.token) {
token = req.query.token;
}
This means that you should be able to log the value for query and _query here, and see your token.
If you cannot, you must be sure on in your socket.io client that you are setting the token to the query. The typical way for this is to add it to the connectParams.
In the iOS/Swift client, this looks like this:
self.socket = [[SocketIOClient alloc] initWithSocketURL:#"localhost:8091"
options:#{
#"connectParams" : #{#"token" : <my_token>}
}];
Actually the right syntax:
var ioSocket = io(null, {
query: {
token: Auth.getToken()
}
});
Related
Problem
I was trying to use 'aws-amplify' GET API request with query parameters on the client side, but it turned out to be Request failed with status code 403, and the response showed:
"message":"The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.
Note: React.js as front-end, Javascript as back-end.
My code
Front-end
function getData() {
const apiName = 'MyApiName';
const path = '/path';
const content = {
body:{
data:'myData',
},
};
return API.get(apiName, path, content);
}
Back-end
try {
const result = await dynamoDbLib.call("query", params);
} catch (e) {
return failure({ status: false });
}
What I did to debug
The GET lambda function works fine in Amazon Console (Tested)
If I change the backend lambda function so that the frontend request can be made without parameters, i.e. return API.get(apiName, path), then no error shows up.
My question
How can I make this GET request with query parameters works?
I changed GET to POST (return API.post()), everything works fine now.
If anyone can provide a more detailed explanation, it would be very helpful.
I am trying to make an HTTP request like this:
login(username, password) {
let body = {
userid: username,
password: password
}
let options = {
headers: new HttpHeaders().set('Content-Type', 'application/x-www-form-urlencoded'),
withCredentials: true
};
let request = this.http.post(this.baseUrl, body, options);
request.subscribe();
}
which is returning a 500 internal server error. However, if I modify the body variable to look like this:
login(username, password) {
let body = 'userid=' + username + '&password=' + password;
let options = {
headers: new HttpHeaders().set('Content-Type', 'application/x-www-form-urlencoded'),
withCredentials: true
};
let request = this.http.post(this.baseUrl, body, options);
request.subscribe();
}
it works fine. I have seen the first version used in the documentation, but for some reason it doesn't work this way for me. I'm wondering:
A) Are these statements supposed to be equivalent? Is there a syntax issue? -or-
B) Is there a problem on the backend? In our server log, we're getting something like 'parameter #userIdentifier is expected but not supplied.'
I have to go with the one that works, but I'd like to use the syntax of the first statement if possible. Thanks!
Without more information on the backend or on the specific 500 error message you are receiving, the only suggestion I have is to verify that your back-end schema matches the front-end model. Judging by the limited error message provided, it looks as though you may have mislabeled userid as userIdentifier in the backend.
I'm doing the tutorial for IBM Watson Speech-to-text. In the section "Using the WebSocket interface", subsection "Opening a connection and passing credentials", I copied the following code:
var token = watsonToken;
console.log(token); // token looks good
var wsURI = 'wss://stream.watsonplatform.net/speech-to-text/api/v1/recognize?watson-token=' +
token + '&model=es-ES_BroadbandModel';
var websocket = new WebSocket(wsURI);
websocket.onopen = function(evt) { onOpen(evt) };
websocket.onclose = function(evt) { onClose(evt) };
websocket.onmessage = function(evt) { onMessage(evt) };
websocket.onerror = function(evt) { onError(evt) };
I'm using Angular so I made a value for the token:
app.value('watsonToken', 'Ln%2FV...');
I get back an error message:
WebSocket connection to 'wss://stream.watsonplatform.net/speech-to-text/api/v1/recognize?watson-toke...&model=es-ES_BroadbandModel' failed: HTTP Authentication failed; no valid credentials available
I tried hardcoding the token:
var wsURI = 'wss://stream.watsonplatform.net/speech-to-text/api/v1/recognize?watson-token=Ln%2FV2...&model=es-ES_BroadbandModel';
Same error message.
IBM's documentation on tokens says that an expired or invalid token will return a 401 error, which I didn't get, so I presume that my token is neither expired nor invalid. Any suggestions?
I think you can see the Official Example from IBM Developers here.
The error is because the authentication does not work fine before you send the request to recognize, try to follow the same step inside this repository, like:
const QUERY_PARAMS_ALLOWED = ['model', 'X-Watson-Learning-Opt-Out', 'watson-token', 'customization_id'];
/**
* pipe()-able Node.js Readable/Writeable stream - accepts binary audio and emits text in it's `data` events.
* Also emits `results` events with interim results and other data.
* Uses WebSockets under the hood. For audio with no recognizable speech, no `data` events are emitted.
* #param {Object} options
* #constructor
*/
function RecognizeStream(options) {
Duplex.call(this, options);
this.options = options;
this.listening = false;
this.initialized = false;
}
util.inherits(RecognizeStream, Duplex);
RecognizeStream.prototype.initialize = function() {
const options = this.options;
if (options.token && !options['watson-token']) {
options['watson-token'] = options.token;
}
if (options.content_type && !options['content-type']) {
options['content-type'] = options.content_type;
}
if (options['X-WDC-PL-OPT-OUT'] && !options['X-Watson-Learning-Opt-Out']) {
options['X-Watson-Learning-Opt-Out'] = options['X-WDC-PL-OPT-OUT'];
}
const queryParams = extend({ model: 'en-US_BroadbandModel' }, pick(options, QUERY_PARAMS_ALLOWED));
const queryString = Object.keys(queryParams)
.map(function(key) {
return key + '=' + (key === 'watson-token' ? queryParams[key] : encodeURIComponent(queryParams[key])); // our server chokes if the token is correctly url-encoded
})
.join('&');
const url = (options.url || 'wss://stream.watsonplatform.net/speech-to-text/api').replace(/^http/, 'ws') + '/v1/recognize?' + queryString;
const openingMessage = extend(
{
action: 'start',
'content-type': 'audio/wav',
continuous: true,
interim_results: true,
word_confidence: true,
timestamps: true,
max_alternatives: 3,
inactivity_timeout: 600
},
pick(options, OPENING_MESSAGE_PARAMS_ALLOWED)
);
This code is from IBM Developers and for my project I'm using and works perfectly.
You can see in the code line #53, set the listening to true, otherwise it will eventually timeout and close automatically with inactivity_timeout applies when you're sending audio with no speech in it, not when you aren't sending any data at all.
Have another example, see this example from IBM Watson - Watson Developer Cloud using Javascript for Speech to Text.
Elementary, my dear Watson! There are three or four things to pay attention to with IBM Watson tokens.
First, you won't get a token if you use your IBMid and password. You have to use the username and password that were provided for a project. That username is a string of letters and numbers with hyphens.
Second, the documentation for tokens gives you code for getting a token:
curl -X GET --user {username}:{password}
--output token
"https://stream.watsonplatform.net/authorization/api/v1/token?url=https://stream.watsonplatform.net/text-to-speech/api"
Part of that code is hidden on the webpage, specifically the part that says /text-to-speech/. You need to change that to the Watson product or service you want to use, e.g., /speech-to-text/. Tokens are for specific projects and specific services.
Third, tokens expire in one hour.
Lastly, I had to put in backslashes to get the code to run in my terminal:
curl -X GET --user s0921i-s002d-dh9328d9-hd923:wy928ye98e \
--output token \
"https://stream.watsonplatform.net/authorization/api/v1/token?url=https://stream.watsonplatform.net/speech-to-text/api"
I just updated parse-server from 2.2.x to 2.4.x and my cloud code using sessionToken did not work. Below is simple cloud code function:
Parse.Cloud.define('find_device', function(request, response) {
var user = request.user;
if(user){
var token = user.getSessionToken();
console.log("User token " + token);
var query = new Parse.Query('devices');
query.equalTo('deviceId', "389125651274465");
query.find({ sessionToken: token })//<- sessionToken does not work
.then(function(messages) {
response.success(messages);
},function(error){
console.log(error);
response.error("error");
});
}else{
response.error("error");
}
});
It uses {sessionToken: token} to query. This code worked before, but now it does not work in parse-server 2.4.x. I received error
ParseError { code: undefined, message: 'unauthorized' }
I don't know if anything change in parse-server version 2.4.x. If i change to {useMasterKey:true} it works ok, but in this case i want to use user's token to query. Thank for your help.
They havent really changes the the ... query.find({sessionToken : token}) ... part, but maybe they have changed how User.getSessionToken() works.
The documentations says :
String getSessionToken( )
Returns the session token for this user, if
the user has been logged in, or if it is the result of a query with
the master key. Otherwise, returns undefined.
Returns: the session token, or undefined
Since in case of cloud-code, neither the user is logged in, not its the result of a query using masterKey, getSessionToken() should actually behave that way only.
To correct this, what I would suggest is, rather than making the query on-behalf of the user in the cloud-code(and thus on the server), just let the user make it from the client.
I'm developing a Dart application that will need authentication and session control. I'm trying shelf_auth to do that, but the examples doesn't seem to work or, more likely, I'm not implementing them the right way.
In short, this is what I want to happen:
An user opens the application on the browser.
The user enters the login information (login and password), which are POSTED to the server.
If the provided information is valid, the application generates a session code that is passed to the client and stored on the DB (server-side). This code will be sent with every transaction to the server-side.
The package shelf_auth has some examples, but I don't know which one to follow. So my question is: how could I do that with shelf_auth? I'm not asking for anyone to code this for me, but just to point me to the right direction.
EDIT: The example that I was trying out was this: example_with_login_and_jwt_session.dart. Seems that it's lacking CORS headers (this question helped me fixing it) and, even providing valid information, it responds "Unauthorized".
This is how I'm POSTING the information:
import "dart:html";
void main() {
Map _queryParameters = {
"username": "fred",
"password": "blah"
};
var _button = querySelector("#login_button");
_button.onClick.listen((MouseEvent e) {
e.preventDefault();
var requisition = new HttpRequest();
Uri uri = new Uri(path: "http://localhost:8080/login", queryParameters: _queryParameters);
requisition.open("POST", uri.toString());
requisition.setRequestHeader("content-type", "application/x-www-form-urlencoded");
requisition.onLoadEnd.listen((_) {
print(requisition.response.toString());
});
requisition.send();
});
}
I got it working with this client code
import "dart:html";
void main() {
Map _queryParameters = {"username": "fred", "password": "blah"};
var _button = querySelector("#login_button");
_button.onClick.listen((MouseEvent e) async {
e.preventDefault();
var requisition = new HttpRequest();
Uri uri = new Uri(
path: "http://localhost:8080/login/");
requisition.onLoadEnd.listen((_) {
print(requisition.response.toString());
});
HttpRequest request = await HttpRequest.postFormData(
"http://localhost:8080/login/", _queryParameters
//,withCredentials: true
);
print(request.response);
});
}
The example server expects the credentials in the body instead of query parameters and I set withCredentials: true so authentication cookies are sent with the request. Worked without withCredentials.