{"action":"created","issue":{"url":"https://api.github.com/repos/drone/drone/issues/855","labels_url":"https://api.github.com/repos/drone/drone/issues/855/labels{/name}","comments_url":"https://api.github.com/repos/drone/drone/issues/855/comments","events_url":"https://api.github.com/repos/drone/drone/issues/855/events","html_url":"https://github.com/drone/drone/issues/855","id":55651574,"number":855,"title":"GitLab Refresh Tokens & Concurrency","user":{"login":"bradrydzewski","id":817538,"avatar_url":"https://avatars.githubusercontent.com/u/817538?v=3","gravatar_id":"","url":"https://api.github.com/users/bradrydzewski","html_url":"https://github.com/bradrydzewski","followers_url":"https://api.github.com/users/bradrydzewski/followers","following_url":"https://api.github.com/users/bradrydzewski/following{/other_user}","gists_url":"https://api.github.com/users/bradrydzewski/gists{/gist_id}","starred_url":"https://api.github.com/users/bradrydzewski/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bradrydzewski/subscriptions","organizations_url":"https://api.github.com/users/bradrydzewski/orgs","repos_url":"https://api.github.com/users/bradrydzewski/repos","events_url":"https://api.github.com/users/bradrydzewski/events{/privacy}","received_events_url":"https://api.github.com/users/bradrydzewski/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":1,"created_at":"2015-01-27T17:56:49Z","updated_at":"2015-08-04T07:59:54Z","closed_at":null,"body":"When the `access_token` is refreshed GitLab also sends a new `refresh_token`. This is a perfectly valid (but optional) implementation detail:\r\n\r\n> the authorization server MAY issue a new refresh token, in which case the client MUST discard the old refresh token and replace it with the new refresh token.\r\n\r\nWhen GitLab sends back a new `refresh_token` it also immediately expires the old `refresh_token`. This is also a perfectly valid (but optional) implementation detail:\r\n\r\n> The authorization server MAY revoke the old refresh token after issuing a new refresh token to the client.\r\n\r\nThis becomes problematic for systems that are making concurrent requests to the API. It is possible for two threads (or in our case goroutines) to successfully refresh an access_token around the same time. This means one thread will have an expired set of tokens that it cannot refresh.\r\n\r\nThis gets more complicated because we are making these requests offline. This means if we achieve the above race condition, we could get locked out of the API forever until the user physically goes to the website and re-authenticates.\r\n\r\nThere really isn't a good way to handle this in a concurrent, offline environment. We could try to implement mutexes, but even this is subject to edge cases (ie program quits un-unexpectedly)\r\n\r\nI believe we need to engage GitLab for this. One example of a middle ground could be providing `access_type=offline` (similar to Google) that would prevent sending a new `refresh_token` when refreshing an `access_token`.\r\n\r\nAnother option would be to more closely mirror GitHub and never expire an access token. It looks like this is possible (see https://github.com/doorkeeper-gem/doorkeeper/pull/76) but I'm not sure they would be willing to make such a drastic policy change."},"comment":{"url":"https://api.github.com/repos/drone/drone/issues/comments/127512072","html_url":"https://github.com/drone/drone/issues/855#issuecomment-127512072","issue_url":"https://api.github.com/repos/drone/drone/issues/855","id":127512072,"user":{"login":"Intrepidd","id":803765,"avatar_url":"https://avatars.githubusercontent.com/u/803765?v=3","gravatar_id":"","url":"https://api.github.com/users/Intrepidd","html_url":"https://github.com/Intrepidd","followers_url":"https://api.github.com/users/Intrepidd/followers","following_url":"https://api.github.com/users/Intrepidd/following{/other_user}","gists_url":"https://api.github.com/users/Intrepidd/gists{/gist_id}","starred_url":"https://api.github.com/users/Intrepidd/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Intrepidd/subscriptions","organizations_url":"https://api.github.com/users/Intrepidd/orgs","repos_url":"https://api.github.com/users/Intrepidd/repos","events_url":"https://api.github.com/users/Intrepidd/events{/privacy}","received_events_url":"https://api.github.com/users/Intrepidd/received_events","type":"User","site_admin":false},"created_at":"2015-08-04T07:59:54Z","updated_at":"2015-08-04T07:59:54Z","body":"I think we stumbled upon this. After recently upgrading drone, we had issues with build not launching.\r\n\r\nAfter digging into the logs and source code, we found that the owner of the repository had to log in again.\r\n\r\nProblem is, this issue happens several times a day. I imagine we're having the race condition you're describing"}}