build a One Time Password authentication server - node.js

Problem
In our system we have:
Two apps: a backoffice in reactjs and an app for user in react-native
An API (with postgres db)
Hubspot (user informations, phone number, etc.)
We want to add an authentication server to secure our user data and allow user to connect to the mobile app. That server would provide tokens and a link between Hubspot (that carries user informations) and the user in the API db. The db would store only hubspot user id and the api user id and some timestamp. We want to use a One Time Password using text messages.
The workflow would be something like:
the user want to connect to the app (for the first time or not). The app is requesting a phone number.
the phone number is sent to the auth server that checks if it exists in hubspot. If the user phone number exists but nothing yet in the database, that means we need to create a new user (in the auth server database AND in the api). If the user number exists and already in the database there is nothing to do. In both case, a token is generated and the user is able to connect (still need to understand how to do that). If nothing exist in hubspot, the user wouldn’t be able to authenticate in the app.
Questions
Am I going in the right direction? Creating an authentication server, is it a good idea or completely useless? Should we implement our logic directly in the API? The system is about medical information and data should be protected.
Concerning the OTP, what should we send to the user if the phone number actually exists? The auth token or a random string to require the actual token?

the phone number is sent to the auth server that checks if it exists
in hubspot. If the user phone number exists but nothing yet in the
database, that means we need to create a new user (in the auth server
database AND in the api). If the user number exists and already in the
database there is nothing to do. In both case, a token is generated
and the user is able to connect (still need to understand how to do
that). If nothing exist in hubspot, the user wouldn’t be able to
authenticate in the app.
I do not think sending the phone number to the auth server is a good idea, instead you generate a code and save it on some backend server or some backend database and then text the user the same exact code. The reason for saving the code on the backend is to compare it to the one the user provides at some point in the future.
That is a unique identifying piece of information, not a phone number, peoples' phone numbers change all the time.
The user presumably receives the text message, that is the only reason we need the phone number for to send that text message and they can enter that code back into the application.
So the user sends us the correct code and that comes to the backend server. It's then compared on the server and if the user entered the correct code, send them some further identifying token, such as a JSON Web Token that identifies the user for future follow up requests.
This is what it means to be authenticated. Once the user successfully enters the token, we provide a user with a JSON Web Token to specifically identify them and say, hey this user did correctly enter a one time password, here is some identifying information on the user.

Related

What is the most secure way to invite an unregistered user to my app?

I'm working on a React app with an Express backend, with Passport for authentication via JWTs. A registered user needs to be able to send an invitation to someone else who is unregistered, to come use the application. The unregistered user should not be required to register in order to see a subset of our content. THIS IS IMPORTANT - the unregistered user needs to be able to have access to some data that belongs to the registered user and would otherwise be unviewable without being authenticated. I built an invitation model to track these invites, who sent them, who they're being sent to, etc.
What is the best/most secure way to identify this user?
My current guess is to create a unique string and store that in the invitation object and pass that to the unregistered user via email. So they will have a link to our app with ?invite_id=SOME_ID_HERE appended at the end. When they reach our app we will verify that the string matches an invite in our DB.
Is this the best approach? Should I be doing something more secure, maybe a pair of public and private keys? Any advice would be greatly appreciated, thanks!
I think it's best to keep this as a random ID in your database. That way, the users can be removed later. And, if you do associate this new user with that random ID later, you can use an existing profile that you're already storing rather than having them start from scratch.
In other words, create a new ID for this user but set it up so that they can only access things via this URL until they create an account.

Session between REST calls with node.js for mobile

I have to do registration for a mobile app with node.js (express.js) backend. The registration process involves sevaral steps:
1. provide email
2. verify email
3. provide personal details
4. upload photo
For each of these steps there should be a separate call to the server API ( possibly through REST ).
How to keep the session so that the server knows that the consecutive calls come from the same client ? This is a mobile app so cookie based session won't work I think. Could you guide me somehow ? Is using a JWT token the right way to go ?
I'm not an expert but...
So here you need to firstly answear a question:
How much time does user have to create such account? For example, if you won't store information that user had started to create account and server restarted ( for whatever reason. eg error ), you will lose this info. So it would be worth to store this in some db.
You can use redis, mongodb, some sql db or just system files (not recommended ) it's up to you.
Assuming you want to persist such info, you can create REST endpoints.
So for example, you can have entry in MongoDB (which basically stores JSON structures).
NewAccount { id: <unique_id> , email, info, images }
So each endpoint you create will set info in this MongoDB entry.
Example:
1) POST /user/create -> this would create entry in MongodDB
2) PUT /user/create { body: { field: 'email', value: 'p#pp.pl' }}
3) POST /user/create/finish
We have one more question -> how to identify user? You can try to identify it by IP address. If it's mobile app, you have different ways to store info (eg user token) eg:
https://developer.android.com/guide/topics/data/data-storage
As per your step given :
sevaral steps: 1. provide email 2. verify email 3. provide personal details 4. upload photo
1.Register by email and password
Suggestion: You need to ask for email and password.
i) When a user enters the email and password check user exists with email if not then send a verified email and redirect to login.
2. Once User verified. Now user tries to log in.
i) When a user tries to login check email and password is correct or not.
ii) If correct then generate JWT Token on the backend and send back to APP.
ii) Now using JWT Token you can manage the user session on the app.

How to integrate Google or Facebook login with my database?

