How to securely setExternalUserId() in OneSignal? - security

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?

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.

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.

Personalized web push notifications

I want to send web push notifications to registered users, are there any best practices on how to implement the cases when multiple users have access to the same device and one should not see the message of another user.
Thanks in advance.
A web push notification subscription is tied to the browser, not the device.
What you need to do is, map this id with your registered user when he logs in from a particular browser. Also, you need to remove the subscription id mapping with any other users in the system.
In the case of multiple users using the same browser, the above logic will make sure that at a time, a particular browser subscription id is linked only to a single user.
And when you want to send a notification to a registered user, you can retrieve all push subscription IDs linked to this user in your database, and trigger notifications to those subscription IDs.
And don't forget to unmap a subscription id when the user logs out from a browser. Otherwise, he will continue to receive all notifications even if he has logged out.

Dedicated Services Account and Embedded Sending Experience

We are using the EnvelopeView: CreateSender endpoint on the server side and are authenticated under a service account we have dedicated for this process. Ultimately, we send a URL such as https://demo.docusign.net/Member/StartInSession.aspx?StartConsole=1&t=<GUID>&DocuEnvelope=<ENVELOPEID>&send=1 back to the end user to pick the signers, and populate tags.
All works fantastically, however, we were hoping to make it so the user can only see and populate the information for this single document. Currently, once the user clicks the link they are essentially authenticated as our backend service account and if they open another tab in their browser and go to (https://demo.docusign.net) they can see all documents and even change the password of the account if they wanted.
Is there a way to restrict this in any way? Would the experience be different if purchased an “API” account not tried to use an actual user account on the backend? Yes, we know about OAuth, but we don’t really want to impersonate the sender and prefer to keep a dedicated service account.
An "API" account would give you the same issues as dedicating one of your current users as a "Services Account," so I don't think that's a solution.
Instead, I suggest that you move all of the functionality that's needed upstream into your app. That way you will not need to present the Sender view to your users.
Your app can enable your users to:
choose who the envelope will be sent to
choose/edit the email messages, etc
choose the documents that will be sent
etc
If you have preset templates that include the document tabs/fields for the signers then there is no reason for the sender to deal with the sending screen for picking the tab/field locations on the documents.
This type of app will also give a smoother user experience to your users since they'll stay in your app rather than bouncing over to DocuSign for part of the task.

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/

Resources