OAuth 2.0 y autorización JWT en Go: de la teoría a la práctica
\n\nLas aplicaciones web y API modernas rara vez prescinden de un sistema robusto de autenticación y autorización. Dos estándares — OAuth 2.0 y JWT (JSON Web Tokens) — se han convertido en estándares de facto en el mundo del desarrollo. En este artículo, analizaremos con ejemplos prácticos cómo implementar la autorización OAuth 2.0 utilizando JWT en el lenguaje Go (Golang).
\n\nCrearemos un servidor REST API simple que emitirá tokens JWT después de una autenticación exitosa a través de un proveedor OAuth 2.0 (por ejemplo, Google) y los verificará en cada solicitud.
\n\n1. Fundamentos de OAuth 2.0 y JWT
\n\nAntes de escribir código, aclaremos brevemente los términos.
\n\n- \n
- OAuth 2.0 — es un protocolo de autorización que permite a los usuarios otorgar a terceros acceso limitado a sus recursos sin compartir su nombre de usuario y contraseña. Roles principales: Resource Owner (usuario), Client (nuestra aplicación), Authorization Server (servidor que emite tokens), Resource Server (servidor con datos protegidos). \n
- JWT — es un formato de token compacto y seguro para URL que consta de tres partes: header, payload y signature. JWT puede contener cualquier dato (claims) y se firma con una clave secreta o un par de claves RSA. \n
En nuestra implementación, OAuth 2.0 se utilizará para obtener un token de identidad del proveedor (Google), y luego generaremos nuestro propio JWT para el trabajo posterior con nuestra API.
\n\n2. Configuración del proyecto y dependencias
\n\nCreemos un nuevo proyecto en Go e instalemos los paquetes necesarios:
\n\nmkdir go-oauth-jwt\ncd go-oauth-jwt\ngo mod init example.com/go-oauth-jwt\ngo get github.com/gin-gonic/gin\ngo get github.com/golang-jwt/jwt/v5\ngo get golang.org/x/oauth2\ngo get golang.org/x/oauth2/google\n\nUsaremos:
\n- \n
- Gin — un framework HTTP rápido para Go. \n
- golang-jwt — una biblioteca para trabajar con JWT. \n
- oauth2 — la biblioteca estándar de Go para OAuth 2.0. \n
También necesitarás registrar una aplicación en Google Cloud Console, crear un OAuth 2.0 Client ID y Secret, y especificar la Redirect URI (por ejemplo, http://localhost:8080/auth/google/callback).
3. Implementación del inicio de sesión OAuth 2.0 a través de Google
\n\nComencemos creando la configuración de OAuth 2.0 y los endpoints para el inicio de sesión y la devolución de llamada.
\n\npackage main\n\nimport (\n "crypto/rand"\n "encoding/base64"\n "net/http"\n "os"\n\n "github.com/gin-gonic/gin"\n "golang.org/x/oauth2"\n "golang.org/x/oauth2/google"\n)\n\nvar (\n googleOauthConfig *oauth2.Config\n oauthStateString string\n)\n\nfunc init() {\n googleOauthConfig = &oauth2.Config{\n RedirectURL: "http://localhost:8080/auth/google/callback",\n ClientID: os.Getenv("GOOGLE_CLIENT_ID"),\n ClientSecret: os.Getenv("GOOGLE_CLIENT_SECRET"),\n Scopes: []string{"https://www.googleapis.com/auth/userinfo.email", "https://www.googleapis.com/auth/userinfo.profile"},\n Endpoint: google.Endpoint,\n }\n // Generamos un token state aleatorio para protección contra CSRF\n b := make([]byte, 32)\n rand.Read(b)\n oauthStateString = base64.StdEncoding.EncodeToString(b)\n}\n\nfunc main() {\n r := gin.Default()\n\n r.GET("/auth/google/login", handleGoogleLogin)\n r.GET("/auth/google/callback", handleGoogleCallback)\n\n r.Run(":8080")\n}\n\nfunc handleGoogleLogin(c *gin.Context) {\n url := googleOauthConfig.AuthCodeURL(oauthStateString)\n c.Redirect(http.StatusTemporaryRedirect, url)\n}\n\nfunc handleGoogleCallback(c *gin.Context) {\n state := c.Query("state")\n if state != oauthStateString {\n c.JSON(http.StatusBadRequest, gin.H{"error": "invalid oauth state"})\n return\n }\n\n code := c.Query("code")\n token, err := googl