faye authentication with token - javascript

I am working with faye messaging system and I want to add authentication! I worked my way through the website and followed the tutorial.
On the Client I have an extension for outgoing Messages:
var droneFaye = new faye.Client("/faye", {
timeout: 120
});
var USER_TOKEN = 'ifd63cylqwsyaq9c2ptzywjujgtfpxs';
droneFaye.addExtension({
outgoing: function(message, callback) {
if (message.channel !== '/meta/subscribe')
return callback(message);
message.ext = message.ext || {};
message.ext.token = USER_TOKEN;
console.log(message);
callback(message);
}
});
On the Server:
var token = 'ifd63cylqwsyaq9c2ptzywjujgtfpxs'
var serverAuth = {
incoming: function(message, callback) {
// Let non-subscribe messages through
if (message.channel !== '/meta/subscribe')
return callback(message);
// Get subscribed channel and auth token
var msgToken = message.ext && message.ext.token;
// Find the right token for the channel
if (token !== msgToken) {
message.error = 'Invalid subscription auth token';
}
console.log(message);
callback(message);
}
};
var adapter = new faye.NodeAdapter({
mount:'/faye',
timeout:45
});
adapter.addExtension(serverAuth);
adapter.attach(httpServer);
I have a subscription on the server like this:
adapter.getClient().subscribe("/drone/move", function(cmd) {});
Alright! So when I start the server and there is NO CLIENT it already calls the extension for the subscriptions and it will output on the console:
{ channel: '/meta/subscribe',
clientId: '2isdeb0ds77zl0lh82ob1kqu29y1cajnv80',
subscription: '/drone/move',
id: '2',
error: 'Invalid subscription auth token' }
Once a Client connects to the server it will again call the extension and it will output this:
{ channel: '/meta/subscribe',
clientId: '3kechs0c7smpc05z5o7d0a8qcd301d8zi41',
subscription: '/drone/move',
id: '3',
ext: { userId: 18787, token: 'ifd63cylqwsyaq9c2ptzywjujgtfpxs' } }
So this looks good! But no other messages are going to arrive on the server even though they have the correct token and there is no error message!
Just for information. If you add a error key with a value to the message object it will not pass the message to its subscription...its supposed to be like that!..
Also when I comment out the message.error in the extension it works fine but of course there is not authentication.
So does anyone know why the server calls the extension even though there is no client and second why does faye not give the message to its subscription even though there is no error in the message object?
thx!

Question was also asked, and answered here:
This is caused by the call to adapter.getClient().subscribe().
[...] the server-side client (<adapter>.getClient()) returns a connection to the server, thus walks through the same extensions (incoming, outgoing) as the client does.
[...] Attach an outgoing extension and you'll see it being responded to the server-client.

Related

Not able to communicate through websocket from amazon connect

