Random 401 errors after using freshly generated installation access token


I am getting random “401 — Bad credentials” errors while using freshly generated installation token for Github App installation. It works 99% of the time but from time to time it fails.

What I do exactly:

CALL -> /app/installations/X/access_tokens
RESPONSE <- {"token":"XXX","expires_at":"2019-04-30T08:07:39Z"}

everything looks good so far, note: expires_at is a future date

I use received token to call API like repos/X/Y/pulls/2823/files and from time to time I get 401 error exactly like GitHub API was not internally consistent. 

Any pointers how should I solve this? I thought about simply retrying it before really failing.

We’re running a few different Probot framework GitHub Apps and haven’t seen this kind of intermittent failure. Are you using a framework like Probot or Octokit to interact with the GitHub API?

I just make raw http request — no library. I noticed that octokit allows to easily implement retry strategy. Probably I do just this and retry 401 with some delay. 

@lee-dohm do you cache installation access tokens in any way on your end? I noticed that they are valid for ~one hour so they could be easily reused between requests which probably could also make this problem go away (at least till some extent). 

Happening for us at GitSpeak well. Very annoying.

1 Like

I’d have to go digging into the Probot internals to see how it caches installation tokens. If I get a chance to do so, I’ll see if I can find it. Or you could take a look and duplicate the code … or convert to using Probot :grinning: That’s why we built the Probot framework, to make all of this easier.

We’re also seeing this random 401 errors when using github apps. Every now and then it happens when retrieving installation tokes, but more commonly it happens after getting an installation token and using it for other API calls. Same call might work 5 times and then get a 401 the next one, or get 401 as soon as we make the first call


Yep, looks like Probot caches them for 59 minutes by default.

I’ve talked to the developers and the current advice is the following:

  • Cache access tokens and reuse them until they expire (currently 60 minutes)
  • Avoid making many simultaneous requests immediately after generating a new access token
  • Retry failed operations with exponential backoff up to a reasonable maximum number

I hope that helps and let us know what you find after implementing :point_up_2:


Thanks! I am gonna implement those ideas and let you know if it really solved our problems.