Files
go-usertoken/README.md
T
konradandCursor f082561cc6 Mint and verify short-lived RS256 user tokens.
ExApps sign after AppAPI auth; Microservices check a static public key or an OIDC issuer and forward the same bearer.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-28 14:03:52 +02:00

70 lines
2.2 KiB
Markdown

# go-usertoken
Short-lived RS256 user tokens from a Nextcloud ExApp to Go Microservices.
Import: `gitea.neitzel.de/konrad/go-usertoken` (package `usertoken`).
The ExApp mints a token after AppAPI has named the user. Each Microservice checks that token. One process trusts either a static public key or an OIDC issuer. The same bearer is forwarded when a Microservice calls another.
Procedure and claim rules: Knowledge `platforms/nextcloud/exapps/authentication.md`. Domain words: [CONTEXT.md](./CONTEXT.md).
This module does not speak AppAPI and does not see `APP_SECRET`.
## ExApp
```go
signer, err := usertoken.NewSignerFromEnv()
raw, err := signer.Mint(time.Now(), usertoken.MintInput{
Subject: userID,
Groups: &groupIDs, // nil omits groups
})
req.Header.Set("Authorization", "Bearer "+raw)
```
| Variable | Role |
| --- | --- |
| `USER_TOKEN_PRIVATE_KEY_FILE` | RSA private key PEM |
| `USER_TOKEN_ISSUER` | `iss` string |
| `USER_TOKEN_AUDIENCE` | `aud` string |
| `USER_TOKEN_TTL` | optional, default `5m` |
## Microservice
```go
auth, err := usertoken.FromEnv(ctx)
handler = auth.Middleware()(handler)
caller, _ := usertoken.CallerFromContext(r.Context())
raw, _ := usertoken.BearerFromContext(r.Context())
out.Header.Set("Authorization", "Bearer "+raw)
```
`/health` is not authenticated. Any other path without a valid bearer is 401.
Set one of these. Setting both, or neither, makes `FromEnv` fail.
Static public key (ExApp-minted tokens):
| Variable | Role |
| --- | --- |
| `USER_TOKEN_PUBLIC_KEY_FILE` | RSA public key PEM |
| `USER_TOKEN_ISSUER` | expected `iss` |
| `USER_TOKEN_AUDIENCE` | expected `aud` |
| `USER_TOKEN_SKEW` | optional, default `1m` |
OIDC issuer (Keycloak or another identity server):
| Variable | Role |
| --- | --- |
| `OIDC_ISSUER` | issuer URL that serves discovery |
| `OIDC_AUDIENCE` | expected `aud`; empty skips the check |
| `OIDC_GROUPS_CLAIM` | group array claim, default `groups` (`identity_groups` for current Keycloak tokens) |
| `USER_TOKEN_SKEW` | optional, default `1m` |
```bash
openssl genrsa -out user-token.key 2048
openssl rsa -in user-token.key -pubout -out user-token.pub
```
The private key stays on the ExApp. Static mode copies `user-token.pub` to each Microservice.