How CasaOS Implements JWT-Based Authentication and Token Management
CasaOS validates every API request using JSON Web Tokens (JWT) processed through Echo middleware that verifies ECDSA signatures against a runtime public key and injects the user ID into request headers for downstream handlers.
CasaOS is an open-source home cloud platform developed by IceWhaleTech that secures its REST APIs using stateless JWT-based authentication. The implementation leverages the Echo web framework alongside cryptographic utilities from the CasaOS-Common library to enforce token validation on all /v1 and /v2 endpoints.
JWT Middleware Integration in the Echo Router
CasaOS centralizes authentication logic in dedicated router files, applying middleware during route group initialization. This approach ensures consistent protection across the entire API surface without requiring individual handler modifications.
Token Validation Pipeline in route/v1.go and route/v2.go
The router configuration in route/v1.go (lines 44-56) and route/v2.go (lines 71-84) applies echo_middleware.JWTWithConfig to the API groups. The middleware configuration defines a custom ParseTokenFunc that delegates cryptographic validation to jwt.Validate from the CasaOS-Common package.
The configuration includes three critical components:
- Skipper function: Returns
truefor localhost requests (::1or127.0.0.1), bypassing authentication for local development - ParseTokenFunc: Validates the token signature using an ECDSA public key retrieved via
external.GetPublicKey(config.CommonInfo.RuntimePath) - TokenLookupFuncs: Extracts tokens from either the
Authorizationheader (Bearer scheme) or thetokenquery parameter
// route/v1.go – lines 44-56
v1Group.Use(echo_middleware.JWTWithConfig(echo_middleware.JWTConfig{
Skipper: func(c echo.Context) bool {
return c.RealIP() == "::1" || c.RealIP() == "127.0.0.1"
},
ParseTokenFunc: func(token string, c echo.Context) (interface{}, error) {
valid, claims, err := jwt.Validate(
token,
func() (*ecdsa.PublicKey, error) {
return external.GetPublicKey(config.CommonInfo.RuntimePath)
})
if err != nil || !valid {
return nil, echo.ErrUnauthorized
}
c.Request().Header.Set("user_id", strconv.Itoa(claims.ID))
return claims, nil
},
TokenLookupFuncs: []echo_middleware.ValuesExtractor{
func(ctx echo.Context) ([]string, error) {
if len(ctx.Request().Header.Get(echo.HeaderAuthorization)) > 0 {
return []string{ctx.Request().Header.Get(echo.HeaderAuthorization)}, nil
}
return []string{ctx.QueryParam("token")}, nil
},
},
}))
Asymmetric Key Verification
The validation process uses asymmetric cryptography rather than shared secrets. The jwt.Validate function receives a callback returning an *ecdsa.PublicKey loaded from the runtime path. This design eliminates the need to distribute private signing keys to the API server, maintaining a secure separation between token issuance and verification.
Token Extraction and Claims Processing
Once the middleware validates the signature, it processes the JWT claims to identify the requesting user and make that context available to business logic.
Authorization Header and Query Parameter Support
The middleware supports dual token sources through the TokenLookupFuncs array. It first checks the Authorization header for a Bearer token. If the header is absent, it falls back to the token query parameter, enabling authentication in scenarios such as WebSocket connections or direct browser links where header manipulation is difficult.
User ID Propagation to Downstream Handlers
After successful validation, the middleware extracts the ID field from the JWT claims and injects it into the request header as user_id. This allows handlers to access the authenticated user identifier via c.Request().Header.Get("user_id") without re-parsing the token. The claims object includes standard JWT fields such as exp (expiration) and iat (issued at) alongside the user-specific ID.
Configuration and Public Key Management
CasaOS maintains JWT configuration in internal/conf/config.go, which includes a JwtSecret field defined as:
JwtSecret string `json:"jwt_secret" env:"JWT_SECRET"`
While this field supports symmetric HMAC signing as a fallback, the current implementation exclusively uses the asymmetric approach. The system loads the ECDSA public key from config.CommonInfo.RuntimePath using the external.GetPublicKey utility provided by CasaOS-Common, reading the PEM-encoded key at runtime.
Practical Implementation Examples
Making an Authenticated Request
Use the Bearer token scheme in the Authorization header:
curl -H "Authorization: Bearer $TOKEN" \
http://localhost:80/v1/sys/hardware
Accessing User Context in Handlers
Retrieve the authenticated user ID from the injected header:
func GetSystemHardwareInfo(c echo.Context) error {
userID := c.Request().Header.Get("user_id")
log.Printf("hardware request from user %s", userID)
// Implement business logic here
return c.JSON(http.StatusOK, hardwareInfo)
}
Authenticating via Query Parameter
For requests where headers cannot be set:
http://localhost:80/v1/file?token=eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9...
Summary
- Centralized Middleware: CasaOS uses
echo_middleware.JWTWithConfiginroute/v1.goandroute/v2.goto protect all API endpoints under/v1and/v2 - ECDSA Verification: Token validation relies on asymmetric cryptography with public keys loaded from
config.CommonInfo.RuntimePathviaexternal.GetPublicKey - Flexible Token Sources: The system accepts tokens from the
Authorizationheader (Bearer) or thetokenquery parameter - Context Propagation: Validated user IDs propagate to handlers via the
user_idrequest header, enabling stateless user identification - Hybrid Configuration: While
internal/conf/config.goincludesJwtSecretfor symmetric signing, the active implementation uses ECDSA verification exclusively
Frequently Asked Questions
How does CasaOS validate JWT tokens on each request?
CasaOS validates JWT tokens through a custom ParseTokenFunc configured in the Echo middleware. This function calls jwt.Validate from the CasaOS-Common library, which verifies the token's ECDSA signature against the public key stored in the runtime directory. Validation occurs automatically for every request to /v1 and /v2 endpoints, rejecting unauthorized requests with a 401 status before they reach business logic.
What signing algorithm does CasaOS use for JWT verification?
CasaOS implements ECDSA (Elliptic Curve Digital Signature Algorithm) for JWT verification. The middleware uses a public key loaded via external.GetPublicKey(config.CommonInfo.RuntimePath) to verify signatures. While the configuration struct includes a JwtSecret field for symmetric HMAC signing, the current implementation exclusively uses the asymmetric ECDSA approach.
Where does CasaOS store the public key for token verification?
The public key resides in the runtime path specified by config.CommonInfo.RuntimePath. The external.GetPublicKey function in CasaOS-Common reads the PEM-encoded ECDSA public key from this location. This design allows the main CasaOS application to verify tokens without access to the private signing key, which remains secured in the authentication service or key management system.
Can CasaOS fall back to symmetric JWT signing?
Yes, the codebase includes infrastructure for symmetric signing through the JwtSecret configuration field in internal/conf/config.go. However, the current middleware implementation in route/v1.go and route/v2.go does not utilize this secret, instead relying exclusively on the ECDSA public key validation via jwt.Validate. The symmetric option remains available for future implementation or custom builds requiring HMAC-based verification.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →