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

2.2 KiB

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.