Introducción a OAuth 2.0 y JWT en Go
Las aplicaciones web modernas y las API requieren un sistema de autenticación y autorización robusto y seguro. Los dos estándares más populares en este ámbito son OAuth 2.0 y JWT (JSON Web Tokens). En el lenguaje Go (Golang), la implementación de estos mecanismos se vuelve especialmente eficiente gracias al soporte incorporado de concurrencia, alto rendimiento y un rico ecosistema de bibliotecas.
En este artículo, analizaremos en detalle cómo implementar la autorización OAuth 2.0 y JWT en Go. Aprenderá a configurar el servidor, generar y verificar tokens, así como proteger sus endpoints. El material será útil tanto para desarrolladores Go principiantes como experimentados.
Fundamentos de OAuth 2.0 y JWT
¿Qué es OAuth 2.0?
OAuth 2.0 es un protocolo de autorización que permite a las aplicaciones obtener acceso limitado a los recursos del usuario sin transmitir la contraseña. En su lugar, se utilizan tokens de acceso (access tokens). Los participantes principales del proceso son:
- Resource Owner — el usuario propietario de los datos
- Client — la aplicación que solicita acceso
- Authorization Server — el servidor que emite los tokens
- Resource Server — el servidor que proporciona los recursos protegidos
¿Qué es JWT?
JWT (JSON Web Token) es un formato compacto y autónomo para transferir datos entre partes en forma de objeto JSON. El token consta de tres partes separadas por puntos:
header.payload.signature
Ventajas de JWT:
- No requiere almacenar sesiones en el servidor (stateless)
- Contiene toda la información necesaria (claims)
- Está firmado para verificar la integridad
Implementación de autorización JWT en Go
Para trabajar con JWT en Go, utilizaremos la popular biblioteca golang-jwt/jwt/v5. Instálela con el comando:
go get github.com/golang-jwt/jwt/v5
Generación de token JWT
Creemos una función para generar tokens de acceso y actualización:
package auth
import (
"time"
"github.com/golang-jwt/jwt/v5"
)
var jwtSecret = []byte("your-secret-key")
type Claims struct {
UserID uint `json:"user_id"`
Email string `json:"email"`
jwt.RegisteredClaims
}
func GenerateAccessToken(userID uint, email string) (string, error) {
claims := &Claims{
UserID: userID,
Email: email,
RegisteredClaims: jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(time.Now().Add(15 * time.Minute)),
IssuedAt: jwt.NewNumericDate(time.Now()),
Issuer: "myapp",
},
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
return token.SignedString(jwtSecret)
}
func GenerateRefreshToken(userID uint) (string, error) {
claims := &Claims{
UserID: userID,
RegisteredClaims: jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(time.Now().Add(7 * 24 * time.Hour)),
IssuedAt: jwt.NewNumericDate(time.Now()),
},
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
return token.SignedString(jwtSecret)
}
Verificación de token JWT
Middleware para verificar el token en solicitudes HTTP:
package middleware
import (
"net/http"
"strings"
"github.com/gin-gonic/gin"
"myapp/auth"
)
func AuthMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
authHeader := c.GetHeader("Authorization")
if authHeader == "" {
c.JSON(http.StatusUnauthorized, gin.H{"error": "missing authorization header"})
c.Abort()
return
}
tokenString := strings.TrimPrefix(authHeader, "Bearer ")
if tokenString == authHeader {