How to map storage.userId and idToken in Google Assistant actionSdk - node.js

Hi, We have created a bot where user interact with the bot. so our
bot has two type of queries static and dynamic queries. if user asks
static query we don't ask for SIGN IN but if user ask for dynamic
query than we ask user to SIGN IN and redirect to SIGN IN page than
we ask mobile no and dob and send OTP to user and than verify the
user and send back a token in response which we get in further
request. The problem is let use suppose user came on our our bot and
asked static query so i store the chat of user to my db initially I
create a userId for user like this conv.user.storage.userId =
'unique_id' and store this unique_id in my db to identify the user
next time and send back. Next time same bot get same userId and keep
updating my chat in db for this userId. Now the problem comes when
users asks a dynamic query than I have to redirect user to our
account linking page. user is redirectd to account linking page and
user fill his mobile no. and DOb and we send a otp to usermobile.
When our SendOtp api is called I create a userId and store in
databse but I want the userId which I set before for static queries
(conv.user.storeage.userId) this one. How can I get this Id. Can we
pass this userId as params to when to ask for SIGN In (conv.ask(new
SignIn('To get your account details'))) and get this static query
userId in my SendOtp API. I need same ID to send further to update
chat.

When you create a SignIn request, you cannot provide any additional data in that request. However, you are able to provide this behavior when your Action gets a callback. You will get a Sign In event that can be set to when the user signs in. At that point you can add your additional logic to connect the user's account on your backend with the account ID in userStorage.
Here's an example of what it may look like.
app.handle('linkAccount', async conv => {
let payload = conv.headers.authorization;
if (payload) {
// Perform account merge
await performAccountMerge(payload.email, conv.user.storage.userId)
}
});
async function performAccountMerge(authorizedEmail, savedUserId) {
await saveInDatabaseForEmail(authorizedEmail, savedUserId)
}

Related

how to store sub account auth tokens twilio

