I am working on a speech-to-text web app using the IBM Watson Speech to text API. The API is fetched on the click of a button. But whenever I click the button. I get the above-mentioned error. I Have stored my API key and URL in a .env file.
I tried a lot but keep on getting this error. Please Help me out as I am new to all this.
I got server.js from the Watson Github Repo
Server.js
'use strict';
/* eslint-env node, es6 */
const env = require('dotenv');
env.config();
const express = require('express');
const app = express();
const AuthorizationV1 = require('watson-developer-cloud/authorization/v1');
const SpeechToTextV1 = require('watson-developer-cloud/speech-to-text/v1');
const TextToSpeechV1 = require('watson-developer-cloud/text-to-speech/v1');
const vcapServices = require('vcap_services');
const cors = require('cors');
// allows environment properties to be set in a file named .env
// on bluemix, enable rate-limiting and force https
if (process.env.VCAP_SERVICES) {
// enable rate-limiting
const RateLimit = require('express-rate-limit');
app.enable('trust proxy'); // required to work properly behind Bluemix's reverse proxy
const limiter = new RateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // limit each IP to 100 requests per windowMs
delayMs: 0 // disable delaying - full speed until the max limit is reached
});
// apply to /api/*
app.use('/api/', limiter);
// force https - microphone access requires https in Chrome and possibly other browsers
// (*.mybluemix.net domains all have built-in https support)
const secure = require('express-secure-only');
app.use(secure());
}
app.use(express.static(__dirname + '/static'));
app.use(cors())
// token endpoints
// **Warning**: these endpoints should probably be guarded with additional authentication & authorization for production use
// speech to text token endpoint
var sttAuthService = new AuthorizationV1(
Object.assign(
{
iam_apikey: process.env.SPEECH_TO_TEXT_IAM_APIKEY, // if using an RC service
url: process.env.SPEECH_TO_TEXT_URL ? process.env.SPEECH_TO_TEXT_URL : SpeechToTextV1.URL
},
vcapServices.getCredentials('speech_to_text') // pulls credentials from environment in bluemix, otherwise returns {}
)
);
app.use('/api/speech-to-text/token', function(req, res) {
sttAuthService.getToken(function(err, token) {
if (err) {
console.log('Error retrieving token: ', err);
res.status(500).send('Error retrieving token');
return;
}
res.send(token);
});
});
const port = process.env.PORT || process.env.VCAP_APP_PORT || 3002;
app.listen(port, function() {
console.log('Example IBM Watson Speech JS SDK client app & token server live at http://localhost:%s/', port);
});
// Chrome requires https to access the user's microphone unless it's a localhost url so
// this sets up a basic server on port 3001 using an included self-signed certificate
// note: this is not suitable for production use
// however bluemix automatically adds https support at https://<myapp>.mybluemix.net
if (!process.env.VCAP_SERVICES) {
const fs = require('fs');
const https = require('https');
const HTTPS_PORT = 3001;
const options = {
key: fs.readFileSync(__dirname + '/keys/localhost.pem'),
cert: fs.readFileSync(__dirname + '/keys/localhost.cert')
};
https.createServer(options, app).listen(HTTPS_PORT, function() {
console.log('Secure server live at https://localhost:%s/', HTTPS_PORT);
});
}
App.js
import React, {Component} from 'react';
import 'tachyons';
//import WatsonSpeech from 'ibm-watson';
var recognizeMic = require('watson-speech/speech-to-text/recognize-microphone');
class App extends Component {
onListenClick = () => {
fetch('http://localhost:3002/api/speech-to-text/token')
.then(function(response) {
return response.text();
}).then(function (token) {
var stream = recognizeMic({
token: token, // use `access_token` as the parameter name if using an RC service
objectMode: true, // send objects instead of text
extractResults: true, // convert {results: [{alternatives:[...]}], result_index: 0} to {alternatives: [...], index: 0}
format: false // optional - performs basic formatting on the results such as capitals an periods
});
stream.on('data', function(data) {
console.log('error 1')
console.log(data);
});
stream.on('error', function(err) {
console.log('error 2')
console.log(err);
});
//document.querySelector('#stop').onclick = stream.stop.bind(stream);
}).catch(function(error) {
console.log('error 3')
console.log(error);
});
}
render() {
return(
<div>
<h2 className="tc"> Hello, and welcome to Watson Speech to text api</h2>
<button onClick={this.onListenClick}>Listen to Microphone</button>
</div>
);
}
}
export default App
Since the only code you show is fetching an authorisation token then I guess that that is what is throwing the authentication failure. I am not sure how old the code you are using is, but the mechanism you are using was used when the STT service credentials are userid / password. The mechanism became unreliable when IAM keys started to be used.
Your sample is still using watson-developer-cloud, but that has been superseded by ibm-watson. As migrating the code to ibm-watson will take a lot of rework, you can continue to use watson-developer-cloud.
If do you stick with watson-developer-cloud and you want to get hold of a token, with an IAM Key then use:
AuthIAMV1 = require('ibm-cloud-sdk-core/iam-token-manager/v1'),
...
tokenService = new AuthIAMV1.IamTokenManagerV1({iamApikey : apikey});
...
tokenService.getToken((err, res) => {
if (err) {
...
} else {
token = res;
...
}
});
Related
I am pretty new to Programming and have some questions regarding the MERN stack.
I am building an app and trying to realize the log in via google. I was successful with integrating the google auth to my frontend and now I want to store the user after a successful login in the backend.
The first question I have is do I need a database to store the user, or is it common to just store them on the express backend?
In the auth process I do get the JWT from google and try sending it to the backend, but it does not work.
I do get the following error: "SyntaxError: Unexpected token o in JSON at position 1".
How can I send the JWT to the backend and check, if the user already exists in MongoDB and if he does not exist, make a new entry for the user. And when he is logged in, make a session so he does not have to log in again after every refresh.
At the moment I got the following code for the frontend:
import './App.css';
import { useEffect, useState } from 'react'
import jwt_decode from 'jwt-decode';
import Survey from './components/survey';
function App() {
const [ user, setUser] = useState({});
const [backendData, setBackendData] = useState([{}]);
// fetch backend API, we can define relative route, as proxy is defined in package.json
useEffect(() => {
fetch("http://localhost:5000/api").then(
response => response.json()
).then(
data => {
setBackendData(data)
}
)
}, [])
// store the JWT and decode it
function handleCallBackResponse(response){
console.log("Encoded JWT ID token: " + response.credential);
var userObject = jwt_decode(response.credential);
console.log(userObject);
setUser(userObject);
document.getElementById("signInDiv").hidden = true;
fetch("http://localhost:5000/user", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: userObject,
})
}
// logout the user and show sign in button, google.accounts.id.disableAutoSelect is recording the status in cookies. This prevents a UX dead loop.
function handleSignOut(event){
setUser({});
document.getElementById("signInDiv").hidden = false;
google.accounts.id.disableAutoSelect();
}
useEffect(() => {
/* global google */
// The google.accounts.id.initialize method initializes the Sign In With Google client based on the configuration object.
google.accounts.id.initialize({
client_id: "CLIENT_ID",
callback: handleCallBackResponse
});
// The google.accounts.id.renderButton method renders a Sign In With Google button in your web pages
google.accounts.id.renderButton(
document.getElementById("signInDiv"),
// if only want to display icon
//{theme: "outline", size: "medium", type: "icon"}
{theme: "outline", size: "medium", text: "signin", shape: "square"}
);
// The google.accounts.id.prompt method displays the One Tap prompt or the browser native credential manager after the initialize() method is invoked.
google.accounts.id.prompt();
}, [])
// If we have no user: show sign in button
// if we have a user: show the log out button
return (
<div className="App">
<div id = "signInDiv"/>
{ Object.keys(user).length !== 0 &&
<button className ='signout' onClick={ (e) => handleSignOut(e)}>
{ user &&
<img className='logout' alt="googleprofile" src={user.picture} width='30px' height='30px'></img>
}
</button>
}
<Survey></Survey>
{(typeof backendData.users === 'undefined') ? (
<p>Loading</p>
) : (
backendData.users.map((user, i) => (
<p key={i}>{user}</p>
))
)}
</div>
);
}
export default App;
Backend:
const express = require('express')
const morgan = require('morgan')
const cors = require("cors")
const mongoose = require("mongoose")
const { OAuth2Client } = require("google-auth-library");
const jwt = require("jsonwebtoken");
const app = express()
const uri = "MONGODBURL"
// connect to mongoDB
async function connect() {
try {
await mongoose.connect(uri)
console.log("Connected to MongoDB")
} catch (error) {
console.error(error)
}
}
connect()
// setup view engine, file in "views" folder needs to have ending .ejs
app.set('view engine', 'ejs')
// log requests in the terminal for troubleshooting
app.use(morgan('combined'))
// allow cors URLs
app.use(cors({
origin: ['http://localhost:3000', 'https://play.google.com', 'https://accounts.google.com'],
methods: ["GET", "POST", "PUT", "DELETE"],
credentials: true
}))
app.use(express.json());
// start app on port 5000 and give an log message
app.listen(5000, () => {console.log("Server started on port 5000") })
Hope this make clear what I want to achieve. I really appreciate any help.
Kind Regards
I'm trying to make users profiles dynamic in appwrite app. I want each user profile page to be accessible to all users so it goes like this (www.appname.com/users/{userid}).
I'm very new to node JS but i managed to install appwrite SDK for node and created a seperate folder for node and when i run the below code in node it gets me the user as expected in the terminal.
const sdk = require("node-appwrite");
// Init SDK
let client = new sdk.Client();
let users = new sdk.Users(client);
client
.setEndpoint("http://localhost/v1") // Your API Endpoint
.setProject("myProjectId") // Your project ID
.setKey(
"mykey"
); // Your secret API key
let promise = users.get("myUserId");
promise.then(
function (response) {
console.log(response);
},
function (error) {
console.log(error);
}
);
But I want to be able to use Vuejs to call out this outcome! I want to be able to use (users.get) from Vue component. How can I make this happen?
here is what I have tried till now:
I have created UserService.js file and added the below function to grab users.get from node Js
import users from "../../../api/server";
export async function getUser(userId) {
let promise = users.get(userId);
promise.then(
function (response) {
console.log(response);
},
function (error) {
console.log(error);
}
);
}
And I called it from my VueJS component
<script>
import { getUser } from "../../services/UserService";
export default {
name: "Profile",
props: ["id"],
data() {
return {
userprfile: false,
};
},
mounted() {
this.getUser();
},
methods: {
getUser() {
getUser(this.id).then((response) => {
console.log(response);
});
},
},
};
</script>
But it doesn't work
All I want is a way that allows me to use appwrite nodeJS SDK in my vueJS component. I need to be able to pass it the userID and get back the user in VueJS component
UPDATE:
The below code works and I can get now retrieve the data from appwrite NodeJS SDK to my browser but the problem is that I want this to be dynamic. I need a way to pass on UserID from vue to NodeJS sdk and retrieve the data.
const express = require("express");
const path = require("path");
const app = express(),
bodyParser = require("body-parser");
port = 3080;
// place holder for the data
const sdk = require("node-appwrite");
// Init SDK
let client = new sdk.Client();
let users = new sdk.Users(client);
client
.setEndpoint("http://localhost/v1") // Your API Endpoint
.setProject("myProjectID") // Your project ID
.setKey(
"MySecretApiKey"
); // Your secret API key
app.use(bodyParser.json());
app.use(express.static(path.join(__dirname, "../appwrite-app/build")));
app.get("/v1/users", (req, res) => {
console.log("api/users called!");
let promise = users.get("userId");
promise.then(
function (response) {
res.json(response);
},
function (error) {
console.log(error);
}
);
});
app.listen(port, () => {
console.log(`Server listening on the port::${port}`);
});
It looks like you are trying to use a node only module on the client (browser). You cannot use any module on the client that uses native node modules - in this case fs.
So what you need to do from your frontend application is send a request to your server application (API). On the API do any file system/database retrieval, then send the results back to the client.
It's very common to write the backend/frontend as separate applications - in separate folders and even store in separate repositories.
You should also never expose any secret keys on the client.
There may also be some confusion about the term 'client'. Most of the time it's used to refer to an application run in a web browser but you also get node sdk's which are 'clients' of the services they use - like node-appwrite in your case.
I am logging users in via their domain Google accounts using passport.js. This works great, but now I need to give this application access to a few Google API's (drive, sheets, etc).
When a user logs in, a message appears in the logs, that makes it seem like passport has all the required info:
info: [06/Jun/2019:21:24:37 +0000] "302 GET /auth/callback?code=** USER ACCESS TOKEN HERE **&scope=email%20profile%20https://www.googleapis.com/auth/drive.file%20https://www.googleapis.com/auth/spreadsheets%20https://www.googleapis.com/auth/userinfo.email%20https://www.googleapis.com/auth/userinfo.profile%20https://www.googleapis.com/auth/drive HTTP/1.1" [46]
This is achieved by passing the appended scopes via passport.authenticate(), which presents the user with the "Grant access to these things on your Google account to this app?" screen :
//Initial auth call to Google
router.get('/',
passport.authenticate('google', {
hd: 'edmonds.wednet.edu',
scope: [
'email',
'profile',
'https://www.googleapis.com/auth/drive',
'https://www.googleapis.com/auth/drive.file',
'https://www.googleapis.com/auth/spreadsheets'
],
prompt: 'select_account'
})
);
However, when I go and try to call an API with something like:
const {google} = require('googleapis');
const sheets = google.sheets({version: 'v4', auth});
router.post('/gsCreate', function(req,res,next){
sheets.spreadsheets.create({
// Details here.....
});
});
I get nothing but errors (the current one is debug: authClient.request is not a function)
My question is: Is it possible for me to use a setup like this, asking the user to log in and grant permissions once, and then somehow save that to their user session via passport?
I had the same question, but I was able to access Google Gmail API functionalities along with Passport.js user authentication by specifying 'scopes' using the following process.
First, create a file to setup the passport-google-strategy in nodejs as follows.
passport_setup.js
const passport = require('passport')
const GoogleStrategy = require('passport-google-oauth20')
const fs = require("fs");
const path = require('path');
//make OAuth2 Credentials file using Google Developer console and download it(credentials.json)
//replace the 'web' using 'installed' in the file downloaded
var pathToJson = path.resolve(__dirname, './credentials.json');
const config = JSON.parse(fs.readFileSync(pathToJson));
passport.serializeUser((user, done) => {
done(null, user.id)
})
passport.deserializeUser((id, done) => {
const query = { _id: id }
Users.findOne(query, (err, user) => {
if (err) {
res.status(500).json(err);
} else {
done(null, user)
}
})
})
//create a google startergy including following details
passport.use(
new GoogleStrategy({
clientID: config.installed.client_id,
clientSecret: config.installed.client_secret,
callbackURL: config.installed.redirect_uris[0]
}, (accessToken, refreshToken,otherTokenDetails, user, done) => {
//in here you can access all token details to given API scope
//and i have created file from that details
let tokens = {
access_token: accessToken,
refresh_token: refreshToken,
scope: otherTokenDetails.scope,
token_type: otherTokenDetails.token_type,
expiry_date:otherTokenDetails.expires_in
}
let data = JSON.stringify(tokens);
fs.writeFileSync('./tokens.json', data);
//you will get a "user" object which will include the google id, name details,
//email etc, using that details you can do persist user data in your DB or can check
//whether the user already exists
//after persisting user data to a DB call done
//better to use your DB user objects in the done method
done(null, user)
})
)
Then create your index.js file in nodejs for API route management and to call send method of Gmail API.
Also, run the following command to install "google-apis"
npm install googleapis#39 --save
index.js
const express = require("express")
//import passport_setup.js
const passportSetup = require('./passport_setup')
const cookieSeesion = require('cookie-session');
const passport = require("passport");
//import google api
const { google } = require('googleapis');
//read credentials file you obtained from google developer console
const fs = require("fs");
const path = require('path');
var pathToJson_1 = path.resolve(__dirname, './credentials.json');
const credentials = JSON.parse(fs.readFileSync(pathToJson_1));
//get Express functionalities to app
const app = express();
// **Middleware Operations**//
//cookie encryption
app.use(cookieSeesion({
name:'Reserve It',
maxAge: 1*60*60*1000,
keys: ['ranmalc6h12o6dewage']
}))
//initialize passort session handling
app.use(passport.initialize())
app.use(passport.session())
app.use(express.json());
//**API urls**//
//route to authenticate users using google by calling google stratergy in passport_setup.js
//mention access levels of API you want in the scope
app.get("/google", passport.authenticate('google', {
scope: ['profile',
'email',
'https://mail.google.com/'
],
accessType: 'offline',
prompt: 'consent'
}))
//redirected route after obtaining 'code' from user authentication with API scopes
app.get("/google/redirect", passport.authenticate('google'), (req, res) => {
try {
//read token file you saved earlier in passport_setup.js
var pathToJson_2 = path.resolve(__dirname, './tokens.json');
//get tokens to details to object
const tokens = JSON.parse(fs.readFileSync(pathToJson_2));
//extract credential details
const { client_secret, client_id, redirect_uris } = credentials.installed
//make OAuth2 object
const oAuth2Client = new google.auth.OAuth2(client_id,
client_secret,
redirect_uris[0])
// set token details to OAuth2 object
oAuth2Client.setCredentials(tokens)
//create gmail object to call APIs
const gmail = google.gmail({ version: 'v1', auth: oAuth2Client })
//call gmail APIs message send method
gmail.users.messages.send({
userId: 'me',//'me' indicate current logged in user id
resource: {
raw: //<email content>
}
}, (err, res) => {
if (err) {
console.log('The API returned an error: ' + err)
throw err
}
console.log('Email Status : ' + res.status)
console.log('Email Status Text : ' + res.statusText)
})
res.status(200).json({ status:true })
} catch (err) {
res.status(500).json(err)
}
})
app.listen(3000, () => { console.log('Server Satrted at port 3000') })
You can separate the routes in the index.js file to different files for clarity using express.Router()
If you want to call another Google API service just change this code segment and code below that;
const gmail = google.gmail({ version: 'v1', auth: oAuth2Client })
gmail.users.messages.send(....Send Method internal implementation given above....)
For Google Drive:
const drive = google.drive({version: 'v3', auth: oAuth2Client});
drive.files.list(...Refer "Google Drive API" documentation for more details....)
I believe you can't use passport.js for three-legged oauth for APIs like Sheets or Drive.
Have a look at the Using OAuth for web servers documentation instead.
user835611 has the correct answer, as that page explains everything quite nicely. However, if you still need more, the below link really helped me to understand how this works.
https://github.com/googleapis/google-auth-library-nodejs#oauth2
I was trying to make a Polyfill.io server as a microservice on AWS Lambda, it was supposed to run a JavaScript file on a GET request.
When I run the service locally the call goes through but it returns an undefined object instead of JS file.
I'm running it locally using serverless, my code is based on polyfill.io's github repo
I've modified the service/index.js to be like so:
'use strict';
const express = require('express');
const path = require('path');
const Raven = require('raven');
const morgan = require('morgan');
const shrinkRay = require('./shrink-ray');
const app = express().enable("strict routing");
const one_day = 60 * 60 * 24;
const one_week = one_day * 7;
const one_year = one_day * 365;
app.use(shrinkRay({
brotli: {quality: 11}
}));
let ravenClient;
// Log requests
if (process.env.ENABLE_ACCESS_LOG) {
app.use(morgan('method=:method path=":url" request_id=:req[X-Request-ID] status=:status service=:response-time bytes=:res[content-length]'));
}
process.on('uncaughtException', (err) => {
console.log('Caught exception', err);
});
// Set up Sentry (getsentry.com) to collect JS errors.
if (process.env.SENTRY_DSN) {
const about = require(path.join(__dirname, '../about.json'));
ravenClient = new Raven.Client(process.env.SENTRY_DSN, {
release: about.appVersion || process.env.SENTRY_RELEASE || 'unknown'
});
ravenClient.patchGlobal();
app.use(Raven.middleware.express.requestHandler(ravenClient));
}
// Do not send the X-Powered-By header.
app.disable("x-powered-by");
// Default response headers
app.use((req, res, next) => {
// Ensure our site is only served over TLS and reduce the chances of someone performing a MITM attack.
res.set('Strict-Transport-Security', `max-age=${one_year}; includeSubdomains; preload`);
// Enables the cross-site scripting filter built into most modern web browsers.
res.set('X-XSS-Protection', `1; mode=block`);
// Prevents MIME-sniffing a response away from the declared content type.
res.set('X-Content-Type-Options', `nosniff`);
// Sets content-type
res.set('Content-Type', `application/javascript`);
// Prevents clickjacking by prohibiting our site from being included on other domains in an iframe.
res.set('X-Frame-Options', `sameorigin`);
res.set('Cache-Control', 'public, s-maxage=' + one_year + ', max-age=' + one_week + ', stale-while-revalidate=' + one_week + ', stale-if-error=' + one_week);
res.set('Surrogate-Key', process.env.SURROGATE_KEY || 'polyfill-service');
res.set('Timing-Allow-Origin', '*');
return next();
});
/* Routes */
app.use(require('./routes/api.js'));
app.use(require('./routes/meta.js'));
app.use('/test', require('./routes/test.js'));
if (process.env.RUM_MYSQL_DSN) {
app.use(require('./routes/rum.js'));
}
app.use(/^\/v[12]\/assets/, express.static(__dirname + '/../docs/assets'));
if (process.env.SENTRY_DSN) {
app.use(Raven.middleware.express.errorHandler(ravenClient));
}
module.exports.node = (event, context, callback) => {
const response = {
statusCode: 200,
body: JSON.stringify({
message: 'Go Serverless v1.0! Your function executed successfully!',
input: event,
}),
};
callback(event, app);
};
This is my serverless.yml:
service: serverless-node
provider:
name: aws
region: us-east-1
stage: dev
runtime: nodejs6.10
functions:
node:
handler: service/index.node
events:
- http:
path: node
method: get
I think you need to pass back the response object in the callback in the handler e.g.
callback(null, response);
EDIT 5
I have back and front end running on LAMP environment accesible with 192.168.80.213/backend adress.
I try to make a push notification server using nodejs, socket.io and express framework to link back and front end.
My nodejs server is listening on port 3000 while my backend and front end listenning on port 80 both using apache.
Here is my node client :
<script type="text/javascript" src="socket.io-1.4.5.js"></script>
<script type="text/javascript">
var socket = io('http://192.168.80.213:3000/');
</script>
Here is my node server :
const express = require('express')
, app = express()
, http = require('http').Server(app)
, socketIo = require('socket.io')(http)
, cookieParser = require('cookie-parser')
, cookie = require('cookie')
, connect = require('connect')
, expressSession = require('express-session')
, port = 3000
, helmet = require('helmet')
, name = 'connect.sid'
, sessionStore = new expressSession.MemoryStore({ reapInterval: 60000 * 10 })
, sessionSecret = 'VH6cJa7yZSmkRbmjZW#J3%CDn%dt'
, environment = process.env.NODE_ENV || 'development'
;
/** Configuration **/
app.enable('trust proxy');
app.disable('x-powered-by');
app.use(helmet());
app.use(cookieParser());
app.use(expressSession({
'name' : name,
'secret': sessionSecret,
'store' : sessionStore,
'resave': true,
'saveUninitialized': true
}));
app.get('/', function(req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello from node');
});
socketIo.use(function(socket, callback) {
// Read cookies from handshake headers
var cookies = cookie.parse(socket.handshake.headers.cookie);
// We're now able to retrieve session ID
var sessionID;
if (cookies[name]) {
console.log( "cookies['" + name + "'] = " + cookies[name] );
sessionID = cookieParser.signedCookie( cookies[name], sessionSecret );
console.log( "sessionID = " + sessionID );
}else{
console.log( "cookies['" + name + "'] = undefined" );
}
if (!sessionID) {
console.log('ERROR NO SESSION CONNECTION REFUSED !!');
callback('No session', false);
} else {
// Store session ID in handshake data, we'll use it later to associate
// session with open sockets
socket.handshake.sessionID = sessionID;
callback(null, true);
}
});
socketIo.on('connection', function (socket) { // New client
console.log( 'new connection..' );
console.log('user ' + socket.handshake.sessionID + ' authenticated and is now connected.');
});
/** Start server */
http.listen(port);
console.log( "listening on :" + port );
Go to 192.168.80.213:3000 and see 'Hello from node' and cookie['connect.sid'] is set according to screenshot below
And console output :
Now Clearing cache and i'm going to my back end app where is my nodeClient 192.168.80.213/backend.
connect.sid cookie doesn't exist
And console output :
Why express-session ain't set cookie.sid ? how can i fix that ? I'm new to node and express, i spend many times googling without succes, hope some node masters coul help me !!
regards
I dont know which version of socket.io you are using but after version 1.0 (> 1.0):
To register a middleware you should use socketIo.use (See documentation)
First parameter is incoming socket which have access to request through socket.request
express session by default save cookies with connect.sid name if you want to use io name you should set it explicitely (See name option)
When you want to parse a signed cookie you should provide it sessionSecret not sessionStore
and finally i think handshake support is deprecated and you should attach anything you want directly to socket (See authentication-differences).
With considering aboves you could use a middleware like following to Authenticate your sockets:
// every incoming socket should pass this middleware
socketIo.use(function(socket, next) {
var cookies = cookie.parse(socket.request.headers.cookie);
var sessionID = cookieParser.signedCookie(cookies['connect.sid'], sessionSecret);
sessionStore.get(sessionID, function(err, session) {
if ( session && session.isAuthenticated ) {
socket.userId = session.user.id;
return next();
} else {
return next(new Error('Not Authenticated'));
}
});
});
// when connected ...
socketIo.on('connection', function(socket) {
console.log('user ' + socket.userId + ' authenticated and is now connected.')
});
Here i consider you set isAuthenticated Boolean value and user on session when users logged in.
Also bear in mind that built in sessionStore, MemoryStore is not suit for production environment:
The default server-side session storage, MemoryStore, is purposely not
designed for a production environment. It will leak memory under most
conditions, does not scale past a single process, and is meant for
debugging and developing.
So you must consider using another session store like:
connect-mongo
or
connect-redis
I don't have experience using cookie or cookie-parser and am generally new to node, but I had a similar system to authenticate socket connections by accessing server side session variables if that helps at all.
Save the session details inside a variable
var sessionStorage = expressSession({
'secret': sessionSecret,
'store' : sessionStore,
'resave': true,
'saveUninitialized': true
});
let socketIo and app use the storage
socketIo.use(function (socket, next) {
sessionStorage(socket.request, socket.request.res, next);
});
app.use(sessionStorage);
and then inside on connect you can access those session variables using:
socket.request.res.session.[variable name]