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>
This commit is contained in:
@@ -1,2 +1,69 @@
|
||||
# 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.
|
||||
|
||||
Reference in New Issue
Block a user