# Biblija SSO Server (WordPress plugin)

Lasten OAuth 2.0 + PKCE strežnik za enotno prijavo (single sign-on) z WordPress računom na biblija.net.

## Lastnosti

- **OAuth 2.0 Authorization Code Grant** s PKCE (S256) — varno za browser SPA-je
- **Refresh tokens** z rotacijo (zaznavanje replay napadov)
- **Token revocation** (`/revoke` endpoint)
- **PASETO-style varnost**: vsi tokeni so v DB shranjeni kot SHA-256 hashi (kompromis DB ≠ kompromis sej)
- **Consent screen** ob prvi avtorizaciji (uporabnik vidi, kaj client zahteva)
- **HMAC-podpisan webhook** ob brisanju uporabnika (delete_user hook)
- **Admin UI** v WP Settings za client_id, client_secret, redirect URI-je, webhook nastavitve
- **Cron cleanup** poteklih artefaktov (urno)
- **Brez composer dependencies** — vse v vanilla PHP/WP

## Namestitev

1. Skopiraj celotno mapo `biblija-sso/` v `wp-content/plugins/` na svetopismo.si.
2. V WP admin → Plugins → aktiviraj "Biblija SSO Server".
3. Pojdi v **Settings → Biblija SSO**:
   - **Client ID**: pusti `biblija-net` (ali izberi svojega)
   - **Client Secret**: klikni "Generiraj nov secret" — secret se enkrat prikaže, shrani ga
   - **Redirect URIs**: dodaj `https://biblija.hozana.si/oauth/callback` (en URL na vrstico)
   - **Webhook URL**: `https://biblija.hozana.si/api/wp-webhook/user-deleted`
   - **Webhook Secret**: generiraj naključen niz ≥32 znakov (npr. `openssl rand -hex 32`)
4. Na biblija.net strežniku ustvari `config/sso.php` z istimi vrednostmi (client_secret + webhook_secret).

## OAuth flow (povzetek za client developerje)

### 1. Authorize redirect

Client preusmeri uporabnika na:

```
https://svetopismo.si/?biblija_sso_action=authorize
  &client_id=biblija-net
  &response_type=code
  &redirect_uri=https://biblija.hozana.si/oauth/callback
  &state=<random_csrf>
  &scope=profile+email
  &code_challenge=<base64url(sha256(code_verifier))>
  &code_challenge_method=S256
```

`code_verifier` mora client generirati naključno (43-128 znakov, URL-safe) in shraniti v session.

### 2. Uporabnik se prijavi + da consent

WP login (če ni že prijavljen) → consent screen → uporabnik klikne "Dovoli" → redirect nazaj:

```
https://biblija.hozana.si/oauth/callback?code=XYZ&state=<isti>
```

Client mora preveriti `state` (CSRF zaščita).

### 3. Code → tokeni

```http
POST https://svetopismo.si/wp-json/biblija-sso/v1/token
Content-Type: application/x-www-form-urlencoded
Authorization: Basic base64(client_id:client_secret)

grant_type=authorization_code
&code=XYZ
&redirect_uri=https://biblija.hozana.si/oauth/callback
&code_verifier=<plain code_verifier>
```

Odgovor:

```json
{
  "access_token": "...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "...",
  "scope": "profile email"
}
```

### 4. Userinfo

```http
GET https://svetopismo.si/wp-json/biblija-sso/v1/userinfo
Authorization: Bearer <access_token>
```

Odgovor:

```json
{
  "sub": "42",
  "email": "ime@example.org",
  "name": "Ime Priimek",
  "preferred_username": "ime",
  "locale": "sl_SI"
}
```

`sub` je WP user ID — uporabi ga kot foreign key na svojem strežniku.

### 5. Refresh

```http
POST .../v1/token
grant_type=refresh_token
&refresh_token=<refresh>
+Basic Auth
```

Pomembno: vsak refresh izda **nov** refresh token, stari postane neveljaven (rotacija).

### 6. Revoke (logout)

```http
POST .../v1/revoke
token=<refresh_or_access_token>
&token_type_hint=refresh_token
```

## Webhook

Ob `delete_user` v WP-ju, plugin pošlje POST na konfiguriran URL:

```http
POST https://biblija.hozana.si/api/wp-webhook/user-deleted
Content-Type: application/json
X-Biblija-Signature: sha256=<hmac>
X-Biblija-Timestamp: 1716832000

{
  "event": "user.deleted",
  "user_id": 42,
  "timestamp": 1716832000,
  "nonce": "0a1b2c..."
}
```

Client mora preveriti:
1. `X-Biblija-Timestamp` je ≤ 5 min star (replay zaščita)
2. `X-Biblija-Signature` se ujema s `hash_hmac('sha256', body, $webhook_secret)`
3. Če da: zbriši lokalne podatke za `wp_user_id = user_id`

## Varnostni model

| Sredstvo | Hramba | Lifetime |
|---|---|---|
| Authorization code | DB SHA-256 hash, used flag | 5 min, one-shot |
| Access token | DB SHA-256 hash | 1h (konfigurabilno) |
| Refresh token | DB SHA-256 hash | 30 dni (konfigurabilno), rotacija ob vsaki uporabi |
| Client secret | DB bcrypt hash | trajno |
| Webhook secret | DB plain (manj kritično) | trajno |

Kompromis DB ne razkrije nobenega plain tokena. Token-leakage v logih je preprečen (logirajo se le `token_hash`-i, nikoli plain).

## Cleanup

Cron `biblija_sso_cleanup` teče urno:
- pobriše authorization kode po 1 min (po expiry-ju)
- pobriše tokens 7 dni po expiry-ju (audit margin)

## Razvoj / testiranje

```bash
# Discovery endpoint (preveri, da REST routes delajo)
curl https://svetopismo.si/wp-json/biblija-sso/v1/discovery

# Token exchange test (potrebuje veljaven code iz authorize flow)
curl -X POST https://svetopismo.si/wp-json/biblija-sso/v1/token \
    -u biblija-net:CLIENT_SECRET \
    -d grant_type=authorization_code \
    -d code=XYZ \
    -d redirect_uri=https://biblija.hozana.si/oauth/callback \
    -d code_verifier=...
```

## Licence

MIT (interni produkt Svetopisemske družbe Slovenije).
