You’ve just bought a license β this page takes you from an empty StarterKit Foundation project to
a working composer update. The checkout success page and the purchase email show the same steps
with your real license key, email, and licensing host already filled in β copy the ready-made line
from there rather than retyping it here.
1. Your license key
The license key is the Composer HTTP-basic password; the email address you used at checkout is the username. Keep the key private β never commit it to a repository or paste it into a public issue.
2. Composer credentials β config/environment/.env.secret
Add one line to config/environment/.env.secret in your StarterKit project β unescaped JSON, one
line, no spaces:
COMPOSER_AUTH={"http-basic":{"<licensing-host>":{"username":"<your-email>","password":"<your-license-key>"}}}
The file is gitignored β never commit it. The Composer container reads COMPOSER_AUTH from it
automatically. See Environment & Secrets for the full environment
file layout.
3. CI/CD (GitHub Actions) β repository secret
GitHub β Settings β Secrets and variables β Actions β New repository secret. Name it
COMPOSER_AUTH and paste only the value, with no COMPOSER_AUTH= prefix. GitHub requires the
escaped form (every " backslash-prefixed), which is why it differs from step 2:
{\"http-basic\":{\"<licensing-host>\":{\"username\":\"<your-email>\",\"password\":\"<your-license-key>\"}}}
See CI/CD Deployments for how the deploy pipeline consumes this secret.
4. composer.json β repository and modules
A StarterKit Foundation project already ships both entries below β this step is only for a project
that lost them, or one that was not built on Foundation. repositories[0] points at the licensing
repository, and one require entry per granted module is added at "*"; constraints are left at
* and should be pinned per project.
{
"repositories": [
{
"type": "composer",
"url": "https://<licensing-host>"
}
],
"require": {
"solidbunch/<module-slug>": "*"
}
}
5. Install the modules
From the project root, run Composer inside its dedicated container β never on the host, never
docker compose run directly. See Composer usage for why: ownership/UID
mismatch and version skew.
make run composer
composer update
Granted modules land in kit-modules/.
Verify the install
Check composer.lock: a licensed module has a real "dist" block ("type": "zip", a real URL).
Without valid credentials, Composer degrades the package to "type": "metapackage" instead of
failing loudly β that is the single most important thing on this page.
grep -A4 '"name": "solidbunch/<module-slug>"' composer.lock
A good entry looks like this:
"name": "solidbunch/<module-slug>",
"dist": {
"type": "zip",
"url": "https://<licensing-host>/..."
}
A bad entry (no real credentials, or license does not grant the module) looks like this:
"name": "solidbunch/<module-slug>",
"type": "metapackage"
Also run ls kit-modules/ β it should show real directories containing code, not just an empty or
missing folder.
When it does not work
- 401 Unauthorized / “Invalid credentials” while downloading from the licensing repo. Wrong
email or wrong key β a typo, a trailing space, wrong quoting in the JSON, or the escaped form
used in
.env.secretinstead of the unescaped one. Fix: re-copy both values from the success page or the purchase email, then re-runmake run composerandcomposer update. - Package installed but composer.lock says
"type": "metapackage". Credentials worked, but the license does not grant that module (for example, a Free/Pro tier asked for an Enterprise-only module). Nothing is broken locally β the fix is an upgraded license, not a config change. - Everything worked before and now returns the same 401-style failure. The license has expired β not a typo. Fix: renew the license, then re-run the install; the key itself does not change on renewal unless the storefront says otherwise.