README
¶
02: Resource Token with HS256 (Federated Auth)
Non-UI | No infrastructure needed | Builds on Example 01
What you'll learn
- Start auth server and resource server — Same as Example 01, but now the resource server also extracts the
client_idclaim to know which app minted the token. - Register an app with HS256 signing — The app gets a client_id and a shared secret. The secret is stored in the KeyStore — both the app and resource server can use it for signing/verification.
- Mint a resource token for user Alice — The app creates a JWT with sub=alice, signed with its HS256 secret. The token includes quota claims (max_rooms) for resource-level enforcement.
- Mint a resource token for user Bob (different scopes) — Same app, different user, different permissions. Bob gets read-only access with a lower room quota.
- Resource server validates Alice's token — The resource server validates the JWT using the app's key from the shared KeyStore. It extracts the user ID, scopes, and quota claims.
- Resource server validates Bob's token — Same resource server, different user — Bob's token has fewer scopes and a lower quota.
- Token signed with wrong secret is rejected — A token signed with the wrong secret fails signature verification — the resource server rejects it immediately.
Flow
sequenceDiagram
participant App as Your App
participant AS as Auth Server
participant RS as Resource Server
Note over App,RS: Step 1: Start auth server and resource server
Note over App,RS: Step 2: Register an app with HS256 signing
App->>AS: POST /apps/register {domain: myapp.example.com, signing_alg: HS256}
AS-->>App: {client_id, client_secret}
Note over App,RS: Step 3: Mint a resource token for user Alice
App->>App: MintResourceToken(alice, scopes=[read,write], max_rooms=10)
Note over App,RS: Step 4: Mint a resource token for user Bob (different scopes)
App->>App: MintResourceToken(bob, scopes=[read], max_rooms=3)
Note over App,RS: Step 5: Resource server validates Alice's token
App->>RS: GET /resource (Bearer: alice's token)
RS->>RS: Validate HS256 signature via KeyStore
RS-->>App: 200 {user: alice, scopes: [read,write], max_rooms: 10}
Note over App,RS: Step 6: Resource server validates Bob's token
App->>RS: GET /resource (Bearer: bob's token)
RS-->>App: 200 {user: bob, scopes: [read], max_rooms: 3}
Note over App,RS: Step 7: Token signed with wrong secret is rejected
App->>App: MintResourceToken(eve, secret=wrong-secret)
App->>RS: GET /resource (Bearer: bad token)
RS-->>App: 401 Unauthorized
Steps
How this differs from Example 01
Actors: App, Auth Server (AS), Resource Server (RS). Think: the GitHub bot now posts to Slack as Alice, not as itself. What are these?
In 01 — Client Credentials, the bot got a token representing itself (sub=client_id). That's machine-to-machine auth.
Here, the app registers with the auth server and gets a shared secret (HS256).
Then it uses admin.MintResourceToken() to create JWTs for individual users.
Each token carries:
sub= the user's ID (not the app's)client_id= the app that minted itscopes= what this user can do- Quota claims (max_rooms, max_msg_rate) for resource-level limits
The resource server validates these tokens using the same KeyStore — it trusts the app's signing key without calling back to the auth server.
Step 1: Start auth server and resource server
Same as Example 01, but now the resource server also extracts the client_id claim to know which app minted the token.
Step 2: Register an app with HS256 signing
References: RFC 7515 — JSON Web Signature (JWS)
The app gets a client_id and a shared secret. The secret is stored in the KeyStore — both the app and resource server can use it for signing/verification.
MintResourceToken vs client_credentials
MintResourceToken is a library call, not an HTTP endpoint. The app calls it
directly in its own process to create a JWT signed with the shared secret.
This is different from the client_credentials grant in Example 01, where the
app POSTs to the auth server's token endpoint. Here the app is trusted to mint
tokens itself — the auth server just manages key registration.
Think of it like this:
- client_credentials: "Auth server, give ME a token"
- MintResourceToken: "I'll make a token FOR this user, signed with my key"
Step 3: Mint a resource token for user Alice
References: RFC 7519 — JSON Web Token (JWT), RFC 7515 — JSON Web Signature (JWS), RFC 7638 — JWK Thumbprint (kid)
The app creates a JWT with sub=alice, signed with its HS256 secret. The token includes quota claims (max_rooms) for resource-level enforcement.
Step 4: Mint a resource token for user Bob (different scopes)
References: RFC 7519 — JSON Web Token (JWT)
Same app, different user, different permissions. Bob gets read-only access with a lower room quota.
Step 5: Resource server validates Alice's token
References: RFC 6750 — Bearer Token Usage, RFC 7515 — JSON Web Signature (JWS)
The resource server validates the JWT using the app's key from the shared KeyStore. It extracts the user ID, scopes, and quota claims.
Step 6: Resource server validates Bob's token
Same resource server, different user — Bob's token has fewer scopes and a lower quota.
Step 7: Token signed with wrong secret is rejected
References: RFC 7515 — JSON Web Signature (JWS)
A token signed with the wrong secret fails signature verification — the resource server rejects it immediately.
What's next?
In 03 — Resource Token (RS256 + JWKS), you'll see the asymmetric version: the app registers a public key, serves it via JWKS, and the resource server discovers it automatically. No shared secrets — the resource server never sees the private key.
References
- RFC 7519 — JSON Web Token (JWT)
- RFC 7638 — JWK Thumbprint (kid)
- RFC 6750 — Bearer Token Usage
- RFC 7515 — JSON Web Signature (JWS)
Run it
go run ./examples/02-resource-token-hs256/
Pass --non-interactive to skip pauses:
go run ./examples/02-resource-token-hs256/ --non-interactive
Documentation
¶
Overview ¶
Example 02: Resource Token with HS256 (Federated Auth)
Building on Example 01, this shows how a registered app can mint resource-scoped tokens for individual users — not just for itself. This is OneAuth's federated authentication pattern.
In Example 01: client_credentials → token with sub=client_id (machine identity) In this example: app registers → mints per-user tokens → resource server validates
Run: go run ./examples/02-resource-token-hs256/ Docs: Run with --readme to regenerate README.md
See: https://www.rfc-editor.org/rfc/rfc7519 (JWT)