I am using the MERN stack for an app im building. In this app im using twilio. I have decided to use twilio sub-accounts. The way this works is I create a MASTER twilio account that give me an accountSid and authToken.
I can store these as ENV variables in Heroku when I want to deploy, and anytime I need to access these ENV vars I can just use the process.env.AUTH_TOKEN in my Node.js server.
Every customer that signs up for my app is going have their own subaccount that is a child of my MASTER account. When this sub account is created, It will give that user their own accountSid and authToken.
This is where my issue stands, Do I need to store each users authToken on Heroku as an ENV variable?
ex..
process.env.USER_1_AUTH_TOKEN
process.env.USER_2_AUTH_TOKEN
process.env.USER_3_AUTH_TOKEN
process.env.USER_4_AUTH_TOKEN
process.env.USER_5_AUTH_TOKEN
I dont think this will work because how will I know which users auth token belongs to them?
Currently in Development I am storing the sub-account authToken directly on the user object, this user object is visible to the client side of the app and im worried that exposing the auth token directly to the client could result in some sort of hack?
Is it safe to store the auth token on the user object directly in mongodb and whenever my react app needs the user, just send the user object without the auth token?
Should I create a auth-token Model, and store a document in the auth-token model containing the auth-token and user_id and everytime I need the auth token just query mongodb for the auth-token with user_id as a parameter?
How does one go about storing say 100,000 of these auth-tokens?
I'm worried about security and twilio docs dont say much about this...
According to the Subaccounts API documentation you can use the Twilio rest API to instantiate a subaccount and assign that subaccount a friendly name that is easy to retrieve.
client.api.v2010.accounts
.create({friendlyName: 'Submarine'})
.then(account => console.log(account.sid));
This returns an object that contains a lot of information but it has a unique SID for that is associated to that new number/subaccount. That object is then also linked back to your main account via the owner_account_sid which is attached to that object.
Twilio provides functionality in the subaccount API to allow you to retrieve a subaccounts data based on the friendly name like so...
client.api.v2010.accounts
.list({friendlyName: 'MySubaccount', limit: 20})
.then(accounts => accounts.forEach(a => console.log(a.sid)));
So what you should be doing is as follows...
Create a naming convention within your system that can be used to form friendly names to assign to subaccounts.
Use the API to create a new subaccount with the Twilio API under the friendly naming convention you've developed.
Anytime you want to make a call, text, or other supported action from the Twilio API first perform an API action to look up the SID of that account by the friendly name.
Grab the sid the friendly name returns and attach it to your client object like so require('twilio')(accountSid, authToken, { accountSid: subaccountSid });
Perform your action through that client using the subaccount Sid that is now attached.
I would like to add some additional info for anyone using twilio subaccounts.
So what I did was create a master account with twilio. This gives you an accountSid and authToken.
These you can store in Heroku under config vars.
When you create your login function for a user via passport login, google-passport or some custom login you create, make your api call to create a subaccount. ( Like when you buy numbers, you buy them under your main account and drill them to your sub accounts) When this is created ONLY add the sub account accountSid to your user object. the sub accountSid is worthless without the auth-token and since you need to make an api call with your env vars your sub account auth tokens are safely stored in twilio.
Now whenever you need to make twilio api calls, say for sending a message or making a phone call etc... first make a call to this endpoint
client.api.v2010.accounts(subActServiceSid)
.fetch()
.then(account => account.authToken);
const accountSid = keys.accountSid // master accountSid
const authToken = keys.authToken // master authToken
// these will be stored in heroku
const listChatMessages = async (req, res) => {
const { subActServiceSid } = req.user // getting sub accountSid from user object
const subActAuthToken = client.api.v2010.accounts(subActServiceSid)
.fetch()
.then(account => account.authToken);
const subClient = require('twilio')(subActServiceSid, subActAuthToken)
await subClient.messages.list({ // make all the api calls your heart desires
from: chat.phone
})
.then( messages => messages.forEach((m) => { console.log("message", m})
this will contain a JSON object with the sub accounts authToken. You can then use this authToken for the API call. No need to worry about storing 100,000 users authTokens somewhere.... If this is still confusing message me.

Gmail API userId use cases in Gmail NodeJs client?

How do I use the userId property outside the cases where I would use the special value 'me'?
From what I understand, when you use 'me', is when you've authenticated as the end user.
But when you're not authenticated as the end user, you can't use 'me' nor can you use any other value because you don't have permissions to perform a given request.
I'm trying to understand how can I perform an action on behalf of an authenticated user on my app without using the value 'me' in the userId field?
Example using Gmail nodeJs client:
const googleClient = new google.auth.OAuth2(client_id, client_secret, redirect_uri);
async function getUnreadEmailsFrom(userID) {
let gmail = google.gmail({ version: 'v1', auth: googleClient });
/* Here on the line below, I'd like to use the email or ID of an already authenticated user in order to perform a given action.
But the only way I understand that I am able to perform any action is by loading the token of the user and saving it via
googleClient.setCredentials(userToken)
and then using the special value 'me' inside the userId propery.
*/
let response = await gmail.users.messages.list({userId: 'me', q: 'is:unread', maxResults: 500 });
return response.data;
}
Short answer:
The only allowed values for userId are me and the authenticated (or impersonated) user email address.
Explanation:
The only way to access other users' data is to grant domain-wide authority to a service account and use that to impersonate the target user whose data you want to access (this user should be in the same domain).
Nevertheless, the target user email is specified when impersonating it (see Preparing to make an authorized API call), that is, before calling the API.
Later, when calling the API, the special value me would correspond to the impersonated user, and the only accepted values would be me and the impersonated user email. Any other value would result in error (since the service account would be acting as the impersonated user, and would only be able to access the impersonated user's data).
Therefore, the only alternative to me is the authenticated user email address, but of course you'd get the same data.
Domain-wide delegation example:
creds = service_account.Credentials.from_service_account_file('credentials.json', scopes=SCOPES)
creds = creds.with_subject('your_target_user#email.com')
service = build('gmail', 'v1', credentials=creds)
messages = service.users().messages().list(userId="me").execute()

Azure App Service Easy Auth

I have an Azure mobile backend set up with easy auth for facebook and google authentication and it works as expected.
Every time a user signs in with any of the supported providers, I want to be able to verify if it's a new user or not (e-mail not in database), without make an additional call from client. Is this possible?
Every time a user signs in with any of the supported providers, I want to be able to verify if it's a new user or not (e-mail not in database), without make an additional call from client. Is this possible?
As far as I know, we couldn't directly verify if it's a new user or not.
No matter you use server flow or client flow, easy auth will just return access token for the client to access the mobile backend resources, it will not check the user is new or old.
If you want to achieve this requirement, you need write your own logic.
You could write codes after the user login successfully.
For example, facebook login.
If you the use have login successfully,you could call GetAppServiceIdentityAsync extension method to get the login credentials, which include the access token needed to make requests against the Facebook Graph API.
// Get the credentials for the logged-in user.
var credentials =
await this.User
.GetAppServiceIdentityAsync<FacebookCredentials>(this.Request);
if (credentials.Provider == "Facebook")
{
// Create a query string with the Facebook access token.
var fbRequestUrl = "https://graph.facebook.com/me/feed?access_token="
+ credentials.AccessToken;
// Create an HttpClient request.
var client = new System.Net.Http.HttpClient();
// Request the current user info from Facebook.
var resp = await client.GetAsync(fbRequestUrl);
resp.EnsureSuccessStatusCode();
// Do something here with the Facebook user information.
var fbInfo = await resp.Content.ReadAsStringAsync();
}
Then you could check the database according to the user information.
More details about how to get user information in server side, you could refer to How to: Retrieve authenticated user information.

Auth0 - enriching data with user information

I need my API to return objects that contain some user info. For example:
api/comment/123 needs to return:
{
id: 123,
author: {
id: 'googleblahblah|123456789',
name: 'James Bond'
}
}
Normally I would just join the user and the comment table, though in this case I can't. My app's database stores the user id, though the name (and other user stuff) is stored in Auth0.
Obviously making an API call to Auth0 to 'enrich' objects on every API call is not plausible.
Do I cache all / some some user info on my app server? Have only the user ID in the API result and let the client enrich the data?
How do people handle this?
I do not think there is an ultimate solution for this problem.
What I did was creating a user table with user id and user name in my own database. Whenever somebody logs via Auth0 in I would create or update the logged-in user information in that table with the OAuth token information.
After that you could join the tables as you stated.

How to get the user name using a Microsoft user id?

Am working on a windows store javascript application. I have used the microsoft login authentication from azure as follows.
client.login("microsoftaccount").done(function (results) {;
userId = results.userId;
refreshTodoItems();
var message = "You are now logged in as: " + userId;
var dialog = new Windows.UI.Popups.MessageDialog(message);
dialog.showAsync().done(complete);
}
Am able to retreive the userid such as "Microsoftaccount:c2892313bla...."
How am I supposed to retreive the associated UserName for that Microsoft account ID?
When you're logged on, on any scripts on the server side you can query for the identities of the user (via the user.getIdentities() function), which will give you an object with access tokens which you can use to talk to the authentication providers. The post at http://blogs.msdn.com/b/carlosfigueira/archive/2012/10/25/getting-user-information-on-azure-mobile-services.aspx has an example on how to get the user name for MS account (and other providers as well).

Resources