I want to understand how to integrate auth of Google or Facebook with my database.
I have a login system with email and password, users table and messages table for that represent messages of users.
When someone registers, a new user with userID is created.
When a user login to the system with email and password he gets an auth token,
and for each action the user makes, like POST or GET requests for fetching or creating a new message, he sends the token he got and the system finds the userID by this token, and then finds his own messages.
Now I want to add Google and Facebook login, how should I do it now?
I can get from each of them a token. but the user isn't actually exists in my user table, so when I search the user by his token, I won't get anything, because he is not exists in the user table, and when I want to insert him to this table, I need to fill the password field there but I can't get it from google.
What should be the approach to do thing like this?
Thank you.
When they first login, you can request their email from Facebook or google, the user will give your application access to see their email address.
At this point you could create a new user with that email and add a flag to say they came from facebook/google.
The rest works as normal, they would get a token from your application and so on.
In case they come back and login again, you don't need to register them as they are already in your database.
In case you need extra info from them, (more then just the info you can request from facebook/google) you could redirect them to a special form, for their first login.

How to implement server session validation scenario in MobileFirst 8?

I have a problem with the following scenario using MobileFirst HTTP javascript adapters:
let's say the adapters call 2 methods,
login, that calls a back end service which authenticates the user and also returns a customer_id (input: a username and a password).
retrieveData (protected by security-check) that retrieves sensitive data about a customer by calling a back end service (input: customer_id).
How can we make sure that some client that has credentials to authenticate and have access to retrieveData, will request only data that concern him and not be able to send a request sto retrieveData with a different customer_id from his own? (We assume that this client has tempered with the app and has made it send different customer_id's.)
With MobileFirst 7, after login was successful, we would call setActiveUser setting the returned customer_id as an atttribute of active user or we would call WL.Server.getClientRequest().getSession().setAttribute and again set the customer_id. So when a user called retrieveData, we would take his customer_id input and compare it to the customer_id in his session. If it was different, then they would get an error because they requested data that do not belong to them.
Since MobileFirst 8 does not have a session, how can we prevent this scenario from happening?
In 8.0, "Client Registration Data" is the closest thing to a session.
There are a lot of unknowns about your use case, but I will try to describe the expected behavior is most cases:
Assuming your security check extends UserAuthenticationSecurityCheck, as soon as the user succeeds to login, his user id will be registered in the client registration data on the server. This will map the client to the user in a database.
From that point on, on any adapter you can safely check who is the currently logged-in user by using securityContext.getAuthenticatedUser().
If you want to make sure that a client only accesses data it is allowed to, use this getAuthenticatedUser to check against your database that the requested data belongs to it.
If you really need to store extra custom data in the registration context (the closest thing to a session object) there are APIs in the security check to do so. See RegistrationContext.
In v8.0, the client is able to retrieve information from the backend system because it passed the challenge presented to it, and in return received an access token that enables it to access resources that are protected by a scope, which you define. This is how OAuth works more or less.
Have you read the Authentication Concepts tutorial? https://mobilefirstplatform.ibmcloud.com/tutorials/en/foundation/8.0/authentication-and-security/

How to secure an app built on phone-number registration?

I want to build a mobile app that requires the number of the user to be filled in. After that, the phone number is sent to a server, the server generates a random verification code that corresponds to this phone number. Then, this verification code is sent via SMS to the user. Next, the user sends the verification code back to the server to ensure that he/she has entered his/her real phone number and not anybody's else.
I was wondering how do you really authenticate against the server if you only have a phone number and nothing else? I mean, in the typical scenario you have a username and a password that are checked on the server and if both of them are correct you can have access to the server. But in the case of a phone-number registration, you have only a phone number and if you authenticate with it only, it means that anyone who knows your number or just picks it out, can pretend to be you.
If you send some sort of a unique device ID, that means that you won't be able to use your existing account anymore, for example, if you happen to change your device with a new one.
So, how do you solve this issue?
The pattern is always: client provides proof of something they have, in return they receive an identifying token. In a typical username/password scenario, this means the user proves that they have a secret (username + password), in return they'll typically receive a session cookie. In your case, the user proves that they are in possession of a specific phone, in return you give them a session token or other identifying token. The client holds on to this token and uses it to identify themselves to the server.
You're relying on the principles of the telephone system to make sure that's a uniquely identifying characteristic. You're basing your security on the assumption that only one person can receive messages for a specific phone number at any one time, and that you need to be in physical possession of the phone at the time of login to complete the proof. Of course you require this proof every time the user logs in. You do not let them register once with an SMS-loop, then afterwards you just ask them for their number and let them through.
If a user wishes to log in, they must proof they're in physical possession of the phone in question using the SMS-loop, then they'll receive a token. Period. That's the way it goes. No other way. The client (app) must hold on to the token for as long as it wishes to stay logged in. Obviously, you probably want this to last for quite a while and not require the user to do SMS confirmations all the time.
This obviously brings us to the topic of token theft, which can be a real issue. The token must be kept secret, since it essentially allows proof-less authentication. You may want to think about signing that token using some unique identifier specific to the device it's for, or encrypting it while it's stored on the device or other measures to make sure it can't be nicked from the device while it is stored on it.
As deceze points out, the best way to ensure the comm is safe is to use a temporal token signed with the device id. If the user logs out, changes device or reinstalls the app then they must go through the SMS verification process again to ensure the SIM cards is still in their possession. Keep in mind that the SIM card and device have different udids. To simplify this you can use RingCaptcha SDK on your app to generate the token, verify the user possesses the SIM card and store that token or id temporarily. Use the phone number as an identifier - similar to a username - and the temporal PIN code as the password. That pair plus the token will give you enough security that the device and SIM card are joined.

Resources