Skip to content

Commit 62ef608

Browse files
skedwards88jhosmanhpsin
authored
Best practices for GitHub Apps (#36983)
Co-authored-by: Jess Hosman <1183847+jhosman@users.noreply.github.com> Co-authored-by: Hirsch Singhal <1666363+hpsin@users.noreply.github.com>
1 parent c754334 commit 62ef608

11 files changed

+148
-4
lines changed

content/apps/creating-github-apps/authenticating-with-a-github-app/generating-a-user-access-token-for-a-github-app.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ When you make API requests with a user access token, the rate limits for user ac
2323

2424
By default, the user access token expires after 8 hours. You can use a refresh token to regenerate a user access token. For more information, see "[AUTOTITLE](/apps/creating-github-apps/authenticating-with-a-github-app/refreshing-user-access-tokens)."
2525

26-
Users can revoke their authorization of a {% data variables.product.prodname_github_app %}. For more information, see "[AUTOTITLE](/authentication/keeping-your-account-and-data-secure/token-expiration-and-revocation)." If a user revokes their authorization of a {% data variables.product.prodname_github_app %}, the app will receive the `github_app_authorization` webhook. {% data variables.product.prodname_github_apps %} cannot unsubscribe from this event. If your app receives this webhook, you should stop calling the API on behalf of the user who revoked the token. If your app continues to use a revoked access token, it will receive the `401 Bad Credentials` error. For more information about this webhook, see "[AUTOTITLE](/webhooks-and-events/webhooks/webhook-events-and-payloads#github_app_authorization)"
26+
Users can revoke their authorization of a {% data variables.product.prodname_github_app %}. For more information, see "[AUTOTITLE](/authentication/keeping-your-account-and-data-secure/token-expiration-and-revocation)." If a user revokes their authorization of a {% data variables.product.prodname_github_app %}, the app will receive the `github_app_authorization` webhook. {% data variables.product.prodname_github_apps %} cannot unsubscribe from this event. If your app receives this webhook, you should stop calling the API on behalf of the user who revoked the token. If your app continues to use a revoked access token, it will receive the `401 Bad Credentials` error. For more information about this webhook, see "[AUTOTITLE](/webhooks-and-events/webhooks/webhook-events-and-payloads#github_app_authorization)."
27+
28+
You should keep user access tokens and refresh tokens secure. For more information, see "[AUTOTITLE](/apps/creating-github-apps/setting-up-a-github-app/best-practices-for-creating-a-github-app)."
2729

2830
## Using the web application flow to generate a user access token
2931

content/apps/creating-github-apps/authenticating-with-a-github-app/generating-an-installation-access-token-for-a-github-app.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ In order to authenticate as an app installation, you must generate an installati
2121

2222
{% endnote %}
2323

24+
You should keep your installation access token secure. For more information, see "[AUTOTITLE](/apps/creating-github-apps/setting-up-a-github-app/best-practices-for-creating-a-github-app)."
25+
2426
## Generating an installation access token
2527

2628
{% data reusables.apps.generate-installation-access-token %}

content/apps/creating-github-apps/authenticating-with-a-github-app/managing-private-keys-for-github-apps.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,10 @@ You can remove a lost or compromised private key by deleting it, but you must re
6464

6565
## Storing private keys
6666

67-
The private key is the single most valuable secret for a {% data variables.product.prodname_github_app %}. We recommend storing the key in a key vault, such as [Azure Key Vault](https://azure.microsoft.com/en-gb/products/key-vault), and making it sign-only. This ensures that you can't lose the private key. Once the private key is uploaded to the key vault, it can never be read from there. It can only be used to sign things, and access to the private key is determined by your infrastructure rules.
67+
The private key is the single most valuable secret for a {% data variables.product.prodname_github_app %}. Consider storing the key in a key vault, such as [Azure Key Vault](https://azure.microsoft.com/en-gb/products/key-vault), and making it sign-only. This helps ensure that you can't lose the private key. Once the private key is uploaded to the key vault, it can never be read from there. It can only be used to sign things, and access to the private key is determined by your infrastructure rules.
6868
6969
Alternatively, you can store the key as an environment variable. This is not as strong as storing the key in a key vault. If an attacker gains access to the environment, they can read the private key and gain persistent authentication as the {% data variables.product.prodname_github_app %}.
7070
7171
You should not hard-code your private key in your app, even if your code is stored in a private repository.
72+
73+
For more information, see "[AUTOTITLE](/apps/creating-github-apps/setting-up-a-github-app/best-practices-for-creating-a-github-app)."

content/apps/creating-github-apps/guides/building-a-cli-with-a-github-app.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -748,3 +748,5 @@ This tutorial demonstrated how to write a CLI that uses the device flow to gener
748748
This tutorial generates a user access token and saves it in a local file. You should never commit this file or publicize the token.
749749

750750
Depending on your device, you may choose different way to store the token. You should check the best practices for storing tokens on your device.
751+
752+
For more information, see "[AUTOTITLE](/apps/creating-github-apps/setting-up-a-github-app/best-practices-for-creating-a-github-app)."

content/apps/creating-github-apps/guides/building-a-github-app-that-responds-to-webhook-events.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -558,6 +558,8 @@ const host = process.env.NODE_ENV === 'production' ? '0.0.0.0' : 'localhost';
558558

559559
You should never publicize your app's private key or webhook secret. This tutorial stored your app's credentials in a gitignored `.env` file. When you deploy your app, you should choose a secure way to store the credentials and update your code to get the value accordingly. For example, you can store the credentials with a secret management service like [Azure Key Vault](https://azure.microsoft.com/en-us/products/key-vault). When your app runs, it can retrieve the credentials and store them in environment variables on the server where your app is deployed.
560560

561+
For more information, see "[AUTOTITLE](/apps/creating-github-apps/setting-up-a-github-app/best-practices-for-creating-a-github-app)."
562+
561563
### Share your app
562564

563565
If you want to share your app with other users and organizations, make your app public. For more information, see "[AUTOTITLE](/apps/creating-github-apps/creating-github-apps/making-a-github-app-public-or-private)."

content/apps/creating-github-apps/guides/building-a-login-with-github-button-with-a-github-app.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,3 +424,5 @@ This tutorial stored all of the code into a single file, but you may want to mov
424424
This tutorial generates a user access token. Unless you opted out of expiration for user access tokens, the user access token will expire after eight hours. You will also receive a refresh token that can regenerate a user access token. For more information, see "[AUTOTITLE](/apps/creating-github-apps/authenticating-with-a-github-app/refreshing-user-access-tokens)."
425425

426426
If you plan on interacting further with {% data variables.product.company_short %}'s APIs, you should store the token for future use. If you choose to store the user access token or refresh token, you must store it securely. You should never publicize the token.
427+
428+
For more information, see "[AUTOTITLE](/apps/creating-github-apps/setting-up-a-github-app/best-practices-for-creating-a-github-app)."
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
---
2+
title: Best practices for creating a GitHub App
3+
shortTitle: Best practices
4+
intro: "Follow these best practices to improve the security and performance of your {% data variables.product.prodname_github_app %}."
5+
versions:
6+
fpt: '*'
7+
ghes: '*'
8+
ghae: '*'
9+
ghec: '*'
10+
topics:
11+
- GitHub Apps
12+
---
13+
14+
## Select the minimum permissions required
15+
16+
Select the minimum permissions that your {% data variables.product.prodname_github_app %} needs. If any keys or tokens for your app become compromised, this will limit the amount of damage that can occur. For more information about how to choose permissions, see "[AUTOTITLE](/apps/creating-github-apps/setting-up-a-github-app/choosing-permissions-for-a-github-app)."
17+
18+
When your app creates an installation access token or user access token, you can further limit the repositories that the app can access and the permissions that the token has. For more information, see "[AUTOTITLE](/apps/creating-github-apps/authenticating-with-a-github-app/generating-an-installation-access-token-for-a-github-app)" and "[AUTOTITLE](/apps/creating-github-apps/authenticating-with-a-github-app/generating-a-user-access-token-for-a-github-app)."
19+
20+
## Stay under the rate limit
21+
22+
Subscribe to webhook events instead of polling the API for data. This will help your {% data variables.product.prodname_github_app %} stay within the API rate limit. For more information, see "[AUTOTITLE](/apps/creating-github-apps/creating-github-apps/using-webhooks-with-github-apps)" and "[AUTOTITLE](/apps/creating-github-apps/guides/building-a-github-app-that-responds-to-webhook-events)."
23+
24+
Consider using conditional requests to help you stay within the rate limit. For more information about conditional requests, see "[AUTOTITLE](/rest/overview/resources-in-the-rest-api#conditional-requests)."
25+
26+
If possible, consider using consolidated GraphQL queries instead of REST API requests to help you stay within rate limits. For more information, see "[AUTOTITLE](/rest/overview/about-githubs-apis)" and "[AUTOTITLE](/graphql)."
27+
28+
If you do hit a rate limit and need to retry an API request, use the `x-ratelimit-reset` or `Retry-After` response headers. If these headers are not available, wait for an exponentially increasing amount of time between retries, and throw an error after a specific number of retries. For more information, see "[AUTOTITLE](/rest/guides/best-practices-for-integrators#dealing-with-rate-limits)."
29+
30+
## Secure your app's credentials
31+
32+
You can generate a private key and client secret for your app. With these credentials, your app can generate installation access tokens, user access tokens, and refresh tokens. These tokens can be used to make API requests on behalf of an app installation or user.
33+
34+
You must store these credentials securely. The storage mechanism depends on your integrations architecture and the platform that it runs on. In general, you should use a storage mechanism that is intended to store sensitive data on the platform that you are using.
35+
36+
### Private keys
37+
38+
The private key for your {% data variables.product.prodname_github_app %} grants access to every account that the app is installed on.
39+
40+
Consider storing your {% data variables.product.prodname_github_app %}'s private key in a key vault, such as [Azure Key Vault](https://azure.microsoft.com/en-gb/products/key-vault), and making it sign-only.
41+
42+
Alternatively, you can store the key as an environment variable. However, this not as strong as storing the key in a key vault. If an attacker gains access to the environment, they can read the private key and gain persistent authentication as the {% data variables.product.prodname_github_app %}.
43+
44+
You should never hard code your private key in your app, even if your code is stored in a private repository. If your app is a native client, client-side app, or runs on a user device (as opposed to running on your servers), you should never ship your private key with your app.
45+
46+
You should not generate more private keys than you need. You should delete private keys that you no longer need. For more information, see "[AUTOTITLE](/apps/creating-github-apps/authenticating-with-a-github-app/managing-private-keys-for-github-apps)."
47+
48+
### Client secrets
49+
50+
Client secrets are used to generate user access tokens for your app, unless your app uses device flow. For more information, see "[AUTOTITLE](/apps/creating-github-apps/authenticating-with-a-github-app/generating-a-user-access-token-for-a-github-app#using-the-device-flow-to-generate-a-user-access-token)."
51+
52+
If your app is a website or web app, consider storing your client secret in a key vault, such as [Azure Key Vault](https://azure.microsoft.com/products/key-vault), or as an encrypted environment variable or secret on your server.
53+
54+
If your app is a native client, client-side app, or runs on a user device (as opposed to running on your servers), you cannot secure your client secret. You should use caution if you plan to gate access to your own services based on tokens generated by your app because anyone can access the client secret to generate a token.
55+
56+
### Installation access tokens, user access tokens, and refresh tokens
57+
58+
Installation access tokens are used to make API requests on behalf of an app installation. User access tokens are used to make API requests on behalf of a user. Refresh tokens are used to regenerate user access tokens. Your app can use its private key to generate an installation access token. Your app can use its client secret to generate a user access token and refresh token.
59+
60+
If your app is a website or web app, you should encrypt the tokens on your back end and ensure there is security around the systems that can access the tokens. Consider storing refresh tokens in a separate place from active access tokens.
61+
62+
If your app is a native client, client-side app, or runs on a user device (as opposed to running on your servers), you may not be able to secure tokens as well as an app that runs on your servers. You should not generate installation access tokens since doing so requires a private key. Instead, you should generate user access tokens. You should store tokens via the mechanism recommended for your app's platform, and keep in mind that the storage mechanism may not be fully secure.
63+
64+
## Use the appropriate token type
65+
66+
{% data variables.product.prodname_github_app %}s can generate installation access tokens or user access tokens in order to make authenticated API requests.
67+
68+
Installation access tokens will attribute activity to your app. These are useful for automations that act independently of users.
69+
70+
User access tokens will attribute activity to a user and to your app. These are useful for taking actions based on user input or on behalf of a user.
71+
72+
An installation access token is restricted based on the {% data variables.product.prodname_github_app %}'s permissions and access. A user access token is restricted based on both the {% data variables.product.prodname_github_app %}'s permission and access and the user's permission and access. Therefore, if your {% data variables.product.prodname_github_app %} takes an action on behalf of a user, it should always use a user access token instead of an installation access token. Otherwise, your app might allow a user to see or do things that they shouldn't be able to see or do.
73+
74+
## Validate organization access for every new authentication
75+
76+
When you use a user access token, you should track which organizations the token is authorized for. If an organization uses SAML SSO and a user has not performed SAML SSO, the user access token should not have access to that organization. You can use the `GET /user/installations` REST API endpoint to verify which organizations a user access token has access to. If the user is not authorized to access an organization, you should reject their access until they perform SAML SSO. For more information, see "[AUTOTITLE](/rest/apps/installations#list-app-installations-accessible-to-the-user-access-token)."
77+
78+
## Expire tokens
79+
80+
{% data variables.product.company_short %} strongly encourages you to use user access tokens that expire. If you previously opted out of using user access tokens that expire but want to reenable this feature, see "[AUTOTITLE](/apps/maintaining-github-apps/activating-optional-features-for-github-apps)."
81+
82+
Installation access tokens expire after one hour, expiring user access tokens expire after eight hours, and refresh tokens expire after six months. However, you can also revoke tokens as soon as you no longer need them. For more information, see "[AUTOTITLE](/rest/apps/installations#revoke-an-installation-access-token)" to revoke an installation access token and "[AUTOTITLE](/rest/apps/oauth-applications#delete-an-app-token)" to revoke a user access token.
83+
84+
## Make a plan for rotating credentials
85+
86+
You should have a plan in place so that you can handle any security breaches in a timely manner.
87+
88+
In the event that your app's private key or secret is compromised, you will need to generate a new key or secret, update your app to use the new key or secret, and delete your old key or secret.
89+
90+
In the event that installation access tokens, user access tokens, or refresh tokens are compromised, you should immediately revoke these tokens. For more information, see "[AUTOTITLE](/rest/apps/installations#revoke-an-installation-access-token)."
91+
92+
## Choose an appropriate environment
93+
94+
If your app runs on a server, verify that your server environment is secure and that it can handle the volume of traffic that you expect for your app.
95+
96+
## Subscribe to the minimum webhooks
97+
98+
Only subscribe to the webhook events that your app needs. This will help reduce latency since your app won't be receiving payloads that it doesn't need.
99+
100+
## Use a webhook secret
101+
102+
You should set a webhook secret for your {% data variables.product.prodname_github_app %} and verify that the signature of incoming webhook events match the secret. This helps to ensure that the incoming webhook event is a valid {% data variables.product.company_short %} event.
103+
104+
For more information, see "[AUTOTITLE](/apps/creating-github-apps/setting-up-a-github-app/using-webhooks-with-github-apps#securing-your-webhooks-with-a-webhook-secret)." For an example, see "[AUTOTITLE](/apps/creating-github-apps/guides/building-a-github-app-that-responds-to-webhook-events)."
105+
106+
## Allow time for users to accept new permissions
107+
108+
When you add repository or organization permissions to your {% data variables.product.prodname_github_app %}, users who have the app installed on their personal account or organization will receive an email prompting them to review the new permissions. Until the user approves the new permissions, their app installation will only receive the old permissions.
109+
110+
When you update permissions, you should consider making your app backwards compatible to give your users time to accept the new permissions. You can use the [installation webhook with the `new_permissions_accepted` action property](/webhooks-and-events/webhooks/webhook-events-and-payloads?actionType=new_permissions_accepted#installation) to learn when users accept new permissions for your app.
111+
112+
{% ifversion fpt or ghec %}
113+
114+
## Further reading
115+
116+
- "[AUTOTITLE](/apps/publishing-apps-to-github-marketplace/creating-apps-for-github-marketplace/security-best-practices-for-apps)"
117+
- "[AUTOTITLE](/apps/publishing-apps-to-github-marketplace/creating-apps-for-github-marketplace/customer-experience-best-practices-for-apps)"
118+
119+
{% endif %}

content/apps/creating-github-apps/setting-up-a-github-app/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,6 @@ children:
2323
- /creating-a-custom-badge-for-your-github-app
2424
- /about-the-user-authorization-callback-url
2525
- /about-the-setup-url
26+
- /best-practices-for-creating-a-github-app
2627
---
2728

content/apps/publishing-apps-to-github-marketplace/creating-apps-for-github-marketplace/customer-experience-best-practices-for-apps.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,8 @@ If you follow these best practices it will help you to provide a good customer e
2323
## Plan management
2424

2525
{% data reusables.marketplace.marketplace-billing-ui-requirements %}
26+
27+
## Further reading
28+
29+
- "[AUTOTITLE](/apps/creating-github-apps/setting-up-a-github-app/best-practices-for-creating-a-github-app)"
30+
- "[AUTOTITLE](/apps/publishing-apps-to-github-marketplace/creating-apps-for-github-marketplace/security-best-practices-for-apps)"

content/apps/publishing-apps-to-github-marketplace/creating-apps-for-github-marketplace/index.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,12 @@ topics:
88
- Marketplace
99
children:
1010
- /requirements-for-listing-an-app
11-
- /security-best-practices-for-apps
11+
- /security-best-practices-for-apps-on-github-marketplace
1212
- /customer-experience-best-practices-for-apps
1313
- /viewing-metrics-for-your-listing
1414
- /viewing-transactions-for-your-listing
1515
shortTitle: Create Marketplace apps
1616
redirect_from:
1717
- /developers/github-marketplace/creating-apps-for-github-marketplace
1818
---
19+

0 commit comments

Comments
 (0)