-
Start your API server:
make run # Or manually: export DATABASE_URL="postgresql://postgres:postgres@localhost:5432/go_api_starter?sslmode=disable" export JWT_SECRET="your-secret-key" go run ./cmd/api
-
Login via Postman or curl:
curl -X POST http://localhost:8080/api/auth/login \ -H "Content-Type: application/json" \ -d '{"email":"testuser@example.com","password":"password123"}'
-
Copy the
tokenfrom the response
- In Postman, select your request
- Go to Authorization tab
- Select Type: Bearer Token
- Paste your token in the Token field
- Postman automatically adds
Authorization: Bearer <token>header
- Go to Headers tab
- Add header:
- Key:
Authorization - Value:
Bearer YOUR_TOKEN_HERE(include the word "Bearer" and a space!)
- Key:
- Token expired - Tokens expire after 7 days. Get a fresh token.
- JWT_SECRET mismatch - Server restarted with different secret
- Wrong format - Missing "Bearer " prefix or extra spaces
- Old token - Token from previous server instance
-
Get a fresh token:
# Login again to get new token curl -X POST http://localhost:8080/api/auth/login \ -H "Content-Type: application/json" \ -d '{"email":"your-email@example.com","password":"your-password"}'
-
Check JWT_SECRET is consistent:
- Make sure
JWT_SECRETenvironment variable matches between token generation and validation - Default:
dev-secret-change-in-production - If you change it, you need a new token
- Make sure
-
Verify token format in Postman:
- Should be:
Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... - NOT:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...(missing Bearer) - NOT:
Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...(extra spaces)
- Should be:
Tokens are valid for 7 days. After that, you need to login again to get a new token.
If you restart the server with a different JWT_SECRET, all existing tokens become invalid. You must:
- Use the same
JWT_SECRETas when the token was generated, OR - Get a new token after restart
# 1. Get token
TOKEN=$(curl -s -X POST http://localhost:8080/api/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"testuser@example.com","password":"password123"}' \
| python3 -c "import sys, json; print(json.load(sys.stdin)['token'])")
# 2. Test token
curl -X GET http://localhost:8080/api/users \
-H "Authorization: Bearer $TOKEN"The API_ACCESS_TOKEN is NOT a Bearer token. It uses a different header.
-
Set the environment variable:
export API_ACCESS_TOKEN="your-api-token-value"
-
In Postman:
- Go to Headers tab (NOT Authorization tab)
- Add header:
- Key:
X-API-Token - Value:
your-api-token-value
- Key:
-
This bypasses JWT authentication - useful for service-to-service calls
| Type | Header | Use Case |
|---|---|---|
| JWT Token | Authorization: Bearer <token> |
User authentication (from login) |
| API Access Token | X-API-Token: <token> |
Service-to-service authentication |
# Set API_ACCESS_TOKEN when starting server
export API_ACCESS_TOKEN="my-secret-api-token"
export DATABASE_URL="postgresql://postgres:postgres@localhost:5432/go_api_starter?sslmode=disable"
go run ./cmd/api
# In Postman, add header:
# X-API-Token: my-secret-api-tokenIf you see this error even with X-API-Token header set:
-
Check server has API_ACCESS_TOKEN set:
# When starting server, make sure you export it: export API_ACCESS_TOKEN="your-token-value" go run ./cmd/api
-
Verify the token value matches exactly:
- Server:
export API_ACCESS_TOKEN="test-token-123" - Postman Header:
X-API-Token: test-token-123(must match exactly)
- Server:
-
Check server logs:
- Look for any errors about missing API_ACCESS_TOKEN
- Default behavior: If
API_ACCESS_TOKENis not set, only JWT Bearer tokens work
-
Quick test:
# Start server with token export API_ACCESS_TOKEN="test-token" go run ./cmd/api # Test in another terminal curl -X GET http://localhost:8080/api/users \ -H "X-API-Token: test-token"
You can set up Postman environment variables:
- Create a new Environment in Postman
- Add variables:
- Variable:
jwt_token(for Bearer auth) - Variable:
api_token(for X-API-Token header)
- Variable:
- In Authorization tab, use:
Bearer {{jwt_token}} - In Headers tab, add:
X-API-Token: {{api_token}}
This way you can update tokens in one place and they apply to all requests.