How to determine if FCM token is from the same device? - firebase-cloud-messaging

Question: On a server side, given a Firebase Cloud Messaging Token (only the token), is there a way to determine that I already have a token for this specific device?
I got 3 tokens from my device, that all have the same prefix (before the colon)
eWckfbcqTjC9Nxm_BT8alU:APA91bHjsrbm27Qrm...
eWckfbcqTjC9Nxm_BT8alU:APA91bH1_COORkdVi...
eWckfbcqTjC9Nxm_BT8alU:APA91bGleAJmFgq4F...
Tokens from different device have completely different prefix.
Is it safe to assume, that if the prefix is the same, then the device is the same?
Situation: I have a method that accepts a CompanyID and a FCM Token to be bound to the company. Problem is, the app sends a new token rather frequently while deleting the old one only on app's side.
If I just add this token (insert into) to the DB, I'll get lots of FCM error messages while sending push notifications (NotRegistered in old version and Requested entity was not found in the new version).
But if I replace the token (update ... set Token = NewToken where CompanyID = CompanyID), it will make another device (that has logged in the same company account) unable to get notifications anymore.
I'm somewhat OK with the first solution, but it will result in 90% dead (but I don't know that on the server side) \ 10% alive tokens for any CompanyID in the database in just over a month.
The idea is to check all the tokens for the given CompanyID, determine if any of them shares the same device with the recieved token and if it is, replace it. Otherwise - add new.

Related

How to manage updates to FCM push tokens?