I'm integration amazon connect platform to maintain a two-way flow communication in our own chatbot where customer will be the user in our platform and agents will be there on amazon connect platform to communicate. I'm using websockets for the communication now but it is giving me Forbidden error. Details are mentioned below
Initially, I have used aws-sdk and #aws-sdk/client-connectparticipant library to make the connection with aws and then multiple SDKs in order are used further to send the messages.
startChatContact -> Used AWS library to make the connection with AWS and then using it to retrieve participation token
createParticipantConnection -> Using participation token to retrieve connection token from this sdk using Type: [ 'CONNECTION_CREDENTIALS' ]
sendEvent -> Using connection token and ContentType: 'application/vnd.amazonaws.connect.event.connection.acknowledged' to send the event
sendMessage -> After sending the event, sending the message with connection token and ContentType: 'text/plain'
import * as AWS from 'aws-sdk';
import * as AWSConnectParticipant from "#aws-sdk/client-connectparticipant";
private messageText = "";
private connectionToken = "";
private connectParticipant = new AWSConnectParticipant.ConnectParticipant({
credentials: {
accessKeyId: '...',
secretAccessKey: '...'
},
region: '...'
});
// It will get called when user sends a message on the chat window
public sendMessage(text: string): void {
this.messageText = text || "";
if (this.connectionToken) {
this.sendEventOnAWSConnect();
} else {
this.startChatContact();
}
}
startChatContact() {
const connect = new AWS.Connect({
accessKeyId: '...',
secretAccessKey: '...',
region: '...'
});
const params = {
ContactFlowId: '...',
InstanceId: '...',
ParticipantDetails: {
DisplayName: 'Customer'
}
};
connect.startChatContact(params, (err: any, data: any) => {
if (data) {
this.createParticipantConnection(data);
}
});
}
createParticipantConnection(startChatContactRes: any) {
const params = {
ParticipantToken: startChatContactRes.ParticipantToken,
Type: [ 'CONNECTION_CREDENTIALS' ]
};
this.connectParticipant.createParticipantConnection(params, (err: any, data: any) => {
if (data) {
this.connectionToken = data.ConnectionCredentials.ConnectionToken;
this.sendEventOnAWSConnect();
this.checkAgentMessage(data.Websocket.Url);
}
});
}
sendEventOnAWSConnect() {
const params = {
ConnectionToken: this.connectionToken,
ContentType: 'application/vnd.amazonaws.connect.event.connection.acknowledged'
};
this.connectParticipant.sendEvent(params, (err: any, data: any) => {
if (data) {
this.sendMessageOnAWSConnect();
}
});
}
sendMessageOnAWSConnect() {
const params = {
ConnectionToken: this.connectionToken,
Content: this.messageText,
ContentType: 'text/plain'
};
this.connectParticipant.sendMessage(params, (err: any, data: any) => {
if (data) {
console.log("Agent connected");
}
});
}
It is working fine as expected. I'm able to send messages on amazon connection with the following code. But I'm facing some issues on receiving agent messages back. I have search for any events which I can trigger on my end or any webhook, but unable to find anything on the same.
Issue on 1st method: Not a good approach. Looking for a better solution
So, I have used polling technique initally where I have used getTranscript SDK from #aws-sdk/client-connectparticipant and calling the api on every 2 seconds to check for any new agent messages but I'm looking for a better method now on the same.
Issue on 2nd method: getting connect.core.getWebSocketManager() as undefined
After exploring, I have also found that there is an onMessage event, which I can trigger using amazon-connect-streams and amazon-connect-chatjs library after creating agent session but
connect.core.getWebSocketManager() as undefined. Also, code after connect.contact is not getting executed, so I have commented that also. I have also created customer session similarly but there also **onMessage **event is not getting triggered. I'm calling its method i.e. checkAgentMessage after I get response from createParticipantConnection method successfully since I'm using contact id, participant id and participant token in checkAgentMessage method, which I'm getting from createParticipantConnection method. Below is the code.
import "amazon-connect-streams";
import "amazon-connect-chatjs";
createParticipantConnection(startChatContactRes: any) {
const params = {
ParticipantToken: startChatContactRes.ParticipantToken,
Type: [ 'CONNECTION_CREDENTIALS' ]
};
this.connectParticipant.createParticipantConnection(params, (err: any, data: any) => {
if (data) {
this.connectionToken = data.ConnectionCredentials.ConnectionToken;
this.sendEventOnAWSConnect();
this.checkAgentMessage(data);
}
});
}
checkAgentMessage(startChatContactRes: any): void {
// for type customer
// const customerChatSession = connect.ChatSession.create({
// chatDetails: {
// contactId: startChatContactRes.ContactId,
// participantId: startChatContactRes.ParticipantId,
// participantToken: startChatContactRes.ParticipantToken,
// },
// type: connect.ChatSession.SessionTypes.CUSTOMER
// });
// for type agent
// connect.contact(contact => {
// if (contact.getType() !== connect.ContactType.CHAT) {
// // applies only to CHAT contacts
// return;
// }
// alternative: if you want control over the args of `connect.ChatSession.setGlobalConfig()` and `connect.ChatSession.create()`
// contact.onAccepted(() => {
const agentChatSession = connect.ChatSession.create({
chatDetails: {
contactId: startChatContactRes.ContactId,
participantId: startChatContactRes.ParticipantId,
participantToken: startChatContactRes.ParticipantToken,
},
options: { // REQUIRED
region: "...", // REQUIRED, must match the value provided to `connect.core.initCCP()`
},
type: connect.ChatSession.SessionTypes.AGENT, // REQUIRED
websocketManager: connect.core.getWebSocketManager() // REQUIRED
})
agentChatSession.onMessage(event => {
console.log("event", event);
});
// });
// });
}
I have checked if I can set connect.core.getWebSocketManager() from somewhere, but got nothing help on the same.
Issue on 3rd method: getting Forbidden as error or message
I have also come across another solution and that is from web sockets. So, I'm implementing the same but there I'm getting error as Forbidden
I have changed my createParticipantConnection function with something as below:
createParticipantConnection(startChatContactRes: any) {
const params = {
ParticipantToken: startChatContactRes.ParticipantToken,
Type: [ 'WEBSOCKET' ]
};
this.connectParticipant.createParticipantConnection(params, (err: any, data: any) => {
if (data) {
let socket = new WebSocket(data.Websocket.Url);
socket.onopen = function(e) {
console.log("[open] Connection established");
console.log("Sending to server");
socket.send("My name is John");
};
socket.onmessage = function(event) {
console.log("event", event);
console.log(`[message] Data received from server: ${event.data}`);
};
socket.onclose = function(event) {
if (event.wasClean) {
console.log(`[close] Connection closed cleanly, code=${event.code} reason=${event.reason}`);
} else {
// e.g. server process killed or network down
// event.code is usually 1006 in this case
console.log('[close] Connection died');
}
};
socket.onerror = function(error) {
console.log(`[error]`);
};
// this.connectionToken = data.ConnectionCredentials.ConnectionToken;
// this.sendEventOnAWSConnect();
// this.checkAgentMessage(data);
}
});
}
Changed Type from CONNECTION_CREDENTIALS to WEBSOCKET to retrieve the websocket url. Getting output on the same as:
[open] Connection established
Sending to server
event MessageEvent {...}
[message] Data received from server: {"message": "Forbidden", "connectionId":"...", "requestId":"..."}
It is throwing Forbidden as error or message. Please let me know if there is anything I have left which needs to be also implemented or I have done anything wrong here. Also please let me know, if anybody have the solution for the issue on 2nd method or if there is any other method to retrieve agent messages as well.
After calling CreateParticipantConnection, you need to send a subscribe message. You'll then start receiving messages & events on the websocket.
From https://docs.aws.amazon.com/connect-participant/latest/APIReference/API_CreateParticipantConnection.html :
For chat, you need to publish the following on the established websocket connection:
{"topic":"aws/subscribe","content":{"topics":["aws/chat"]}}

