Connecting Composer

Configure composer.json, mint a token, and authenticate Composer against your Packyard registry.

Updated April 27, 2026

Once Packyard is running, point your project at it from composer.json, mint a token in the dashboard, and authenticate Composer with HTTP Basic. Three steps, all local to the project that wants to install your private packages.

Every Packyard install ships with a default organization on first boot; URLs always include the org slug. Replace default with whatever slug you've set up if you've added more orgs (see Organizations).

Add the registry to composer.json

{
  "repositories": [
    {
      "type": "composer",
      "url": "https://repo.example.com/default"
    }
  ]
}

The hostname is whatever you set as PACKYARD_BASE_URL; the path suffix is the org slug. Composer treats the resulting URL as a packages.json endpoint and fetches metadata, providers, and dist zips from there.

Mint a token

In the Packyard dashboard, open Tokens → New token. The dashboard generates the token and a unique password together, displayed exactly once. Copy them now — they're not retrievable later.

Field Notes
Name A label for your records ("CI: production", "ci-acme", etc.).
Expiry Optional. Use short-lived tokens for CI; longer for development workstations.
Scope Tokens are scoped to one organization. They cannot reach another org's packages.

The token is hashed (SHA-256) at rest. The password is hashed with bcrypt. Neither is recoverable; rotate by minting a new one and revoking the old.

Authenticate Composer

Tell Composer to send the token as HTTP Basic credentials for that hostname:

composer config --auth http-basic.repo.example.com YOUR_TOKEN YOUR_PASSWORD

This writes to ~/.composer/auth.json (or auth.json next to composer.json if you pass --global=false). Composer will now send Authorization: Basic <base64(token:password)> on every request to repo.example.com.

Verify:

composer config --auth --list | grep repo.example.com
composer install

If the install resolves your private packages without a 401, you're done.

CI / automation

For unattended environments, prefer auth.json next to composer.json:

{
  "http-basic": {
    "repo.example.com": {
      "username": "YOUR_TOKEN",
      "password": "YOUR_PASSWORD"
    }
  }
}

Then:

COMPOSER_AUTH=$(cat auth.json) composer install

Or expose the same JSON via the COMPOSER_AUTH env var directly so you never have to write the file in CI:

export COMPOSER_AUTH='{"http-basic":{"repo.example.com":{"username":"'"$TOKEN"'","password":"'"$PASS"'"}}}'
composer install --no-interaction --prefer-dist

Heads up. Composer matches http-basic entries by host:port exactly. If your registry runs at a non-standard port, the key must be repo.example.com:9090, not repo.example.com.

Token rotation

  1. Mint a new token in the dashboard.
  2. Update auth.json (or your CI secret) with the new credentials.
  3. Confirm composer install still resolves.
  4. Revoke the old token in the dashboard.

For audit purposes, every token has a "last used" timestamp and a per-token download counter — both visible from the dashboard.

Troubleshooting

  • 401 Unauthorized: confirm the host key in auth.json matches the registry host (and port, if non-standard). Re-run composer config --auth --list to inspect what Composer thinks it has.
  • 404 on a known package: double-check the URL has the right org slug. https://repo.example.com/default/packages.json and https://repo.example.com/acme/packages.json are different endpoints; a token from one org cannot read the other.
  • TLS errors: Packyard binds plain HTTP. For public deployments, terminate TLS at a reverse proxy — see the recipes in the installation guide.
  • Slow first install: metadata builds the first time it's requested, then caches in memory. Subsequent installs hit the in-memory cache. Restarting Packyard clears it; the rebuild is automatic on next request.