JWT Starter
Introduction
The JWT (JSON Web Token) Starter provides authentication and authorization capabilities for Hiboot applications. It supports token generation, validation, and middleware integration.
Installation
Import the JWT starter in your application:
import "github.com/hidevopsio/hiboot/pkg/starter/jwt"
Configuration
Configure JWT in your application.yml:
app:
profiles:
include:
- jwt
jwt:
# RSA private key file path
private_key_path: "config/keys/private.pem"
# RSA public key file path
public_key_path: "config/keys/public.pem"
Generating RSA Keys
Generate RSA key pair for token signing:
# Generate private key
openssl genrsa -out config/keys/private.pem 2048
# Generate public key from private key
openssl rsa -in config/keys/private.pem -pubout -out config/keys/public.pem
Basic Usage
Token Generation
Inject jwt.Token to generate tokens:
package controller
import (
"time"
"github.com/hidevopsio/hiboot/pkg/app"
"github.com/hidevopsio/hiboot/pkg/at"
"github.com/hidevopsio/hiboot/pkg/model"
"github.com/hidevopsio/hiboot/pkg/starter/jwt"
)
type loginController struct {
at.RestController
at.RequestMapping `value:"/auth"`
token jwt.Token
}
type LoginRequest struct {
model.RequestBody
Username string `json:"username" validate:"required"`
Password string `json:"password" validate:"required"`
}
type LoginResponse struct {
Token string `json:"token"`
ExpiresIn int64 `json:"expires_in"`
}
func init() {
app.Register(newLoginController)
}
func newLoginController(token jwt.Token) *loginController {
return &loginController{
token: token,
}
}
// Post handles POST /auth/login
func (c *loginController) PostLogin(request *LoginRequest) (model.Response, error) {
// Validate credentials (implement your own logic)
if request.Username != "admin" || request.Password != "password" {
response := new(model.BaseResponse)
response.SetCode(401)
response.SetMessage("Invalid credentials")
return response, nil
}
// Generate JWT token
claims := jwt.Map{
"username": request.Username,
"role": "admin",
}
// Token expires in 30 minutes
tokenString, err := c.token.Generate(claims, 30, time.Minute)
if err != nil {
return nil, err
}
response := new(model.BaseResponse)
response.SetData(&LoginResponse{
Token: tokenString,
ExpiresIn: 1800, // 30 minutes in seconds
})
return response, nil
}
JWT Middleware
Use the JWT middleware to protect routes:
package controller
import (
"github.com/hidevopsio/hiboot/pkg/app"
"github.com/hidevopsio/hiboot/pkg/at"
"github.com/hidevopsio/hiboot/pkg/model"
"github.com/hidevopsio/hiboot/pkg/starter/jwt"
)
type protectedController struct {
at.RestController
at.RequestMapping `value:"/api"`
// JWT Middleware for route protection
Middleware *jwt.Middleware `inject:""`
}
func init() {
app.Register(newProtectedController)
}
func newProtectedController() *protectedController {
return &protectedController{}
}
// Before is called before each request
// Use this to apply JWT validation
func (c *protectedController) Before() {
c.Middleware.Serve(c.Ctx)
}
// GetProfile handles GET /api/profile
func (c *protectedController) GetProfile() (model.Response, error) {
// Get claims from context
claims := c.Ctx.Values().Get("jwt").(*jwt.Token)
response := new(model.BaseResponse)
response.SetData(map[string]interface{}{
"username": claims.Get("username"),
"role": claims.Get("role"),
})
return response, nil
}
Token API
jwt.Token Interface
type Token interface {
// Generate creates a new JWT token
Generate(claims Map, expiresAt int64, timeUnit time.Duration) (string, error)
// VerifyKey returns the public key for verification
VerifyKey() interface{}
// SignKey returns the private key for signing
SignKey() interface{}
}
jwt.Map
jwt.Map is an alias for map[string]interface{} used for token claims:
claims := jwt.Map{
"user_id": 123,
"username": "john",
"role": "admin",
"permissions": []string{"read", "write"},
}
Advanced Usage
Custom Token Expiration
// Token valid for 24 hours
token, err := c.token.Generate(claims, 24, time.Hour)
// Token valid for 7 days
token, err := c.token.Generate(claims, 7*24, time.Hour)
// Token valid for 15 minutes
token, err := c.token.Generate(claims, 15, time.Minute)
Extracting Claims from Token
func (c *protectedController) GetUserInfo() (model.Response, error) {
// Access JWT claims from context
jwtValue := c.Ctx.Values().Get("jwt")
if jwtValue == nil {
response := new(model.BaseResponse)
response.SetCode(401)
response.SetMessage("Unauthorized")
return response, nil
}
token := jwtValue.(*jwt.MapClaims)
username := (*token)["username"].(string)
role := (*token)["role"].(string)
response := new(model.BaseResponse)
response.SetData(map[string]interface{}{
"username": username,
"role": role,
})
return response, nil
}
Role-Based Access Control
func (c *adminController) Before() {
c.Middleware.Serve(c.Ctx)
// Check for admin role
jwtValue := c.Ctx.Values().Get("jwt")
if jwtValue != nil {
token := jwtValue.(*jwt.MapClaims)
role := (*token)["role"].(string)
if role != "admin" {
c.Ctx.StatusCode(403)
c.Ctx.JSON(map[string]string{
"error": "Forbidden: Admin access required",
})
c.Ctx.StopExecution()
}
}
}
Making Authenticated Requests
Include the JWT token in the Authorization header:
# Login to get token
TOKEN=$(curl -s -X POST http://localhost:8080/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"password"}' | jq -r '.data.token')
# Make authenticated request
curl http://localhost:8080/api/profile \
-H "Authorization: Bearer $TOKEN"
Configuration Reference
| Property | Description | Default |
|---|---|---|
jwt.private_key_path |
Path to RSA private key | - |
jwt.public_key_path |
Path to RSA public key | - |
What’s Next?
- Auto Configuration - Create custom starters
- Web Application - Build REST APIs
- Actuator Starter - Health checks and metrics