Xero API Token Handling - oauth-2.0

We think we have a challenge with Xero tokens possibly due to how store and retreive the access and refresh token.
We have an application that seems to disconnect some tenants/Xero Organizations from time to time. We are currently storing a single token (and using refresh and access tokens) without issue, but it feels like when a different user then authorizes a new tenant within our partner organziation, some of the previously authorized tenants stop working.
Do we need to maintain a new set of tokens per user who authorized the request? E.g. User A has a set of Access+Refresh Tokens and User B has a set of Access + Refresh tokens? If so, how do we keep track of what user has authorized which organization last? E.g. if User A authorized Org1 and User B authorized Org2, but then User A also authorized Org2, when our app (per schedule) needs to access Org2 do we just have to enumerate all the tokens and call GetOrganizations() to determine which ones they have?
Again, we have been operating on the idea that a single Access + Refresh token is all we should work with despite working with 100's of tenants/Organizations.
Any great advice on the proper way to store and re-use tokens for Xero would be really appreciated.
We used to store tokens separately, but the combined into single token as it seemed correct, but we still seem to have a few issues, not sure if we need to store a token per user (e.g. decrypt the Access Token, the get User ID, and store 1 pair per unique user id (access+refresh). Is this the proper way so that we don't have disconnect all the time?

Access tokens are issued per user per app. So user A would have one token pair for all the Xero organisations that they have authorised with your app and user B would have another pair for the organisations that they have authorised.
Storing 1 pair per user id would be a good idea.

Related

Refresh token rotation for different client but same user

For refresh token rotation and update both refresh token and access token way, I am wondering, for the same user, if he or she opens different browser and logs in. This means, for the same user, tokens rotation would think it is stolen. Am I right?
If I don't want this to happen, can I use IP combined with user ID to identity the user? Is it secure? I know if it is shared IP, then no.
Is there anything that hacker cannot fake which can distinguish hacker and the user? I think Phone has its device ID of some sort. How about browser?
I think you are confusing completely different concepts
Oauth - authorization.
Open id connect - sign-in - authentication.
Access tokens and refresh tokens are used for authorization. A user grants your application access to their data. The user does not have to be present for this to happen. There for using an access token to prove a users identity is not the correct course of action.
You should use open id connect, to authencation a user - sign them in. Then you should get an id token back which contains claims, one of these claims is the subject claim which should be the users id on the system you are connecting to. You should use that to identify the user.
As for hacking oauth. (Authorization)
Access tokens are short lived they will give your application access to a system for a limited amount of time usually an hour. If a hacker got the access token they would also have access to the system for this hour. access tokens are self contained. no further verification is preformed.
Refresh tokens require the client id and client secrete in order to request a new access token. So the hacker would need to have your client id, client secret, be on one of the valid redirect uris. in order to request a new access token. This is why you should not set a redirect uri to localhost.
Hacking and open id connect.(authencation)
Well as far as signin goes the hacker would need to have the users login and password in order to signin in and get an id token back. You should be good to assume that this is not a hacker and is the user behind the machine.

How should I use the id token returned to me by Google after a successful code exchange?

I am not clear on what exactly I should do with the id token from Google after the initial verification.
I'm developing on expo/react native and get the id token locally. Then, I send it to my server and verify it using google client libraries. Once it's verified what should I do with it?
Ideally I could use it to protect my api routes (express) but id tokens expire after 1 hour and I'm not sure how to refresh them with the client library. So, I don't know how I would do this.
Is that the intended use for id tokens? Should I instead be signing my own jwt and sending that back to the client? Then, the client could send that in the auth header of each request to a protected routes.
Google says:
After you have verified the token, check if the user is already in your user database. If so, establish an authenticated session for the user. If the user isn't yet in your user database, create a new user record from the information in the ID token payload, and establish a session for the user. You can prompt the user for any additional profile information you require when you detect a newly created user in your app.
https://developers.google.com/identity/sign-in/ios/backend-auth
Do I use the id token to "establish a session for the user"?
Yes, the ID-token is only used to create the local session, perhaps also create a local entry in your local database if that is used.
The ID token also have a very short lifetime, like 5 minutes in some systems. So it has no long-term use.
The ID token is intended to authenticate the user. It gives you information about the authenticated user, it should not be used to allow access to your endpoints. Access tokens or sessions are intended to do so. So in your case, you should do exactly as your gut feeling tells you - create a session for the user basing on the data you got in the ID token.
If you have your own Authorization Server you can use the ID token to issue an access token and return the token to the frontend app, then use the access token to access your backends. Have a look at OAuth flows if you would want to go this way.

How long does the connection to Google Calendar API lasts?

I am building a website where the users can schedule a meeting between two persons. In this meeting, there will also be a third person that will ALWAYS be the same and always be there.
My idea was, on the admin panel, make this third user logout and when there is a request for a meeting in the app, make a calendar event / Google Meet where the third account will invite the two users.
This action will be made automatically and these events will happen on the span of many months. I wanted to know how often the user will have to connect. Can he connect just once and then the token for the requests is valid forever or will the third attendee have to login periodically in order to keep the token "fresh"?
Thanks!
The way oauth works is that when authorized you are granted an access token which will give you access to the users data for one hour. If when authorizing the user you request "offline" access as well then you will be given a refresh token.
The refresh token does not expire for the most part, and can be used to request a new access token at anytime. There by refreshing your access as needed.
Get a refresh token for this user and then just refresh the access as needed.

How to revoke all jwt tokens for a specific user?

I know an access token is self-contained and therefore can't be revoked.
To my understanding, this is why the expiration time of an access token often is low. This enables one to revoke the refresh token, and thereby only allow users to be signed in, for the expiration time of the access token.
However, if I understand it correctly, a user is able to renew his token infinitely without the use of the refresh token.
One can initiate a silent authentication request by adding prompt=none. This is possible as long as your access token is still valid. Doing so will return a new access token, that is indistinguishable from a login performed directly without the prompt=none parameter.
If I understand this correctly, a user who once got a valid token is able to constantly renew this without me being able to "revoke" his access in any way?
Am I understanding this correctly, and if so, how do I go about revoking a user's access until he manually signs in again?
The prompt=none silent renewal actually uses the user's IDP authentication cookie and not their access token.
The good news is that ASP.Net Core allows you to store the data held in said cookie on the serverside (e.g. in a database or distributed cache) and thus you can revoke said cookie any time you like. By deleting the cookie data related to that user account you effectively invalidate their current session(s) and thus can prevent any future silent renewals. Likewise you can delete all persisted grants (reference tokens and refresh tokens).
Check out the Microsoft.AspNetCore.Authentication.Cookies.ITicketStore interface and the CookieAuthenticationOptions.SessionStore property.

Google OAuth 2.0 offline access

My app needs to access user's data even when the user is not present. So my request for authorization code includes access_type=offline meaning I will get back a refresh token if this is the first time the user authenticates my app. I save the refresh token and use it later on.
Everything works as expected and pretty well. But what bothers me is a statement in the documentation:
Note that there are limits on the number of refresh tokens that will
be issued; one limit per client/user combination, and another per use across all clients. You should save refresh tokens in long-term
storage and continue to use them as long as they remain valid. If your
application requests too many refresh tokens, it may run into these
limits, in which case older refresh tokens will stop working.
If I understand this correctly, it is possible the refresh token I save to become invalid if the user authorizes too many applications?! Is this correct? How should the application react in such situations? Ask for another refresh token?
Thanks in advance.
EDIT: I created a test PHP script that would request refresh tokens from 4 Google clients (by client I mean generated credentials in the Dev console). Three of them are linked to one gmail address and the forth to a different one. For the first email, I generated 2 projects and for the first project, I generated 2 client ids. So:
email X, project A, client id abc
email X, project A, client id def
email X, project B, client id mno
email Y, project C, client id xyz
I started the test by requesting a refresh token for each client. Then I requested 24 more refresh tokens for the first client id abc. At this point all refresh tokens were valid even though for email X I had 27 refresh tokens. Then when I requested another refresh token for client with id abc, the first one for this client got invalidated, so hitting the 25 token limit per email/client combination. All other tokens were still valid and I managed to generate new tokens for client def. This client is for the same project A and the same email X. So I can't hit the second limit. What do these statements mean is still a complete mistery to me:
https://developers.google.com/accounts/docs/OAuth2#expiration
If you need to authorize multiple programs, machines, or devices, one
workaround is to limit the number of clients that you authorize per
user account to 15 or 20. If you are a Google Apps admin, you can
create additional admin users and use them to authorize some of the
clients.
https://developers.google.com/accounts/docs/OAuth2WebServer#refresh
Note that there are limits on the number of refresh tokens that will
be issued; one limit per client/user combination, and another per user
across all clients.
It actually isn't as bad as you think. Refresh tokens are application specific, that meaning specific to your client id. If the user installs your application a number of times then they have a number of Refresh tokens related to your application.
I ran into this issue with a SSIS Connection manager if the user had my connection manager running on more then 20 SSIS packages the first one the installed would stop working.
https://developers.google.com/accounts/docs/OAuth2#expiration
Token expiration
You should write your code to anticipate the possibility that a granted token might
no longer work.
A token might stop working for one of these reasons:
The user has revoked access.
The token has not been used for six months.
The user account has exceeded a certain number of token requests.
There is currently a 25-token limit per Google user account. If a user
account has 25 valid - tokens, the next authentication request
succeeds, but quietly invalidates the oldest outstanding token without
any user-visible warning.
If you need to authorize multiple programs, machines, or devices, one
workaround is to limit the number of clients that you authorize per
user account to 15 or 20. If you are a Google Apps admin, you can
create additional admin users and use them to authorize some of the
clients.
So as long as your application isn't being installed more then 15 times by the same user you shouldn't have a problem. If it is a problem you can suggest that they use a different / dedicated login for your application.

Resources