# Blessing Skin — auth + skin server (Drasl alternative)

## Summary

Drop-in alternative to Drasl (`plan/03-drasl.md`). Blessing Skin Server (BSS) is
a PHP skin station; the **yggdrasil-api plugin** gives it a Yggdrasil API that
authlib-injector talks to — same end result as Drasl, different internals.

Run it as an override **instead of** Drasl:

```
docker compose -f docker-compose.yml -f docker-compose.blessingskin.yml up -d
```

The override (`docker-compose.blessingskin.yml`) repoints Caddy's `auth.*` vhost
at `blessing-skin:80`, adds `mariadb` + `blessing-skin`, and switches the
Minecraft authlib endpoint to `/api/yggdrasil`. Drasl stays defined but idle and
unreachable (compose merges `depends_on`, so an override can't remove it);
`docker compose … stop drasl` after up if you want it down.

## Drasl vs Blessing Skin — what changes

| | Drasl | Blessing Skin |
|---|---|---|
| Backend | single Go binary | PHP app + **MariaDB** (no SQLite) |
| Config | rendered `config.toml` | **web install wizard** + DB |
| Yggdrasil API | built in | **yggdrasil-api plugin** (install + enable) |
| authlib endpoint | `…/authlib-injector` | `…/api/yggdrasil` |
| OIDC/Keycloak | supported (future) | not native (OAuth plugins exist) |
| Server online-mode | repo used FALSE | **TRUE** (real session validation) |

## Setup (first run)

1. `cp .env.example .env`, fill the `BS_*` vars. Generate `BS_APP_KEY`:
   ```
   docker run --rm azusamikan/blessing-skin-server-docker:latest \
     php artisan key:generate --show
   ```
2. Bring the stack up with the override (command above).
3. Open `http://auth.${BASE_DOMAIN}` → BSS install wizard. DB host = `mariadb`,
   port `3306`, name/user/pass = the `BS_*` values. Create the admin account.
4. Admin panel → **Plugins → Plugin Market** → install **yggdrasil-api** →
   enable it. (Needs internet; for air-gap, pre-place the plugin jar/zip into
   the `bs_plugins` volume.) After enabling, the API root is live at
   `http://auth.${BASE_DOMAIN}/api/yggdrasil`.
5. Each player: register on the BSS site, add a character whose name == their
   in-game player name, upload a skin.
6. Restart minecraft if it came up before the plugin was enabled.

## Client (Prism / authlib-injector)

- authlib-injector URL: `http://auth.${BASE_DOMAIN}/api/yggdrasil`
- Login = BSS **email + password** (BSS uses email as the account id).
- Must match the server's `-javaagent` arg exactly (same host + path).

## Gotchas

- **`/api/yggdrasil`, not `/authlib-injector`.** Wrong path → silent "Invalid
  session". Server `JVM_OPTS` and every client must agree.
- **ONLINE_MODE=TRUE.** authlib-injector only authenticates when online-mode is
  on; the server then validates the join against BSS. (The Drasl variant in this
  repo set FALSE — do not copy that here.)
- **Secure profile (1.21+).** Override ships `ENFORCE_SECURE_PROFILE=FALSE` for
  safety. yggdrasil-api *does* sign profile keys, so TRUE may work — flip and
  test if signed chat matters; revert on "Invalid signature".
- **APP_KEY must persist.** Set `BS_APP_KEY` in `.env`. Losing it invalidates
  all sessions and breaks encrypted data.
- **DB is the source of truth.** `bs_db` volume holds accounts; `bs_storage`
  holds skins; `bs_plugins` holds the yggdrasil-api plugin. Back these up.
- **Air-gap:** the plugin market needs internet. Install + enable yggdrasil-api
  while online (it persists in `bs_plugins`), or stage the plugin manually.

## Image note

`azusamikan/blessing-skin-server-docker:latest` is a community image and the
env-var names (`DB_*`, `APP_KEY`) may differ slightly by tag — if auto-config
doesn't take, the web wizard is the reliable path. Official source:
https://github.com/bs-community/blessing-skin-server ,
plugin: https://github.com/bs-community/yggdrasil-api , authlib-injector setup:
https://github.com/bs-community/blessing-skin-manual/blob/master/man/yggdrasil-api/authlib-injector.md
