Servicio REST en Go para generar y verificar tokens JWT firmados con HS256, ideal para autenticación y autorización segura en aplicaciones.
package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
"time"
"github.com/golang-jwt/jwt/v5"
)
// Clave secreta usada para firmar los tokens JWT (en producción debe gestionarse de forma segura)
const jwtSecret = "questa_e_una_chiave_segreta_molto_lunga_e_sicura"
// Payload representa los datos personalizados contenidos en el token JWT
// Puedes agregar otros campos a tu gusto
type Payload struct {
Username string `json:"username"`
Role string `json:"role"`
// Puedes agregar otros campos como Email, Exp, Issuer, etc.
}
// ResponseToken representa la respuesta JSON con el token JWT generado
type ResponseToken struct {
Token string `json:"token"`
}
// ResponseVerify representa la respuesta JSON para la verificación del token
// Indica si el token es válido y devuelve la carga decodificada
type ResponseVerify struct {
Valid bool `json:"valid"`
Payload Payload `json:"payload,omitempty"`
Error string `json:"error,omitempty"`
}
// generaToken crea un token JWT firmado con HS256 a partir del payload proporcionado
func generaToken(payload Payload) (string, error) {
// Creamos un nuevo token JWT
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
"username": payload.Username,
"role": payload.Role,
"iat": time.Now().Unix(), // Emitido en
"exp": time.Now().Add(time.Hour * 1).Unix(), // Expira en 1 hora
})
// Firmamos el token con la clave secreta
tokenString, err := token.SignedString([]byte(jwtSecret))
if err != nil {
return "", err
}
return tokenString, nil
}
// verificaToken decodifica y verifica la validez del token JWT
func verificaToken(tokenString string) (Payload, error) {
// ParseWithClaims permite especificar el tipo de claims esperados
claims := jwt.MapClaims{}
token, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) {
// Verificamos que el algoritmo de firma sea HS256
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("algoritmo de firma no válido")
}
return []byte(jwtSecret), nil
})
if err != nil {
return Payload{}, err
}
if !token.Valid {
return Payload{}, fmt.Errorf("token no válido")
}
// Extraemos los datos del payload
username, ok1 := claims["username"].(string)
role, ok2 := claims["role"].(string)
if !ok1 || !ok2 {
return Payload{}, fmt.Errorf("payload del token malformado")
}
return Payload{Username: username, Role: role}, nil
}
// handler para generar un token JWT a partir de un payload JSON
func handleGenerateToken(w http.ResponseWriter, r *http.Request) {
// Establecemos header para respuesta JSON
w.Header().Set("Content-Type", "application/json")
// Decodificamos el payload JSON de la solicitud
var payload Payload
err := json.NewDecoder(r.Body).Decode(&payload)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
json.NewEncoder(w).Encode(map[string]string{"error": "payload JSON no válido"})
return
}
// Generamos el token JWT
token, err := generaToken(payload)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
json.NewEncoder(w).Encode(map[string]string{"error": "error al generar el token"})
return
}
// Respondemos con el token generado
json.NewEncoder(w).Encode(ResponseToken{Token: token})
}
// handler para verificar un token JWT
func handleVerifyToken(w http.ResponseWriter, r *http.Request) {
// Establecemos header para respuesta JSON
w.Header().Set("Content-Type", "application/json")
// Estructura para recibir el token de la solicitud
type RequestToken struct {
Token string `json:"token"`
}
var reqToken RequestToken
err := json.NewDecoder(r.Body).Decode(&reqToken)
if err != nil || reqToken.Token == "" {
w.WriteHeader(http.StatusBadRequest)
json.NewEncoder(w).Encode(ResponseVerify{Valid: false, Error: "token faltante o JSON no válido"})
return
}
// Verificamos el token
payload, err := verificaToken(reqToken.Token)
if err != nil {
w.WriteHeader(http.StatusUnauthorized)
json.NewEncoder(w).Encode(ResponseVerify{Valid: false, Error: err.Error()})
return
}
// Token válido, respondemos con el payload
json.NewEncoder(w).Encode(ResponseVerify{Valid: true, Payload: payload})
}
func main() {
// Registramos los endpoints HTTP
http.HandleFunc("/generate-token", handleGenerateToken)
http.HandleFunc("/verify-token", handleVerifyToken)
// Iniciamos el servidor HTTP en el puerto 8080
fmt.Println("Servidor iniciado en el puerto 8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}
// Para probar:
// 1) POST /generate-token con body JSON {"username":"mario", "role":"admin"}
// recibirás un token JWT
// 2) POST /verify-token con body JSON {"token":"<token recibido>"}
// recibirás validez y payload decodificadoGo 1.20+ como lenguaje de programación
Biblioteca github.com/golang-jwt/jwt/v5 para creación y verificación de JWT
Módulo Go con gestión de módulos (go.mod) para dependencias
Servidor HTTP nativo de Go (net/http) para exponer APIs REST
Configuración: clave secreta para firma HS256 definida como constante
Endpoint POST /generate-token: recibe carga JSON, devuelve token JWT
Endpoint POST /verify-token: recibe token JWT, devuelve validez y carga decodificada
Estructura de datos Payload personalizada para contener datos de usuario (ej. username, rol)
Manejo robusto de errores con respuestas HTTP apropiadas y mensajes JSON
Archivo README.md (no incluido en el código) con instrucciones de ejecución y prueba
Ningún hardware Arduino involucrado en este proyecto de software