https://git.your-app.com/team/project-alpha.git. Your server authenticates
each request with your own system and forwards it to Code Storage with a short-lived token.
Your users never receive a Code Storage token or your private key. You control:
- Authentication. Use your own sign-in, access tokens, or SSO.
- Authorization. Decide which user can read or write each repository, and set ref policies for each user.
- Revocation. When you remove access in your system, the next request fails.
- Access logs. Record the user, IP address, repository, and operation of each request.
Choose an approach
A proxy gives you the most control, but it is also the most work: you run a server in the path of every clone and push. Two lighter options do not need a proxy:- Short-lived remote URLs. Your backend gives each user a remote URL with a short-lived token.
See
repo.getRemoteURL(). - A Git credential helper. You ship a credential helper that gets a short-lived token from your API each time Git needs credentials.
How it works
- Forward only the Git endpoints below, and return
404for every other path. - Return
401when the user’s credentials are missing or incorrect, and404when the user cannot access the repository. - Sign a new token for each request, with the repository, the scopes that the request needs, your
user ID as
sub, and your ref policies. - Never forward the user’s
Authorizationheader to Code Storage. - Stream the request body and the response body.
The endpoints that Git uses
Git over HTTPS uses four requests for each repository, under/{repo}.git/:
The example proxy does not support Git LFS yet. It returns
404 for LFS
requests.Build the proxy
The proxy is a Fetch API handler: it takes aRequest and returns a Response. This example runs it on Node.js with
srvx and signs tokens with jose. Install
the packages:
PIERRE_ORG and PIERRE_PRIVATE_KEY as shown in Authentication.
Each step below adds code to proxy.ts, in order. The complete file is at
the end of this section.
Set up
proxy.ts
Match the Git endpoints
Each route sets the access that its endpoint needs. A request that matches no route gets404.
proxy.ts
Check the user
The handler authenticates the user, checks access to the repository, and writes one log line for each request. The line has the user, IP address, repository, endpoint, and response status.proxy.ts
Connect your user system
Put your own logic inauth.ts. It exports two functions:
authenticate(request)returns the user, as an object with anid, ornull. Git sends the user’s credentials as HTTP Basic auth in theAuthorizationheader. Fornull, the proxy returns401, and Git asks the user or its credential helper for credentials.authorize(user, repo, access)returnstrueif the user can access the repository.accessis'read'for a clone or fetch, and'write'for a push. Forfalse, the proxy returns404, so a user cannot find out which repositories exist.
Sign a token
The token covers one repository and the scopes that the request needs. It setssub to your user
ID, which Code Storage shows in its logs. The token expires after 300 seconds. It only needs to be
valid when Code Storage receives the request, so a long push still completes.
proxy.ts
If you use a restricted key, its allowlist must
include
git:read and git:write. A restricted key also limits the token lifetime to 3,600
seconds.Forward the request
The proxy forwards only the headers that Git needs. It does not forward the user’sAuthorization
header. A clone or push can transfer a large pack, so the proxy streams both bodies and does not
buffer them.
proxy.ts
Serve the proxy
proxy.ts
handleGit() uses only the Fetch API. To run it on another server, pass it each Request and the
client IP address, and return its Response.
Run the proxy with Node.js 24 or later. Node.js runs TypeScript files directly. Set
"type": "module" in package.json.
The complete proxy
proxy.ts
proxy.ts
proxy.ts
Use the remote
Give your users the URL of your proxy. Git sends their credentials with HTTP Basic auth, so they can use a Git credential helper as they do with any other host:authenticate() accepts,
for example a username and an access token from your product. The proxy matches repository paths
that end in .git, so give your users URLs in this form.
Attribute pushes
Push webhooks identify the repository and ref, but not the user who pushed. Your proxy log identifies the user for eachgit-receive-pack request. Use your proxy log as the record
of who pushed.
Test the proxy
Run these checks before you give the remote to users:- Clone a repository through the proxy with a valid user.
- Push to a branch that the user can write.
- Clone with an incorrect token. The proxy returns
401. - Clone a repository that the user cannot access. The proxy returns
404. - Push to a ref that a ref policy blocks. Git shows
push denied by policy.