Can anyone please guide me on the following:
I am using valence api to import data to lms system and use a windows service to do the same.
I have created a service account and use user id/key pair of this account to authenticate the valence api call.
My question is:
Do we have an expiry for this user ID/Key pair? I have read somewhere (but not able to find out now) that it will be expired after 30 days. If that is the case, how can i prevent it from getting expired?
The lifetime of a User ID/Key pair is a potentially configurable value. The expected lifetime of a UserID/Key pair is indefinite until it gets marked for expiry. A User ID/Key pair, K, will get marked for expiry when one of these events occur:
The configured "lifetime" of all User ID/Key pairs, in seconds, is reached for K (that is, it was minted that many seconds ago). This is a single LMS configuration value that applies org-wide. By default it is set to a special value meaning "indefinite" (that is, it means "there is no natural expiry time for any User ID/Key pair), but particular LMS administrators can set, or get D2L to set, this to a concrete value (like a week, a month, whatever).
The password of the LMS user account gets reset: either a user changes his or her own password, or an admin performs a password reset of the user account. This event will mark all existing User ID/Key pairs for that user for expiry.
An LMS administrator revokes third-party application access for that user. This event will mark all existing User ID/Key pairs for that user for expiry.
When a User ID/Key pair gets marked for expiry it will, a short time later, get swept up and removed by a task that periodically removes all keys that are marked this way. (Typically the latency between marking a key for expiry, and removing it, is a very short period of time but it's not instant.)
Related
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.
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.
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.
If you have authenticated with an APPID and APPKEY and a specific user (meaning when prompted the users username and password have been entered and authenticated) and the system has sent back a USERID and USERKEY. Can you then make an API call to authenticate that user into D2L so the user arrives at the D2L MY HOME page?
In addition to that...
if the USERID and USERKEY for a specific user are stored in a DB, can you use that data alone to authenticate the user into D2L using an API call so the user arrives at the MY HOME page with no additional login prompt?
I understand that if the USERID and USERKEY have expired this would not work.
There are several different issues in this question.
Active web session for a user. Currently, D2L's Valence platform's user authentication does not work this way. The LMS will only provide back a UserID/Key pair as part of the auth process when it can confirm that it has an active session with a user:
API-calling client makes a request directly to the LMS to retrieve a UserID/Key pair for a user.
a. If the LMS has an active session with a user, (generate if necessary and) return the UserID/Key pair for that application/user pair.
b. If the LMS does not have an active session with a user, go through the login process it has configured to authenticate a user: this could be to redirect the calling web request to the LMS' own user login page, or that redirection could go through a third-party service that the LMS uses to authenticate users (for example, a configured SSO IDP).
What this means: if you use the API to initiate the auth process to retrieve a UserID/Key pair, the calling web browser will (as part of that process) already have an active web-session with the LMS. Either the user will be asked to log in using whatever auth process the LMS uses for that, or the user will already have done so and the calling browser will know that (because it has cookie state indicating an active session).
Programmatic logins. Currently, D2L's Valence platform does not support direct participation in the user authentication process: there are no calls to authenticate the user with the LMS by providing a userid/password or any other secret shared between the user and the LMS. The Valence security model specifically seeks to avoid having the API-calling client know about the authentication secret shared between the user and the LMS.
A client using the Valence Learning Framework APIs needs to either:
Initiate the authentication process by requesting a UserID/Key pair from the LMS (in which case the LMS will seek to auth the user; see the previous answer)
Rebuild a user context by using a valid UserID/Key pair from a cached state that it has already gathered from the LMS (which, in turn, will have required a real user to authenticate with the LMS)
UserID/Key pair expiry. Note that these auth tokens provided to the calling client by the LMS are intended to be long-lived. They should out-last the current web session that a browser will have for the user. Thus, a client application should treat those as secure data especially in combination with the client application's own ID/Key pair (since the user ID/Key pair is bound app's own ID/Key pair). While we expect client applications to cache these authentication tokens, we also expect them to be cached as sensitive information.
A user's ID/Key pair generated for an application will expire when one of these events happens:
The arrival of the expiry time associated with the ID/Key pair when the LMS generated it (the LMS admins can ensure that the default expiry time value for these tokens is "indefinite")
The user's password changes (either by the user or an LMS admin resetting it)
An LMS admin manually revokes client app access for the user
Facebook's deprecation of the offline_access permission is coming May 2012 and the documentation isn't giving us enough information on how to handle it.
We have an iOS app and corresponding service that powers it and integrates with Facebook in a deep way to leverage a user's friend list within out app (so if your FB friends are also using the app you can more easily connect). This is like how all social apps seem to work, so nothing special here.
Client
Our app uses Facebook iOS SDK to allow user to login, which we currently ask for offline_access. The token is persisted in our iOS app, but also sent to our server where it is saved. The client acts on behalf of user to post updates to a user's newsfeed (we also ask for publish_stream permission).
Server
Our server periodically checks to see if user's FB friends are now using our app. Next time user signs in, we expose content and relationships in a certain way to promote that user's friends. The server also acts on behalf of the user to periodically connect to the graph API and get the user's current friends list. This is so we can account for changes in a user's relationships and have them reflected in our app. We do this when the user isn't currently using the app so they have the best experience the next time they do use it. To enable this, our iOS app sends the access token to our server which it uses and why we ask for offline_access.
Note: If user signs out of our app explicitly, we delete the access tokens from both client and server.
Problems
Now that there is no longer a perpetual access token we can use, I'm trying to figure out the best practice for still enabling our scenarios while leveraging facebook's new intended way of handling and extending access tokens. The documentation is unfortunately not totally helpful.
Questions
A. When you authenticate through the newest Facebook iOS SDK, what is the default lifetime of the access token you get? This document says an extended token request will give you one that lasts 60 days. This other document talks about the first access token request and mentions varying validities but it's unclear and does it talk about specific validity times:
(emphasis is mine)
When you obtain an access token from Facebook, it will be valid
immediately and usable in requests to the API for some time period
defined by Facebook. After that period has elapsed, the access token
is considered to have expired and the user will need to be
authenticated again in order for your app to obtain a fresh access
token. The duration for which a given access token is valid depends on
how it was generated.
There are also events which may cause an access token to become
invalid before its expected expiry time. Such events include the user
changing their password, an application refreshing it's App Secret.
Dealing with varying access token expiry times, and handling the case
when an access token becomes invalid before its expected expiry time
is essential for building robust social experiences.
B. For the client, now that the access token isn't necessarily long lived, is the right approach for us to:
Let use login through FB, then detect whenever the access token is expired. If it is, then call into FB iOS SDK to re-authentication/re-authorize? (this should just trigger user to bounce out to FB iOS app, and in most cases come immediately back to our app with a new access token).
C. According to this blog post I found, you can only extend an access token once:
Can I exchange my 60 day access token for a new 60 day access token?
No, sorry you cannot. You can only exchange a valid (meaning current)
user access token for an extended one. You cannot extend an already
extended access token.
On the client, I can just handle this by prompting a re-authentication/re-authorization as I mentioned in Question B. However, this doesn't work on our server. We could certainly have the server renew it once to 60 days, but what happens on the 61st day? The server just stops being able to sync the friend's list?
D. It seems to make sense to check the validity of the FB access token every time the app starts or re-hydrates from sleep. What is the best way for our iOS app to check this? Is there a recommended endpoint to call to validate a token? Should we just call into https://graph.facebook.com/me passing the access token and checking the response?
Note: we can certainly record the expires time when we get the initially extended token, but this isn't reliable since the user could revoke our app's permission anytime which makes the expires time an unreliable data point on validity
Overview
I believe that the root of what facebook is trying to achieve is to prevent an app from having perpetual ever-lasting access to a user's account. So, with the new migration an app can only access an account for 60 days unless the user signs in again.
I don't work for facebook, but here are my findings from playing around with the facebook graph api.
General Solution
Whenever a user signs in, take their access token and immediately extend/refresh it, and save it
Record the expiration date of the access token
When an access token expires (either from the recorded date, or a graph API exception telling you so), then notify the user that you don't have access, and ask them to sign in again.
Answers
A. When you authenticate through the newest Facebook iOS SDK, what is the default lifetime of the access token you get? This document says an extended token request will give you one that lasts 60 days. This other document talks about the first access token request and mentions varying validities but it's unclear and does it talk about specific validity times:
Here's how it works:
The first sign-in grants you approximately two hours
By refreshing the access token, you can get up to 60 days
If the user doesn't sign in to those 60 days, there is no way to get access for longer without having them sign in.
If the user de-authorizes your app, that 60 day windows ends immediately, and you will no longer have access.
B. For the client, now that the access token isn't necessarily long lived, is the right approach for us to: Let use login through FB, then detect whenever the access token is expired. If it is, then call into FB iOS SDK to re-authentication/re-authorize? (this should just trigger user to bounce out to FB iOS app, and in most cases come immediately back to our app with a new access token).
If the users access token is expired, your only option is to have them go through a login loop like you are talking about.
C. According to this blog post I found, you can only extend an access token once. On the client, I can just handle this by prompting a re-authentication/re-authorization as I mentioned in Question B. However, this doesn't work on our server. We could certainly have the server renew it once to 60 days, but what happens on the 61st day? The server just stops being able to sync the friend's list?
You can only extend an access token once. On the 61st day, you are out of luck. Best notify the user and let them know that unless they sign in, you won't be able to do anything.
D. It seems to make sense to check the validity of the FB access token every time the app starts or re-hydrates from sleep. What is the best way for our iOS app to check this? Is there a recommended endpoint to call to validate a token? Should we just call into https://graph.facebook.com/me passing the access token and checking the response?
I haven't be able to find an API equivalent of the Debug Console. This FB blog article talks about invalidated access tokens, but doesn't mention any API methods in particular meant to test the API.
I your suggestion of hitting https://graph.facebook.com/me would work just fine is exactly what they recommend in their example. In fact, I might use this approach in my app as a pro-active way of checking an access token.
Tid Bits
When you "refresh" an access token, a new access token will be returned. The response looks like: access_token=TOKEN&expires=5183912
You can only "refresh" an access token once. If you try to "refresh" the long-lived token returned from a previous call, it will return the same token, but doesn't throw an exception unless the token has expired. (in other words, you can safely try to refresh your token)
The default access token length seems to be around 2 hours
If you "refresh" an access token, that new access tokens seems to be the one that you'll get from the facebook API afterwards (instead of returning the original, short-lived access token)
Also, if you want to play around, these tools make it easy to test out your use case in a browser before burying it in your code:
Graph API Explorer - For creating and getting access tokens
Debug Console - For checking the expiry date of tokens before/after refresh
Refresh Endpoint - For manually testing extending your tokens
Great answer, one important addition : the default token lasts between 1 and 2 hours. You get the remaining of the hour during which the user signs up, plus 1 full hour. For example if a user signs up at 3:45pm, the access token will expire at 5pm. To be safe developers should assume it only lasts 1hour.