You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Support GitHub Apps for Authentication in Crowdin GitHub Action #270
Feature Request: Support GitHub Apps for Authentication in Crowdin GitHub Action
Is your feature request related to a problem? Please describe.
Currently, the Crowdin GitHub Action requires a Personal Access Token (PAT) for authentication, which introduces security risks and compliance challenges. Many organizations, including those using GitHub Enterprise Managed Users (EMU), are transitioning away from PATs in favor of GitHub Apps, which provide:
Scoped permissions to minimize security risks.
Automatic token rotation to reduce manual management.
Better compliance with enterprise security policies.
Without GitHub Apps support, teams are forced to manage long-lived PATs, increasing the risk of token leaks, adding operational overhead, and potentially preventing adoption in environments with strict security policies.
This is critical for us due to security concerns, and we may be unable to continue using the Crowdin GitHub Action if GitHub Apps authentication is not supported.
Describe the solution you’d like
We request official support for GitHub Apps authentication in Crowdin GitHub Action, allowing:
Authentication via GitHub App tokens instead of manually managed PATs.
Support for GITHUB_TOKEN in workflows, leveraging GitHub’s built-in authentication with appropriate permissions.
A migration path from PAT-based authentication to GitHub Apps for existing users.
Describe alternatives you’ve considered
Continuing with PATs: Not ideal due to security risks, manual token rotation, and GitHub's push towards deprecating PAT usage in automation.
Additional context
Crowdin’s official GitHub Action (crowdin/github-action) currently requires PATs for pushing translations and creating pull requests.
GitHub officially recommends GitHub Apps for automation and has enabled GITHUB_TOKEN authentication for repository access.
Many organizations, including ours, will be unable to use Crowdin GitHub Action if GitHub Apps authentication is not supported.
This feature is critical for us, and we’d love to hear if it's on the roadmap. We're happy to assist with testing to ensure a smooth transition.
@Paul-Weaver indeed, that looks like a reason. So it seems to work without any changes to the action code.
By the way, would you like to contribute a readme update describing how to authenticate via the GitHub app? It would be very helpful for other developers.
@Paul-Weaver indeed, that looks like a reason. So it seems to work without any changes to the action code.
By the way, would you like to contribute a readme update describing how to authenticate via the GitHub app? It would be very helpful for other developers.
But suppose I supply a GitHub App access token that I am absolutely certain has contents: write and pull-requests: write on the relevant repo (assume I obtain one and store it in steps.generate-token.outputs.token):
My suspicion is that one cannot overwrite GITHUB_TOKEN like that, which @lol3909 noted here. I note that in your (Paul's) comment you have write access in the permissions block and I wonder if that's why it worked for you there?
@andrii-bodnar Is there any possibility of being able to supply GITHUB_TOKEN as GH_TOKEN in the case where we want to override it in our jobs? That might achieve my desired behaviour, which is:
Start a job with very low permissions (readonly)
Make a call to obtain a write-access token
Pass that token to Crowdin (i.e. a "stepped-up" GITHUB_TOKEN)
Thanks very much @andrii-bodnar , I will try that and report back; I am wondering if this will work in light of what GitHub say here about restrictions on variable names:
You can't overwrite the value of the default environment variables named GITHUB_* and RUNNER_*.
It's not super clear to me from that whether overwrite is used in a strict sense, or it means you also can't write them with original values.
So, it might object to GITHUB_APP_TOKEN but not to GH_TOKEN or similar, because the latter doesn't match GITHUB_*. We'll see!
I've been struggling with this but I don't think it's any problem with the action; more what limitations GitHub Actions puts in place.
I tried with the following, but it 403's every time. Interestingly, if I get a token locally and try pushing to a REPO_URL containing github.com rather than api.github.com, it works. I also tried using different GITHUB_ACTOR values in the REPO_URL, but it made no difference.
I'm left with the suspicion that GitHub Actions does not let you escalate privileges by generating a token with broader permissions than what is given in the job's permissions stanza... but I also have big doubts about that, because how would the remote Git origin know?
And yet, locally, using git push https://any-username:TOKEN@github.com/foo/bar.gitdoes work. Just not in an Action. (Using api.github.com works in neither place.) For what it's worth, my token starts with ghs_ and I'm on GitHub Enterprise SaaS.
At this point, I'm sorry to say, I'm out of ideas... so we might be forced to just use contents: write in the job permissions.
GITHUB_TOKEN (default) handles the REST / GraphQL API calls (open/update PR, set commit status).
GH_TOKEN (GitHub App token) handles the raw git push. If GITHUB_TOKEN (default token is read-only), the API call that opens the PR will 403—even though the push itself succeeded.
Give the job write permissions
Add “contents: write” and “pull-requests: write” to the job.
This upgrades the default token just long enough for the API work while GH_TOKEN stays scoped for the push.
Drop github_api_base_url : Let the action use its default endpoint (api.github.com) unless you’re on a self-hosted GHES instance.
Fix
Give the job write perms so the default token can open/update the PR:
TL;DR — The Crowdin action needs two tokens: the default GITHUB_TOKEN for API calls (opening/updating the PR) and a scoped GH_TOKEN from your GitHub App for the actual git push. If the job’s permissions are read-only, those API calls 403 even though the push works. Give the job temporary contents: write and pull-requests: write perms so GITHUB_TOKEN can finish its work, keep GH_TOKEN for the push, and drop github_api_base_url unless you’re on GHES. That combo removes the 403.
Thanks Paul. That does, indeed, work. I'd conclude from this that if the action were to use GH_TOKEN for everything, (though I thought it did) obtained from a correctly configured app (with permissions to write PRs and pushes), then the following would be possible.
The main (only?) advantage being that it scores maximum points in terms of token scope reduction.
I believe this issue is not actually resolved (#305 is a duplicate of this).
The fix — supporting GH_TOKEN to override GITHUB_TOKEN in push_to_branch() and create_pull_request() — exists in the app_token branch but has never been merged into master (compare). Users on any released version therefore cannot override the token.
Hi @iorate, thanks for reporting this! It's a very confusing situation, i'm sorry for this!
I just rebased the app_token branch and created PR #307. Could you please quickly check to see if everything is working as expected before I merge and release it? Thank you!
Activity
andrii-bodnar commentedon Mar 5, 2025
Hi @Paul-Weaver, thanks for the request!
There was a similar request in issue #264. Could you please check if the solution suggested in that issue works for you?
Paul-Weaver commentedon Mar 5, 2025
Thanks for the swift response, I will create GitHub App then test it
Paul-Weaver commentedon Mar 6, 2025
@andrii-bodnar it actually works on latest crowdin using
GITHUB_TOKENand having the app token there. Or am I misunderstanding something?andrii-bodnar commentedon Mar 6, 2025
@Paul-Weaver it's interesting 🤔
Based on the mentioned issue, I thought it was not working this way
Paul-Weaver commentedon Mar 6, 2025
I'm not sure, but you can see they don't have the correct permissions anyhow it's missing
pull-requests: writeandrii-bodnar commentedon Mar 6, 2025
@Paul-Weaver indeed, that looks like a reason. So it seems to work without any changes to the action code.
By the way, would you like to contribute a readme update describing how to authenticate via the GitHub app? It would be very helpful for other developers.
Paul-Weaver commentedon Mar 6, 2025
Sure I can help with that!
GITHUB_TOKENfor Crowdin GitHub Action when using custom tokens #264 as a duplicate of this issue3dbrows commentedon May 28, 2025
@Paul-Weaver Did you happen to have a chance to write such docs? I'm struggling to understand why this doesn't work:
Here we see the job has readonly access.
But suppose I supply a GitHub App access token that I am absolutely certain has
contents: writeandpull-requests: writeon the relevant repo (assume I obtain one and store it insteps.generate-token.outputs.token):I get a 403 on trying to write to the repo.
My suspicion is that one cannot overwrite
GITHUB_TOKENlike that, which @lol3909 noted here. I note that in your (Paul's) comment you havewriteaccess in thepermissionsblock and I wonder if that's why it worked for you there?@andrii-bodnar Is there any possibility of being able to supply
GITHUB_TOKENasGH_TOKENin the case where we want to override it in our jobs? That might achieve my desired behaviour, which is:GITHUB_TOKEN)andrii-bodnar commentedon Jun 2, 2025
Hi @3dbrows,
In the related issue, there was a proof of concept for this. Could you please check to see if that solution works for you?
3dbrows commentedon Jun 4, 2025
Thanks very much @andrii-bodnar , I will try that and report back; I am wondering if this will work in light of what GitHub say here about restrictions on variable names:
It's not super clear to me from that whether overwrite is used in a strict sense, or it means you also can't write them with original values.
So, it might object to
GITHUB_APP_TOKENbut not toGH_TOKENor similar, because the latter doesn't matchGITHUB_*. We'll see!andrii-bodnar commentedon Jun 4, 2025
@3dbrows I just merged your PR into the
app_tokenbranch. Could you please check it out?3dbrows commentedon Jun 6, 2025
I've been struggling with this but I don't think it's any problem with the action; more what limitations GitHub Actions puts in place.
I tried with the following, but it 403's every time. Interestingly, if I get a token locally and try pushing to a
REPO_URLcontaininggithub.comrather thanapi.github.com, it works. I also tried using differentGITHUB_ACTORvalues in theREPO_URL, but it made no difference.I'm left with the suspicion that GitHub Actions does not let you escalate privileges by generating a token with broader permissions than what is given in the job's
permissionsstanza... but I also have big doubts about that, because how would the remote Git origin know?And yet, locally, using
git push https://any-username:TOKEN@github.com/foo/bar.gitdoes work. Just not in an Action. (Usingapi.github.comworks in neither place.) For what it's worth, my token starts withghs_and I'm on GitHub Enterprise SaaS.At this point, I'm sorry to say, I'm out of ideas... so we might be forced to just use
contents: writein the job permissions.Thanks for looking at this with me!
Paul-Weaver commentedon Jun 6, 2025
@3dbrows here’s what worked for me:
GITHUB_TOKEN(default) handles the REST / GraphQL API calls (open/update PR, set commit status).GH_TOKEN(GitHub App token) handles the raw git push. IfGITHUB_TOKEN(default token is read-only), the API call that opens the PR will 403—even though the push itself succeeded.Give the job write permissions
Add “
contents: write” and “pull-requests: write” to the job.This upgrades the default token just long enough for the API work while
GH_TOKENstays scoped for the push.Drop
github_api_base_url: Let the action use its default endpoint (api.github.com) unless you’re on a self-hosted GHES instance.Fix
Give the job write perms so the default token can open/update the PR:
Give that a spin and shout if anything’s still off.
Paul-Weaver commentedon Jun 6, 2025
TL;DR — The Crowdin action needs two tokens: the default GITHUB_TOKEN for API calls (opening/updating the PR) and a scoped GH_TOKEN from your GitHub App for the actual git push. If the job’s permissions are read-only, those API calls 403 even though the push works. Give the job temporary contents: write and pull-requests: write perms so GITHUB_TOKEN can finish its work, keep GH_TOKEN for the push, and drop
github_api_base_urlunless you’re on GHES. That combo removes the 403.3dbrows commentedon Jun 9, 2025
Thanks Paul. That does, indeed, work. I'd conclude from this that if the action were to use
GH_TOKENfor everything, (though I thought it did) obtained from a correctly configured app (with permissions to write PRs and pushes), then the following would be possible.The main (only?) advantage being that it scores maximum points in terms of token scope reduction.
andrii-bodnar commentedon Jun 9, 2025
Great work on these findings, @Paul-Weaver and @3dbrows. Thank you! 🚀
iorate commentedon Mar 7, 2026
Hi @andrii-bodnar,
I believe this issue is not actually resolved (#305 is a duplicate of this).
The fix — supporting
GH_TOKENto overrideGITHUB_TOKENinpush_to_branch()andcreate_pull_request()— exists in theapp_tokenbranch but has never been merged intomaster(compare). Users on any released version therefore cannot override the token.Could you merge
app_tokenintomaster? Thank you!andrii-bodnar commentedon Mar 12, 2026
Hi @iorate, thanks for reporting this! It's a very confusing situation, i'm sorry for this!
I just rebased the
app_tokenbranch and created PR #307. Could you please quickly check to see if everything is working as expected before I merge and release it? Thank you!