CognitoIdentityServiceProvider.signUP() doesn't accept user pool id? - node.js

In the aws-sdk cognito documentation there is a function listed called signUp() that quote "Registers the user in the specified user pool and creates a user name, password, and user attributes." However, there is no parameter for a user pool Id. How exactly does one specify the user pool they want to add to? At first glance it thought maybe it was just missing in the documentation, but I tried adding UserPoolId as a property in the parameters object, to which it responded with an error about an unexpected field. There is also no function parameter to accept the pool id. My only other guess was that maybe the CognitoIdentityServiceProvider object accepted it in its constructor, but that also does not appear to be the case. I am aware that the API also provides the function AdminCreateUser() to add users, but don't want to use it if there's a better way.
documentation here https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/CognitoIdentityServiceProvider.html#signUp-property
Any ideas?

In Amazon Cognito, the User Pool ID is considered to be a sensitive piece of information, and it is used only in Admin API calls. The SignUp API call is not AWS SigV4 Signed, and it is meant to run on the browser side instead of the server side.
From the App Client ID, Cognito implicitly understands which User Pool you are referring to in your code. Hence, you can use the code in the documentation, and users will get added to your User Pool without the User Pool ID being a parameter in the API call.

Specify the App Client Id from the User Pool - not the User Pool Id. Create an App Client on the User Pool if you don't have one yet.
https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-client-apps.html
The App Client Id is not considered secret from the AWS Cognito docs (but of course App Client Secret is - never include that anywhere on the client side). I've scratched out my App Client Id just to not broadcast here.
import {
CognitoIdentityServiceProvider
} from 'aws-sdk'
// make sure to use the same region as your user pool
const cognitoIdentityServiceProvider =
new CognitoIdentityServiceProvider({region: 'us-west-2'})
try {
const signUpResp =
await cognitoIdentityServiceProvider.signUp({
// Not UserPool ID but the ID for the "App Client" you have created on the User Pool
ClientId: '5orf...i67r',
Password: pw,
Username: email // i'm using email address for Username
}
).promise()
console.log(signUpResp)
} catch(e) {
alert(e.message || JSON.stringify(e));
}

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.

JWT authentication with two different services

We have a service architecture that currently only supports client authentication. A Java service based on spring boot and spring security issues long lived JWT based on tenants for other services to authenticate against each other. For example a render service needs to get templates from the template service.
We now want to build a user service with node.js that issues short lived tokens for users to also access some of those services and only access the resource visible to the user. For example the user wants to see only their templates in a list.
My question is: what do I need to watch out for when implementing the /auth resource on the user service? I have managed to issue a JWT with the required information and obviously the same secret in the user service to access the template service. But I'm not sure if it is secure enough. I had to add a random JID to the user JWT to get it accepted by the template service (which is also implemented with spring boot).
Is there a security issue I need to watch out for? Is this approach naiive?
This is my javascript code that issues the JWT:
const jwt = require('jwt-simple');
const secret = require('../config').jwtSecret;
const jti = require('../config').jti;
// payload contains userId and roles the user has
const encode = ({ payload, expiresInMinutes, tenantId}) => {
const now = new Date();
payload.jti = jti; // this is a UUID - spring security will otherwise not accept the JWT
payload.client_id = tenantId; // this is required by the template service which supports tenants identified through their clientId
const expiresAt = new Date(now.getTime() + expiresInMinutes * 60000);
payload.expiresAt = expiresAt;
return jwt.encode(payload, secret);
};
I think of adding some type information to the user JWT so that those java services that do not allow any User access can directly deny access for all user JWTs. Or maybe I can use the JTI here? Will research how spring boot handles that. I'll probably also have to add #Secured with a role distinction to all the services that allow user access to only some resources.
But those are technical details. My concern really is that I am unsure about wether the entire concept of using JWTs issued from different sources is secure enough or what I have to do in the user service to make it so.
Yeah your concept is right since you are the owner of jwt that means only you can write the jwt, others can read it but can not modify it.
So your userservice will create the token with certain information like userid and another service will decode that jwt fetch userid and validate that userid

How often should I get a new service sid of twillio?

When using twillio, how often should the service sid be created and create a new services? I see 3 options. There might be more options thought.
Get the service sid/create a new service and store it in the db, then never get a new one.
Get the service sid/create a new service every time the backend server starts/runs (I'm using node/express)
Get the service sid/create a new service whenever using the twillio client is used
Here's the code:
let serviceSid = '';
async function init() {
const service = await client.verify.services.create({
friendlyName: 'someName'
});
serviceSid = service.sid;
}
Also, what's the purpose of it, if you already have an account sid?
Your Twilio ACCOUNT SID together width AUTH TOKEN has to do with your overall Twilio account. It gives you access to the entire Twilio API (Verify is just a part of it).
const accountSid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
const authToken = 'your_auth_token';
const client = require('twilio')(accountSid, authToken);
To use the Twilio Verify product (or service if you wish) you will need to create at least one "verification service". You can do it in the Twilio console or by making API requests.
When you create a verification service you get that SID which starts with "VA" and it will be used in a verification code for example.
client.verify.services('VAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX')
.verifications
.create({to: '+15017122661', channel: 'sms'})
.then(verification => console.log(verification.sid));
If let's say you have more than one application using Verify you'll want to create a verification service for each application.
Also, maybe the verification message template is different or maybe you expect different lengths for the verification code, etc. then you need separate verification services hence different VA SIDs.
So from your options in your question I would go with number 1 per distinct application. If you only have one app then I would get one verification service per environment (one for dev, one for QA, one for production, etc.).
Also, I would create Twilio sub-accounts for each app + environment and use them instead of the Twilio master account.

Using AWS Amplify to authenticate Google Sign In - federatedSignin returns null?

I'm trying to use AWS Amplify to support email / password and Google authentication. Now, I want to store the details from Google into my user pool in AWS. I don't understand the flow here - there are many blog posts I read but most of them are just confusing.
Here's what I tried to do:
// gapi and Amplify included
googleSigninCallback(googleUser => {
const googleResponse = googleUser.getAuthResponse();
const profile = googleUser.getBasicProfile();
const name = profile.getName();
const email = profile.getEmail();
Amplify.Auth.federatedSignin('google', googleResponse, {email, name})
.then(response => { console.log(response); }) // is always null
.catch(err => console.log(err));
});
In DevTools I have the following error in the request in Network Tab:
{"__type":"NotAuthorizedException","message":"Unauthenticated access
is not supported for this identity pool."}
Why should I enable unauthenticated access to this pool? I don't want to.
Am I doing this right? Is it even possible or is it a good practice to store Google User details into the AWS User Pool? If it's not a good practice, then what is?
Also, if I want to ask user for further details not provided by Google in the app and store them, how to do it if we can't store the user in User Pool?
First make sure your identity pool and user pool are setup for google authentication.
Then federatedSignIn has a capital last I.
And finally just change your second param in the call to federatedSignIn as follows:
Amplify.Auth.federatedSignIn('google', {
token: googleResponse.id_token,
expires_at: googleResponse.expires_at
}, {email, name})...

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.

Resources