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>
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.
This module does not speak AppAPI and does not see APP_SECRET.
ExApp
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
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 |
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.