How to implement server session validation scenario in MobileFirst 8? - security

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/

Related

Can I create a quickbooks invoice on behalf of another user, in their account?

I am following Intuit's oAuth authentication guide in order to log users in through Quickbooks and get access/refresh tokens in order to make API calls. We make API calls in node through the node-quickbooks SDK.
I can successfully log users in through Quickbooks and exchange codes I receive for access and refresh tokens, and I can even make API calls to create invoices successfully.
The problem is, even when I use the tokens of the user I've authenticated to make API calls, the invoice is created in our Quickbooks company instead of theirs.
Is it possible to create invoices in the Quickbooks account of the other user? If not, what's the point of getting access and refresh tokens for them in the first place? For what it's worth, this is all being done in the Quickbooks developer sandbox (but with two separate accounts).
I'm quite confused as to what the methodology is supposed to be here, and any guidance would be very much appreciated -- or even just a reassurance that this is possible.
Thank you!
The QuickBooks instance that's acted on is determined by the Realm ID parameter. The Realm ID is captured when a QuickBooks Online account is selected during the authorization flow.
If we could call your Quickbooks company "Company A" and the one you're trying to create invoices in "Company B", I'd say it sounds like Company A's Realm ID is being logged and passed in subsequent requests instead of Company B's. This could be caused by things by hard-coding Company A's Realm ID and using that for the create invoices requests, selecting the wrong account during the authorization process, or something trickier like a bug in the SDK you're using.
I'd start by getting Company A and B's Company ID, which is what Intuit calls the Realm ID when you access it from the UI. You can do that while logged into a sandbox or production account by pressing Ctrl + Alt + ? in Windows or Control + Option + ? in macOS. Then you can verify the correct Realm ID is being used in the create invoice requests.
If the requests are using the value captured during authentication (as they should be), then you can —in the SDK code— log the Realm ID that's being captured during authorization and verify it's the right one for the company you selected during the OAuth flow.

Should I use a custom JWT claim or query the db for authorization?

Let's say I have build a REST API for an application like WhatsApp and I got an endpoint like POST chats/groups/{group-id}/messages which adds a new chat message from my requestBody (This is just an example).
Before my API allow this request, it has to ensure that the request comes from a group member. So with that, I want to make sure that only group members are allowed to post new messages.
Since I didn't want to query the database for group membership, everytime I post a message to the group, I thought about adding custom claims to the JWT.
Could look like this
{
...
"groupMemberships": ["Some fancy UUID", "This one is a fancy UUID as well"],
...
}
With that I always could compare if the requester contains the target group in it's groupMembership array via the UUID. Sounds fine until now...
But what happens when the user is kicked out from the group ? Since the JWT is valid for e.g. 2 weeks, the requester could still send messages to the group, which is creepy and weird at the same time. A possible solution could be to blacklist the JWT but that's not really what I want, since that steals the stateless characteristic and lets me hit the DB anyway.
How could someone solve this problem ? Is it maybe okay to query the db for membership checks ?
One risk with your approach is that for some users the token might be quite big (what if you are part of many groups?). In general you want to keep your tokens small.
Another option is o let the API that receives the access token, do a lookup against your database as this is part of the authorization phase. By doing this, you can have long lived access tokens and the user can change groups as you like.
Alternatively, if you do add the claim to the token, you can then make the access token short lived, like 5 minutes, and have a long lived refresh token to renew and update the claims in the access token.

How do i authenticate my api (node app) when being accessed by my UI?

I've looked at various approaches to this but I'm yet to find one that is perfect for my set up.
I have a UI that calls the api to present data to a user - the UI doesn't require someone to login and i don't want to authenticate every user. What i'm trying to do is simply protect the api because with the url to the api, anyone will be able to access the data.
In my mind, i can create a password/ apikey of some sort and store that as an environment variable that is sent from the UI to the API whenever a request is made. On the API, that apikey/password is validated before allowing access to the api.
Does this sound wise? Would you suggest something else? Have i missed anything. All thoughts are welcome.
The solution sounds good to me. You can do something like this:
back-end: create a new REST endpoint (something like /api/get-token) in your Node.JS application which generates a token (or ID), saves it locally (maybe into a DBMS) and returns it as response. Then, in every endpoint you need to protect, you extract the token from the request and, before sending any "private" data, you check if the supplied token is valid, or not.
front-end: as soon as your application is loaded, you send a request to the newly created REST endpoint and store the given token locally (localStorage should be fine). Then, every time the UI needs to access "private" data, you simply supply the claim within the request.
The implementation should be pretty straight forward.

build a One Time Password authentication server

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.

How to securely setExternalUserId() in OneSignal?

I'm setting up OneSignal on my website.
As far as I can see, there are 2 ways I can associate a push subscription with my user ID:
I can call OneSignal.getUserId(), which returns a UUID, and make an authenticated call to my web server to associate this UUID with my logged in user on my server
I can call setExternalUserId() to send the logged in user ID and associate it with the subscription on OneSignal servers
The first option is perfectly secure, as one could only hijack my client-side code to send an invalid subscription ID (or another valid subscription ID they have created), which is not a big deal.
The second option though, feels totally unsecure: anyone could hijack the client-side code to send any valid user ID and associate it with its subscription, and therefore receive notifications on behalf of another user.
Is there a way to securely use setExternalUserId() while preventing a user from associating their subscription with another user?
The only secure scenario I can think of is if my users had UUIDs as well, instead of sequential IDs, and these UUIDs were kept secret (i.e. never exposed publicly on the website).
Any other scenario I can think of sounds plain insecure.
Did I miss something?

Resources