I am wondering when in an app lifecycle to update the FCM registration token. I am using Firebase React native.
Currently, I send the FCM token to my backend:
on every app start
in onRefreshToken
sign in/out actions (to associate a user with the token)
I am wondering whether the above list is comprehensive and whether it contains extraneous update hooks (for instance, I am not certain that updating on every app start is necessary).
Main concerns revolve around:
what happens if the device loses access to the internet in onRefreshToken and the backend fails to be updated about the token refresh?
what happens if the FCM token gets refreshed when the app is not running? (and, hence, onRefreshToken is not invoked?
In summary, what is the officially recommended way to notify backend of updates to the FCM tokens?
because of the complexity of this and the difference depending on the application I have never seen an official recommendation, but a few things to add:
store the token on the device (e. g. shared preferences) to make sure you always use the latest or ask for the current one each time you need it
if it is critical you can store the state after an updated token and re-try more often if it has not been successfully transmitted.
on every app start is usually a good solution as fallback because many things can happen
consider logout without internet or uninstall. Here you will not remove the token on the server, so the next user could get the message without measures against that.
implement an update-process on the server to handle error-responses

Generating a new client secret

Is there a way to change the OAuth2 client secret for our Google app without changing the client ID?
I would like to change the client secret as a security best practice (e.g. when one of our production sys admins leaves the company) without having to get all our clients to re-authorize our app.
All I've found on this forum is how to generate client IDs and secrets for new applications. From what I can see, the only option is to generate a new client ID and secret together, meaning any authorizations obtained with the old client ID are effectively useless.
Client id and Client secret are a pair, together they are used to create the Refresh token and access tokens that allow your application to access a users data. If you where to only change the client secret then the refresh token and access token generated wouldn't match the old one. But any way you can't just change one.
You can create a new client id and Client secret pair for your application and then delete the old one. But the draw back to this will be that any one that had previously given your application access to there data will be forced to reauthenticate because there current refresh token will no longer work.
While I applaud your sense of security and desire to protect your customers data. There is a fine line between annoying customers and protecting them. I wonder how big of a chance there is that this person actually stole a bunch of refresh tokens as well as the client id and Client secret for your application? I also wonder what kind of access your application has and what the damage your former employee could do with the information they may or may not have stolen. Will it be worth it for them to create a new application to use the refresh token and application credentials?
You need to judge if its worth bothering your customers and forcing them to reauthenticate your application every time someone leaves the company.
Josh from the AdWords team directed me to the "Return to original console" link in the bottom right corner. In that version of the console you are able to reset client secrets.
See https://groups.google.com/forum/#!topic/adwords-api/twf3O3fg1oA for the cross posting.

Using Sessions vs Tokens for API authentication

I have built a simple test API for a CakePHP application that will let a user login from a mobile device (or any device for that matter) and get a JSON response. This API could be used for a mobile app built in PhoneGap.
The login method looks like so:
public function login()
{
if($this->request->is('post'))
{
// Use custom method in Model to find record with password params
$findUser = $this->User->findUser(
$_POST['username_or_email'],
AuthComponent::password($_POST['password'])
);
// If a user exists and matches params
if($findUser)
{
$this->User->id = $findUser['User']['id'];
$this->autoRender = false;
$this->response->type('json');
$this->response->body(json_encode(array('authenticated'=>true,'message'=>__('You have been logged in successfully'))));
}
else
{
$this->autoRender = false;
$this->response->type('json');
$this->response->body(json_encode(array('authenticated'=>false,'message'=>__('Username or password is incorrect'))));
}
}
else
{
$this->autoRender = false;
$this->response->type('json');
$this->response->body(json_encode(array('message'=>'GET request not allowed!')));
}
}
The mobile device (or any API user) can send their login details and then they get the request as JSON as true or false for authenticated. This boolean is NOT used to give the user access, it instead tells the mobile app if they can see certain screens and they ONLY get the data or can send data if the session exists!
As just stated, they are also actually logged into the API itself on the device so if they visit the website directly (from that device) they will have a session and see the same response for the JSON.
So essentially a user remains logged in for the duration of the session on the device they communicated with the server on. This is different to a token which would need to be passed for every request, where as in this example they have a session.
Now the questions...
Is it bad practice for the user to be 'actually' logged into the API
with a session like shown above? It seems like the most secure way to handle authentication for a device as it's using the same logic as the direct web root.
I've seen some APIs use access tokens instead which I've also
implemented (user gets their token returned instead of the boolean
and no session is created). But from what I can tell, this seems
like more work as then I need to check for the access token against
a user record every time a request is made.
edit
For the sake of clarity, I am not a supporter of REST, I AM a supporter of RESTful/RESTlike services. If you look at all of the API's on the internet, very few actually stick to one standard. Whatever scheme you choose will depend on your specific problem-space. Just try to be secure and use intuitive design choices (ie dont name a service "cats" if it returns info about "dogs")
end edit
It is good practice in RESTful API's to manage some form of session/tokenizing scheme. Really the ideal (at least in my opinion, there are many schools of thought on this problem) setup involves rolling tokens.
If you are at all concerned with the security of your API, then permissions should be managed out of your database layer. Yes, this creates a bottleneck, BUT THAT IS ACTUALLY A GOOD THING. Needing to hit the database every single time to validate a client's token adds an extra step in the entire process. This slows down the API, which is actually desireable in a secure system. You don't want a malicious individual to be able to hit your API 3000 times a second, you want their requests to hang for a (somewhat) sizeable fraction of a second.
This is similar to MD5 hashing algorithms. Many of them recalculate the hash a few hundred times, with random pauses in between. This helps to keep a malicious client from attempting to brute force a password (by making it take more time to test each variation of the password string). The same applies to your API.
The other benefit, is that if you DO have a malicious user trying to log in over and over again, if you are managing them from the database layer, then you can red flag their IP Address/username/what-have-you and just drop their requests at step 1.
Anyway, for a suggested process (with rolling tokens, you can cut out parts of this if it seems overkill, but this is hella secure):
User hits a 'login' service, this requires a username/password, and returns two tokens, a Private Access Token and a Public Request Token (the server stores these tokens in the db).
The client stores these Tokens in a secure place
User accesses another endpoint to push/pull some data
Request includes a timestamp
Request includes the Public Request Token
Request includes an Access Token=> This token should be a MD5 hash of the string resulting from concatenating the timestamp string to the end of the Private Access Token string
The server takes the Public Request Token, uses that to lookup the Private Access Token that was stored
The server takes that Private Access Token, and concatenates on the Timestamp String, it then takes the MD5 of this string
If the new Access Token matches the one that the client sent the server, HURRAY, this client is validated, so push/pull the data
(Optional) The server generates new tokens on every request, and returns them to the client. This way every transaction invalidates the old tokens, and if there was some kind of man-in-the-middle attack occurring, if the VALID user has already completed their request, the malicious user now has invalid tokens and can't start messing with your API. This scheme tries to ensure that a malicious user can not expect to intercept a single communication between the server and the client, and still gain access to the system. If they do, then the REAL user should immediately get invalidated tokens. Which should then trigger their API client to hit the 'login' service AGAIN, getting new valid tokens. This once again kicks the malicious user out of the system.
This scheme is not 100% secure, no user access system ever will be. It can be made more secure by adding expiration dates on tokens. This scheme also has the added benefit that you can assign specific permissions to users/tokens (ie Read-Only access, only certain End-Points can be seen, etc)
This is not the only way you can do things, I would look up other Authentication Schemes and take what you want from each of them (OAUTH is a good place to start, then I'd look at Facebook/Twitter/Instagram)
Make your app login everytime, but not with login-pass pair as Swayok lastly suggested. When you login, server generates a token and returns it back to the client. Client then uses this token whenever it makes a request. On each request, server checks whether the token is valid and if so, executes the request.
This is very similar to how sessions work in that, server side frameworks manage it internally and these tokens expire from time to time. However, as Swayok rightuflly pointed out, you don't want session mainly because you're RESTful API should have no state. You get the same utility without storing any user specific data regarding user and logging user in with every request.
Here's a good article on this, or you can try the Facebook Graph API explorer to see it in action
Restful API restricts using sessions and saving system state at all. Each request must log-in user.
Access tokes are great but also require additional handling.
The easiest way is to send authorisation data via HTTP Basic Auth ("Authorization" HTTP header)
http://www.httpwatch.com/httpgallery/authentication/
Mobile Applications can easily do that and it is easy to add this header for each request to API.
On server side:
$username = env('PHP_AUTH_USER');
$password = env('PHP_AUTH_PW');
And process user log-in with this data in ApiAppController->beforeFilter()
To answer your questions
Its not a bad practice as long as you close their session on app close and recreate it when needed. it is same as if they were logged in on a browser they would know and have facility to log out however the same should be available on the app as well otherwise they might have closed the app but not actually ended their session. You can handle this in many ways by asking them to log out automatic checking when they close app
Tokens are an enhanced way of doing the above however you have to consider how secure the token is when transmitted and server need to verify the token on each request. You have said that it seems like more work so yes its more work and if you have time or money constrains and looking for an answer to say if the session style would harm your application in future it wont as long as you are in control of session and not leaving user without ending the session. If you have time then implement tokens and you would like that.

AppEngine Channel API - Best way to check if a channel is still open (server side)

I have built a social network/dating type application on the AppEngine and am currently in the process of adding a chat built on top of the Channel API. However, the problem that I have is that users may reload or navigate to new pages while the chat is going on (as they can in Facebook). This means that the server doesn't easily know if it should generate a new channel ID token for a given client, or if a given client has already been assigned a channel token.
It would be extremely useful if there were a way to check (server side) if a particular client already has a channel open. For example, if I assign a client "Jack" a channel ID of "Jack-Jan-21-2010", then I would like to be able to check on the server side if there is already a channel open associated with the ID "Jack-Jan-21-2010". This can be (sort of) tracked on the client side by watching for an onerror() and onclose() callback, but I can't see anything server-side that allows me to just check if a channel associated with a given ID is already open.
Does anyone know an intelligent way to check (server side) if a channel has already been opened, while using the AppEngine Channel API?
Part 1: Solving your problem
See Part 2 below if you really need to track client connections, but I'm not sure from your question if what you're asking for will solve your problem.
Let me see if I can echo your problem back: you're writing a chat app, but it's for a site which isn't fully AJAX (in the way that, say, gmail is); the site contains page navigation where you may need to re-set up your channel after the user clicks on a link to another page. When the user navigates, the new page is rendered, and you want to avoid getting a new token at that point; you want to reuse the existing token and channel with the same client-id.
If that's correct, I have two alternate solutions, one easy but with not-great user experience, one trickier but with a much smoother end result.
Preserve the token in a cookie. When you re-render your page, just use the token from the cookie instead of calling channel.create_channel again. When the token expires you'll get an onerror callback just like if the user had stayed on the original page; at this point, call channel.create_channel again. The problem with this is that re-connection can be slow (up to 10 seconds or more in bad cases) because of the nature of Comet connections.
Wrap your entire site that's not chat-related in an iframe. Put your channel creation code and UI in the outer iframe. This way you don't have to re-connect every time the user navigates. This avoids the downtime on navigation. Note that orkut uses this technique, with floating divs, as a small amount of Firebug investigation will reveal.
Part 2: Your feature request
If it turns out I'm misunderstanding and you really do need to track client connections:
There's not a built-in way to check if a client is connected to a channel identified by a client-id now.
However, I am working right now on adding "presence" (in the chat sense) so that your app can register to get a post when a client connects to or disconnects from a channel created with a given client id. You also might be able to "probe" presence, to query whether a given client id is connected or not (still working on the details of this part).
Note that this won't be token-based, but rather client-id based.
I don't have a definite release date for this yet but as I said I'm actively working on it right now.
In the meantime, you could use a heartbeat HTTP request from your client back to your app that says, "hey, I'm still here" every minute or so. You'll need to have some sort of task that runs every, say, 2 minutes and marks any clients that haven't checked in as inactive, and you'll need to store this data someplace.

Best way to seamlessly & silently authenticate with a second webapp while logged in to a first?

Third party app (A) needs to link users to our app (B) and log them in behind the scenes.
Both apps work independently with their own auth systems. Users share a common unique ID, but have different authentication tokens (username/password/key etc) at each app.
The two complicating factors are as follows:
One app B user may associate with two app A users (e.g. both accounts at app B would redirect and login to the same app A account)
The app B user may not actually have any existing auth tokens, only their personal record and user ID, but we still want to be able to log them in if they are coming from app A.
My first thoughts were OAuth - but I don't think it will work as some users don't have app B accounts and thus won't be able to log in to grant app A access (see point 2 above).
The simplest way I have come up with is:
Each app has a pre-shared key e.g. "LOLS"
Common hash algo generates indepentent identical tokens e.g. hash(PSK + UID)
App B stores hashed tokens for each user
App A sends POST with UID and hashed token to App B, which uses it to identify and auth against a user
The problem with this is that it's hideously insecure. Anyone with knowledge of the pre-shared key (any system admin) and a user's ID (once again, any system admin) would be able to authenticate as ANY user, which is unacceptable.
Does anyone have any solutions? I'd prefer existing standards but am open to customised implementations. We can't really do much to app B other than to get them to use whatever API we provide.
I've faced situation similar to this many times. There have been a variety of solutions we've explored, here's one of them.
You produce a webservice for them to call. This could be something you lock down however you like, including by limiting access to their IP address at the firewall. They post the UID to your webservice, which inserts into a table on your end and hands back some sort of random token (we randomly generated a guid). Your table associates the token with the UID (in plaintext) they sent and a datestamp.
Their application sends the random token to you instead of the UID, you use it to look up the UID, and use the timestamp to make sure the random tokens are expired after a minute or so. Even if someone looks through your table somehow to get the list of UID's recently attempted, it doesn't let them authenticate unless they can pull it off real fast!