Twilio voice call works only once [microphone permission issue]

I implemented Twilio voice call functionality that enables users to call support people from the browser but it works the first time only after allowed microphone permission but then next time getting below error and resetting microphone permission then voice call works.
code: 31000, message: "Cannot establish connection. Client is disconnected"
Below is code snippet on the client-side that written in angular with help of twilio client docs
import twilio from 'twilio-client';
public device: any;
this.device = new twilio.Device('<token-fetched>', {
codecPreferences: ['opus', 'pcmu'],
fakeLocalDTMF: true,
enableIceRestart: true
})
let params = {
To: '<to-number>',
Id: '<id>',
token: '<token-fetched>'
}
if (this.device) {
this.device.connect(params);
}
this.device.on('error', (error) => {
console.log("this is error",error);
})
this.device.on('disconnect',(connection) => {
console.log("connection ended", connection);
})
I had the same issue here, the problem is that I was calling var connection = Twilio.Device.connect(); before the async setup work had been completed.
Write device.connect inside of device.ready function like
Twilio.Device.ready(function(device) {
console.log('Ready');
var connection = Twilio.Device.connect();
// Do rest of twilio work ...!
}
This will fix your issue.

FB Graph API: Grabbing all mutual friends - (#200) You do not have sufficient permissions to perform this action

I am using AWS Lambda to ask for all mutual friends between current user and another user as stated here: https://developers.facebook.com/docs/graph-api/reference/user-context/all_mutual_friends/
I have looked through all the other stackoverflow answers and can't really find one close enough and have followed each of their answers to still get errors like these:
Facebook Graph All Mutual Friends
and
"Requires a valid user is specified ..." error when using getCount
and my code looks like the below in AWS, note that I have used this node.js third-party sdk (https://github.com/node-facebook/facebook-node-sdk):
// Imports third-party fb graph api node.js sdk: https://github.com/node-facebook/facebook-node-sdk
const fbGraph = require('fb');
// Grabs app secret and app ID
const appSecret = process.env.APP_SECRET;
const appID = process.env.APP_ID;
// Uses user access token and grabs total count of all relevant mutual friends
exports.handler = (event, context, callback) => {
// Grabs relevant details from request
// const accessToken = event.accessToken;
const friendUserID = event.friendUserID;
fbGraph.api('oauth/access_token', {
client_id: appID,
client_secret: appSecret,
grant_type: 'client_credentials'
}, function (res) {
if(!res || res.error) {
console.log(!res ? 'error occurred' : res.error);
return;
}
let access_token = res.access_token;
// Sets options for fb graph api to work
fbGraph.options({accessToken: access_token, appId: appID, appSecret: appSecret, timeout: 12000});
// Sets up fields and query string for request
const friendUserIDQueryString = '/' + friendUserID;
const fields = {
fields: 'context.fields(all_mutual_friends.limit(10))'
};
// Sends api request to get all mutual friends
fbGraph.api(friendUserIDQueryString, 'post', fields, function(response) {
console.log(response);
// Error handling
if (response.error) {
// Logs error
context.done(null, { MutualFriendsTotalCountError: 'Error: not able to receive response' });
// Returns error message
return callback(new Error(`Mutual friends total count error: ${response.error}`));
}
// Logs successful operation
context.done(null, { MutualFriendsTotalCountSuccess: `Success: grabbed total mutual friend count for ${friendUserID}`});
// Returns total count of mutual friends between current and other user as integer
return callback(null, { total_count: response.context.all_mutual_friends.summary.total_count });
});
});
}
but my response is now this:
{ error:
{ message: '(#200) You do not have sufficient permissions to perform this action',
type: 'OAuthException',
code: 200,
...
}
I don't really understand it, I've used my own access token on my IOS app I'm using this for, the application app token through OAuth, and also the other user ID who exists on my app and is the one thats specific for my app and other recommended solutions to no avail.
Ok now it works, I followed exactly with the example from this stackoverflow:
Facebook Graph All Mutual Friends
I don't know whats explicitly the difference as it still looks similar to something I had before but this is what my current code looks like and works:
// Imports third-party fb graph api node.js sdk: https://github.com/node-facebook/facebook-node-sdk
const fbGraph = require('fb');
// Grabs app secret and app ID
const appSecret = process.env.APP_SECRET;
const appID = process.env.APP_ID;
// Uses user access token and grabs total count of all relevant mutual friends
exports.handler = (event, context, callback) => {
// Grabs relevant details from request
const accessToken = event.accessToken;
const friendUserID = event.friendUserID;
// Sets options for fb graph api to work
fbGraph.options({accessToken: accessToken, appId: appID, appSecret: appSecret, timeout: 12000});
// Sends api request to get all mutual friends
fbGraph.api('/' + friendUserID, { fields: 'context.fields(all_mutual_friends.limit(0))'}, function(response) {
// Error handling
if (!response || response.error) {
// Logs error
console.log('MutualFriendsTotalCountError: Error: not able to receive response');
// Returns error message
return callback(new Error(`Mutual friends total count error: ${response.error.message}`));
}
// Logs successful operation
console.log(`Success: grabbed total mutual friend count for ${friendUserID}`);
// Returns total count of mutual friends between current and other user as integer
return callback(null, { total_count: response.context.all_mutual_friends.summary.total_count });
});
}
By the way, this returns the total number of app-using and non-app using mutual friends between current user and another user on AWS Lambda

Cloud Functions for Firebase HTTP timeout

I'm so close with this one.
I have written a Cloud Function that takes information sent from an Azure token to custom mint a Firebase token and send this token back to the client.
The token is created correctly, but isn't returned on my HTTP-request.
Unfortunately my Firebase app causes a timeout.
Function execution took 60002 ms, finished with status: 'timeout'
I can't really wrap my head around why that is, hence this post. Is there something wrong with my code, or is it me that's calling the HTTP-request wrong?
Here is the log I get from the Firebase Functions console.
Here's my code
// Create a Firebase token from any UID
exports.createFirebaseToken = functions.https.onRequest((req, res) => {
// The UID and other things we'll assign to the user.
const uid = req.body.uid;
const additionalClaims = {
name: req.body.name,
email: req.body.email
};
// Create or update the user account.
const userCreationTask = admin.auth().updateUser(uid, additionalClaims).catch(error => {
// If user does not exists we create it.
if (error.code === 'auth/user-not-found') {
console.log(`Created user with UID:${uid}, Name: ${additionalClaims.name} and e-mail: ${additionalClaims.email}`);
return admin.auth().createUser({
uid: uid,
displayName: displayName,
email: email,
});
}
throw error;
console.log('Error!');
});
// Wait for all async tasks to complete, then generate and return a custom auth token.
return Promise.all([userCreationTask]).then(() => {
console.log('Function create token triggered');
// Create a Firebase custom auth token.
return admin.auth().createCustomToken(uid, additionalClaims).then((token) => {
console.log('Created Custom token for UID "', uid, '" Token:', token);
return token;
});
});
});
When I'm making this HTTP-request, all i'm sending in is a JSON that looks like this:
parameters = [
"uid" : id,
"email" : mail,
"name" : name
]
Cloud Functions triggered by HTTP requests need to be terminated by ending them with a send(), redirect(), or end(), otherwise they will continue running and reach the timeout.
From the terminate HTTP functions section of the documentation on HTTP triggers:
Always end an HTTP function with send(), redirect(), or end(). Otherwise, your function might to continue to run and be forcibly terminated by the system. See also Sync, Async and Promises.
After retrieving and formatting the server time using the Node.js moment module, the date() function concludes by sending the result in the HTTP response:
const formattedDate = moment().format(format);
console.log('Sending Formatted date:', formattedDate);
res.status(200).send(formattedDate);
So, within your code, you could send the token back in the response with send(), for example:
// ...
// Create a Firebase custom auth token.
return admin.auth().createCustomToken(uid, additionalClaims).then((token) => {
console.log('Created Custom token for UID "', uid, '" Token:', token);
res.status(200).send(token);
return token;
});
// ...

How to determine which session I'm on for OAuth reauthentication in Meteor?

I've written my own custom authentication to work with our corporate OAuth solution. This results in an OAuth access and refresh token being sent to me. I can then store these tokens in the user collection of the Meteor database but when I want to perform reauthentication I need to be able to find the right session to be able to locate which OAuth token I should use for refreshing it, if required. Since the user can login from multiple devices, this complicates matters.
This is the code I use to store the tokens and send result on the server-side:
var userId = null;
var user = Meteor.users.findOne({username: userName});
if (!user) {
userId = Meteor.users.insert({username: userName});
} else {
userId = user._id;
}
logger.info("User logged in: " + userId);
var initToken = Accounts._generateStampedLoginToken();
var token = Accounts._hashStampedToken(initToken);
token.accessToken = result.data.access_token;
token.refreshToken = result.data.refresh_token;
token.ttl = result.data.expires_in;
// Need way to bind oath.loginTokens with Meteor resume token
Meteor.users.update(userId,
{$push: {'services.oauth.loginTokens': token}}
);
var rslt = {
userId: userId
};
return(rslt);
And this is the resulting record in the DB:
"services" : {
"oauth" : {
"loginTokens" : [
{
"when" : ISODate("2014-06-17T17:51:24.635Z"),
"hashedToken" : "ErcosEo9rD+IuT3EyFb3DFS8Bf0enwLzkCIf/nP1JFE=",
"accessToken" : "bhafr3WBDS67EmZ9hFE20af83BJRPFQQS8NGpMlSH6NHVCOiTeTuTJ",
"refreshToken" : "enOAFkBcxB88FlATUh2m0E5NLLG0y8AojyIH5gItnJXdU6",
"ttl" : 3600
}
]
},
"resume" : {
"loginTokens" : [
{
"when" : ISODate("2014-06-17T17:51:24.637Z"),
"hashedToken" : "uhRZpGdBHnAVKvgBEm7oSWsdflOGRI2YrR9Q21iqjzp+Xc="
}
]
}
},
"username" : "lous"
As you can see from what's above, I need to key off of one of the token values to find the right oauth information to do a possible refresh. On the client side I then do what's shown below, but the problem is that the token returned in validateResult is not the same token that is being stored in the DB, so I have no way to track which session is mine.
Template.login.events({
'submit #login-form': function(e,t) {
e.preventDefault();
var id = t.find('#login-id').value,
password = t.find('#login-password').value;
var req = {id: id, password: password};
Accounts.callLoginMethod({
methodArguments: [req],
validateResult: function (result) {
var token = result.token;
window.localStorage.setItem('token', token);
subscribeToRequests();
$.mobile.changePage('#landingPage', {transition: 'slidefade'});
},
userCallback: function(error) {
if (error) {
console.log("Error: " + error.message);
alert("Login Failure");
}
}
});
return false;
}
});
Why would the token not be the same? Any recommendations on how to address this? Then once I do have the token stored client side, does Meteor provide an out-of-the-box way to test the token's validity? Here's the findUser method I'm using to attempt to do that:
Meteor.methods({
findUser: function(token) {
var user = null;
var hashedToken = Accounts._hashLoginToken(token);
if (this.userId) {
//TODO need user object to include token to do TTL check and reauth if necessary
user = Meteor.users.findOne({_id:this.userId});
var result = refreshUser(user);
if (result.err) {
throw { name: 'System Error', message: 'The following error occurred: ' + result.err
};
}
} else {
throw { name: 'System Error', message: 'No userId available. Please try again.'
};
}
return user;
}
});
In your findUser method, you can call Accounts._getLoginToken(this.connection.id) to get the current login token for the connection. You can then look up the OAuth access token associated with this value.
As for your original question of why result.token on the client is different from what's in the database: I think you're comparing the unhashed token (result.token) to the hashed token stored in the database. If that's the case, you can pass result.token to the server and pass it through Accounts._hashLoginToken before looking it up in the database.
Does that make sense?
Here's how I ended up aligning my OAuth tokens with the Meteor session token.
I created the following Meteor.methods on the server-side and my client just calls the updateToken in the validateResult of my Accounts.callLoginMethod so my oauth tokens can be found by the method #emily describes in her answer.
It calls reauthenticateUser whenever the app starts up or is refreshed and finally, it calls logoutUser when the user logs our or the session timeout expires.
updateToken: function() {
// Update oauth hash token with correct hashed token
var user = Meteor.users.findOne({'_id': this.userId});
var hashedToken = Accounts._getLoginToken(this.connection.id);
// Get last element for OAuth array (safely presuming the last one is the last oauth from current call stack) and update hashedToken
var oauthObj = _.last(user.services.oauth.loginTokens);
Meteor.users.update({'services.oauth.loginTokens': {$elemMatch: {hashedToken: oauthObj.hashedToken}}}, {$set: {'services.oauth.loginTokens.$.hashedToken': hashedToken}});
},
reauthenticateUser: function() {
var user = null;
if (this.userId) {
var hashedToken = Accounts._getLoginToken(this.connection.id);
user = Meteor.users.findOne({$and: [{'_id': this.userId}, {'services.oauth.loginTokens': {$elemMatch: {hashedToken: hashedToken}}}]});
// Get specific oauthTokens (keep in mind multiples per client)
var oauthTokens = _.findWhere(user.services.oauth.loginTokens, {'hashedToken': hashedToken});
var result = refreshUser(this.userId, user.username, oauthTokens);
if (result.err) {
throw { name: 'System Error', message: 'The following error occurred: ' + result.err
};
}
} else {
throw { name: 'System Error', message: 'No userId available. Please try again.'
};
}
return user;
},
logoutUser: function() {
var hashedToken = Accounts._getLoginToken(this.connection.id);
// Remove orphaned Oauth tokens
Meteor.users.update(
{$and: [{'_id': this.userId}, {'services.oauth.loginTokens': {$elemMatch: {hashedToken: hashedToken}}}]},
{$pull: {'services.oauth.loginTokens': {'hashedToken':hashedToken}
}});
return true;
}
Once I had this in place, it was easy for me to update the oauth tokens once they were refreshed or to remove them once the user logged out.
I'm not meteorJS developer, but I'll try to suggest the resolution of problem.
install meteor-cookies using npm install meteor-cookies.
and then:
var initToken = Cookie.get('initToken');
if(!initToken) {
initToken = Accounts._generateStampedLoginToken();
Cookie.set('initToken', initToken, {days: 30});
}
var token = Accounts._hashStampedToken(initToken);
token.accessToken = result.data.access_token;
token.refreshToken = result.data.refresh_token;
token.ttl = result.data.expires_in;
OR:
var token = Cookie.get('token');
if(!token) {
var initToken = Accounts._generateStampedLoginToken();
token = Accounts._hashStampedToken(initToken);
Cookie.set('token', token, {days: 30});
}
token.accessToken = result.data.access_token;
token.refreshToken = result.data.refresh_token;
token.ttl = result.data.expires_in;
maybe there are errors in my additions but I think You've understood the trick. (:

Categories

Resources