{"id":49321,"date":"2025-05-14T02:32:33","date_gmt":"2025-05-14T02:32:33","guid":{"rendered":"https:\/\/www.devopsschool.com\/blog\/?p=49321"},"modified":"2026-02-21T07:28:21","modified_gmt":"2026-02-21T07:28:21","slug":"what-is-github-app-installation-token","status":"publish","type":"post","link":"https:\/\/www.devopsschool.com\/blog\/what-is-github-app-installation-token\/","title":{"rendered":"What is GitHub App Installation Token?"},"content":{"rendered":"\n<p>A <strong>GitHub App Installation Token<\/strong> is a <strong>short-lived access token<\/strong> that allows a GitHub App to <strong>interact with specific repositories or organizations<\/strong> where it has been installed \u2014 on behalf of itself, not a user.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\">\n\n\n\n<h2 class=\"wp-block-heading\">\ud83d\udd10 Why is it Needed?<\/h2>\n\n\n\n<p>GitHub Apps <strong>do not use OAuth tokens<\/strong> like traditional apps. Instead, they:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Authenticate as the App using a <strong>JWT (JSON Web Token)<\/strong>.<\/li>\n\n\n\n<li>Exchange the JWT for an <strong>installation token<\/strong> for a <strong>specific installation<\/strong> of the app (per repo\/org).<\/li>\n\n\n\n<li>Use the <strong>installation token<\/strong> to make <strong>authenticated API calls<\/strong> (REST or GraphQL).<\/li>\n<\/ol>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\">\n\n\n\n<h2 class=\"wp-block-heading\">\u2705 What Can You Do with an Installation Token?<\/h2>\n\n\n\n<p>Once issued, an installation token:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Acts on behalf of the GitHub App installation<\/strong><\/li>\n\n\n\n<li><strong>Honors the app&#8217;s granted permissions and scopes<\/strong><\/li>\n\n\n\n<li>Is <strong>limited to specific repositories<\/strong> where the app is installed<\/li>\n\n\n\n<li><strong>Expires in 1 hour<\/strong><\/li>\n<\/ul>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>Example: If your GitHub App is installed on <code>octo-org\/repo-a<\/code> and <code>repo-b<\/code>, your installation token can only access those, not others.<\/p>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\">\n\n\n\n<h2 class=\"wp-block-heading\">\ud83d\udee0\ufe0f How to Generate an Installation Token (Step-by-Step)<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Step 1: Generate a JWT (as the App)<\/h3>\n\n\n\n<p>Use your app\u2019s private key:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">const<\/span> jwt = <span class=\"hljs-built_in\">require<\/span>(<span class=\"hljs-string\">'jsonwebtoken'<\/span>);\n<span class=\"hljs-keyword\">const<\/span> fs = <span class=\"hljs-built_in\">require<\/span>(<span class=\"hljs-string\">'fs'<\/span>);\n\n<span class=\"hljs-keyword\">const<\/span> appId = <span class=\"hljs-string\">'YOUR_APP_ID'<\/span>;\n<span class=\"hljs-keyword\">const<\/span> privateKey = fs.readFileSync(<span class=\"hljs-string\">'private-key.pem'<\/span>);\n\n<span class=\"hljs-keyword\">const<\/span> token = jwt.sign(\n  {\n    <span class=\"hljs-attr\">iat<\/span>: <span class=\"hljs-built_in\">Math<\/span>.floor(<span class=\"hljs-built_in\">Date<\/span>.now() \/ <span class=\"hljs-number\">1000<\/span>),\n    <span class=\"hljs-attr\">exp<\/span>: <span class=\"hljs-built_in\">Math<\/span>.floor(<span class=\"hljs-built_in\">Date<\/span>.now() \/ <span class=\"hljs-number\">1000<\/span>) + (<span class=\"hljs-number\">10<\/span> * <span class=\"hljs-number\">60<\/span>),\n    <span class=\"hljs-attr\">iss<\/span>: appId,\n  },\n  privateKey,\n  { <span class=\"hljs-attr\">algorithm<\/span>: <span class=\"hljs-string\">'RS256'<\/span> }\n);\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\">\n\n\n\n<h3 class=\"wp-block-heading\">Step 2: Get Installation ID<\/h3>\n\n\n\n<p>Make a request using JWT to get installation ID:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\">GET \/app\/installations\nAuthorization: Bearer <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">JWT<\/span>&gt;<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\">\n\n\n\n<h3 class=\"wp-block-heading\">Step 3: Exchange JWT for Installation Token<\/h3>\n\n\n\n<p>Use the installation ID from Step 2:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\">POST \/app\/installations\/:installation_id\/access_tokens\nAuthorization: Bearer <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">JWT<\/span>&gt;<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p><strong>Response:<\/strong><\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"JSON \/ JSON with Comments\" data-shcb-language-slug=\"json\"><span><code class=\"hljs language-json\">{\n  <span class=\"hljs-attr\">\"token\"<\/span>: <span class=\"hljs-string\">\"v1.abc123...\"<\/span>,\n  <span class=\"hljs-attr\">\"expires_at\"<\/span>: <span class=\"hljs-string\">\"2026-05-14T12:00:00Z\"<\/span>\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JSON \/ JSON with Comments<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">json<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\">\n\n\n\n<h3 class=\"wp-block-heading\">Step 4: Use Installation Token to Call GitHub API<\/h3>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">GET \/repos\/octo-org\/repo-a\/issues\nAuthorization: token v1.abc123...\n<\/code><\/span><\/pre>\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\">\n\n\n\n<h2 class=\"wp-block-heading\">\ud83d\udd04 Installation Token vs OAuth Token<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Feature<\/th><th>Installation Token<\/th><th>OAuth Token<\/th><\/tr><\/thead><tbody><tr><td>Acts as<\/td><td>GitHub App installation<\/td><td>Authenticated user<\/td><\/tr><tr><td>Scope<\/td><td>Repo\/org installation<\/td><td>User\u2019s authorized scopes<\/td><\/tr><tr><td>Use case<\/td><td>Automation, bots, CI\/CD<\/td><td>User-based access and interaction<\/td><\/tr><tr><td>Expiry<\/td><td>1 hour<\/td><td>Long-lived unless revoked<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\">\n\n\n\n<h2 class=\"wp-block-heading\">\ud83e\udde0 Example Use Cases<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>CI\/CD pipelines using GitHub Apps<\/li>\n\n\n\n<li>Auto-responders on issues\/pull requests<\/li>\n\n\n\n<li>Infrastructure automation (e.g., with Terraform)<\/li>\n\n\n\n<li>Custom bots interacting with GitHub<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\">\n\n\n\n<h2 class=\"wp-block-heading\">\ud83e\uddea Final Notes<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>You <strong>must use a JWT to request<\/strong> an installation token.<\/li>\n\n\n\n<li>Installation tokens <strong>cannot be refreshed<\/strong> \u2014 regenerate when expired.<\/li>\n\n\n\n<li>Use <strong>Octokit<\/strong> or <strong>Probot<\/strong> for easier abstraction.<\/li>\n<\/ul>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>A GitHub App Installation Token is a short-lived access token that allows a GitHub App to interact with specific repositories or organizations where it has been installed \u2014 on behalf&#8230; <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"_joinchat":[],"footnotes":""},"categories":[2],"tags":[],"class_list":["post-49321","post","type-post","status-publish","format-standard","hentry","category-uncategorised"],"_links":{"self":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/49321","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/comments?post=49321"}],"version-history":[{"count":2,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/49321\/revisions"}],"predecessor-version":[{"id":58971,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/49321\/revisions\/58971"}],"wp:attachment":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/media?parent=49321"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/categories?post=49321"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/tags?post=49321"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}