OAuth 2.0 and JWT Authorization in Go: From Theory to Practice
\n\nModern web applications and APIs rarely function without a reliable authentication and authorization system. Two standards — OAuth 2.0 and JWT (JSON Web Tokens) — have become de facto standards in the development world. In this article, we will use practical examples to break down how to implement OAuth 2.0 authorization using JWT in the Go language (Golang).
\n\nWe will create a simple REST API server that will issue JWT tokens after successful authentication via an OAuth 2.0 provider (e.g., Google) and verify them with each request.
\n\n1. Basics of OAuth 2.0 and JWT
\n\nBefore writing code, let's briefly understand the terms.
\n\n- \n
- OAuth 2.0 — an authorization protocol that allows users to grant third parties limited access to their resources without sharing their login and password. Main roles: Resource Owner (user), Client (our application), Authorization Server (server issuing tokens), Resource Server (server with protected data). \n
- JWT — a compact, URL-safe token format consisting of three parts: header, payload, and signature. JWT can contain any data (claims) and is signed with a secret key or an RSA key pair. \n
In our implementation, OAuth 2.0 will be used to obtain an identity token from a provider (Google), and then we will generate our own JWT for further work with our API.
\n\n2. Project Setup and Dependencies
\n\nLet's create a new Go project and install the necessary packages:
\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\nWe will use:
\n- \n
- Gin — a fast HTTP framework for Go. \n
- golang-jwt — a library for working with JWT. \n
- oauth2 — the standard Go library for OAuth 2.0. \n
You will also need to register an application in the Google Cloud Console, create an OAuth 2.0 Client ID and Secret, and specify a Redirect URI (e.g., http://localhost:8080/auth/google/callback).
3. Implementing OAuth 2.0 Login via Google
\n\nLet's start by creating the OAuth 2.0 configuration and endpoints for login and callback.
\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 // Generate a random state token for CSRF protection\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