This example demonstrates how to integrate OAuth 2.0 SSO (Single Sign-On) with gin-jwt, supporting multiple identity providers.
- Support for multiple OAuth providers (Google, GitHub)
- OAuth 2.0 Authorization Code Flow
- CSRF protection (using state tokens)
- JWT token generation and management
- Secure httpOnly cookie-based authentication
- Token refresh mechanism
- Protected API endpoints
- Automatic cleanup of expired state tokens
The fastest way to test this example:
# 1. Navigate to the example directory
cd _example/oauth_sso
# 2. Install dependencies
go mod download
# 3. Run without OAuth (view API structure only)
go run server.go
# 4. Visit the demo page
open http://localhost:8000/demoFor full OAuth functionality, follow the setup steps below.
- Go 1.24 or higher
- Google OAuth 2.0 credentials (if using Google login)
- GitHub OAuth App credentials (if using GitHub login)
- Go to Google Cloud Console
- Create a new project or select an existing one
- Enable "Google+ API"
- Navigate to "Credentials"
- Create "OAuth 2.0 Client ID"
- Select "Web application" as application type
- Add authorized redirect URI:
http://localhost:8000/auth/google/callback - Note down the Client ID and Client Secret
- Go to GitHub Settings > Developer settings > OAuth Apps
- Click "New OAuth App"
- Fill in application information:
- Application name: Your application name
- Homepage URL:
http://localhost:8000 - Authorization callback URL:
http://localhost:8000/auth/github/callback
- Click "Register application"
- Note down the Client ID and Client Secret
Create a .env file or set environment variables in terminal:
# Google OAuth (Optional)
export GOOGLE_CLIENT_ID="your-google-client-id"
export GOOGLE_CLIENT_SECRET="your-google-client-secret"
# GitHub OAuth (Optional)
export GITHUB_CLIENT_ID="your-github-client-id"
export GITHUB_CLIENT_SECRET="your-github-client-secret"
# JWT Secret Key (recommended to use strong password in production)
export JWT_SECRET_KEY="your-secret-key-here"
# Server Port (optional, default is 8000)
export PORT="8000"go mod downloadgo run server.go
# or use Makefile
make runThe server will start at http://localhost:8000
Visit http://localhost:8000/demo to use the built-in interactive demo page:
- Graphical interface
- One-click login
- Automatic token management
- Real-time testing of all API features
The demo page provides the easiest way to test!
GET /- Home page, displays available endpointsGET /auth/google/login- Initiate Google OAuth login flowGET /auth/github/login- Initiate GitHub OAuth login flowGET /auth/google/callback- Google OAuth callback endpointGET /auth/github/callback- GitHub OAuth callback endpointPOST /auth/refresh- Refresh JWT token
GET /api/profile- Get user profilePOST /api/logout- Logout
Visit the login URL:
# Google login
curl http://localhost:8000/auth/google/login
# GitHub login
curl http://localhost:8000/auth/github/loginThe browser will redirect to the OAuth provider's authorization page.
After user authorization, they will be redirected to the demo page. The server provides the JWT token via two methods:
- httpOnly Cookie - Automatically set by the server (for browser apps)
- Authorization Header - Included in the response (for API clients/mobile apps)
The callback URL will be:
/demo?provider=google (or github)Dual Token Delivery:
For browser applications:
- Token stored in httpOnly cookie (prevents XSS attacks)
- Automatically sent with same-origin requests
- No JavaScript handling needed
For mobile/desktop apps:
- Token available in
Authorizationresponse header - Format:
Authorization: Bearer <jwt_token> - Client can extract and store securely
Token structure (RFC 6749 OAuth 2.0 standard format):
access_token: JWT access tokentoken_type: Token type (usually "Bearer")refresh_token: Refresh token (used to refresh access token)expires_at: Unix timestamp, token expiration time
The demo page automatically handles cookie-based authentication.
The JWT token can be sent via:
- Cookie (automatic with browser requests)
- Authorization header (for API clients)
- Query parameter (not recommended for security)
Using curl with Authorization header:
curl -H "Authorization: Bearer YOUR_JWT_TOKEN" \
http://localhost:8000/api/profileUsing curl with cookie (after login):
curl --cookie-jar cookies.txt --cookie cookies.txt \
http://localhost:8000/api/profileResponse:
{
"code": 200,
"user": {
"id": "google_123456",
"email": "user@example.com",
"name": "User Name",
"provider": "google",
"avatar_url": "https://..."
},
"claims": {
"id": "google_123456",
"email": "user@example.com",
"name": "User Name",
"provider": "google",
"avatar": "https://...",
"exp": 1704110400,
"iat": 1704106800
}
}When the access token is about to expire, you can use the refresh endpoint (requires a valid access token):
curl -X POST \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
http://localhost:8000/auth/refreshResponse format:
{
"access_token": "new_token_here",
"token_type": "Bearer",
"refresh_token": "new_refresh_token_here",
"expires_at": 1704110400,
"created_at": 1704106800
}curl -X POST \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
http://localhost:8000/api/logoutThis example uses httpOnly cookies and Authorization headers for enhanced security and flexibility. The configuration is in initJWTParams():
SendCookie: true, // Enable automatic cookie handling
CookieHTTPOnly: true, // Prevent JavaScript access (XSS protection)
SecureCookie: false, // Set to true in production with HTTPS
CookieMaxAge: time.Hour, // Cookie expiration
SendAuthorization: true, // Send Authorization header in response
TokenLookup: "header: Authorization, query: token, cookie: jwt",This example supports both authentication methods:
-
httpOnly Cookie (Enabled via
SendCookie: true)- Automatically set by server on login
- Cannot be accessed by JavaScript (XSS protection)
- Automatically sent with same-origin requests
- Best for browser-based applications
-
Authorization Header (Enabled via
SendAuthorization: true)- Included in LoginResponse:
Authorization: Bearer <token> - Can be extracted by client applications
- Best for mobile apps and API clients
- Traditional REST API approach
- Included in LoginResponse:
✅ XSS Protection: JavaScript cannot access the token ✅ Automatic: Cookies sent automatically with same-origin requests ✅ Secure: Better than localStorage or URL parameters ✅ CSRF Protected: Combined with state tokens for OAuth flow
✅ API Clients: Easy to integrate with mobile/desktop apps ✅ Flexibility: Client controls token storage ✅ Standard: RESTful API convention ✅ Cross-Domain: Works with CORS without credentials
- Browser (Web App): Uses cookies automatically (no JavaScript needed)
- Mobile Apps: Extract token from Authorization header, store securely
- API Clients: Use Authorization header for requests
- Hybrid Apps: Can use either method based on preference
- Uses randomly generated state tokens to prevent CSRF attacks
- State tokens have a 10-minute validity period
- Tokens are immediately deleted after verification
- JWT tokens use HS256 signing algorithm
- Tokens have a 1-hour validity period
- Can be refreshed within 24 hours
- Stored in httpOnly cookies (cannot be accessed by JavaScript)
- Recommended to use environment variables for strong passwords in production
- Use HTTPS: Must use HTTPS in production environments (set
SecureCookie: true) - Environment Variables: Don't hardcode secrets in code
- httpOnly Cookies: Already enabled for XSS protection
- Token Storage: Consider using Redis or other storage mechanisms to manage tokens
- Refresh Token: Consider implementing refresh token rotation mechanism
- Scope Limitation: Only request necessary OAuth scopes
- Error Handling: Properly handle various error conditions
This example can be easily extended to support other OAuth 2.0 providers, such as:
- Microsoft Azure AD
- Custom OAuth 2.0 servers
You just need to:
- Add OAuth configuration
- Implement login and callback handlers
- Handle provider-specific user information format
If you need to link a user's different OAuth accounts (e.g., Google and GitHub) together, you can:
- Use email as a unique identifier
- Store user associations with multiple OAuth providers in the database
- Allow users to link multiple accounts in settings
To implement server-side token revocation, you can integrate Redis store:
import "github.com/appleboy/gin-jwt/v3/store/redis"
// Add in initJWTParams()
TokenStore: redis.NewStore(...),Refer to the redis_store example for more details.
- Ensure redirect URI matches OAuth application settings
- Check if Client ID and Secret are correct
- Check browser developer tools network requests
- Ensure JWT_SECRET_KEY remains consistent after restart
- Check if token has expired
- Verify Authorization header format:
Bearer <token>
- GitHub: Ensure
user:emailis requested in OAuth scope - Some users may hide their email, requiring additional handling