OAuth 2.0 Overview, Authorization Modes, and Implementation for GitHub, QQ, and WeChat Login
This article provides a comprehensive introduction to OAuth 2.0, its core concepts, advantages and disadvantages, details four authorization flows, and presents step‑by‑step Java Spring Boot implementations for GitHub, QQ, and WeChat third‑party login, including database design considerations and code examples.
1. OAuth Overview
1.1 Introduction
OAuth (Open Authorization) is an open network standard for authorization that allows users to grant third‑party applications access to their data stored on service providers without sharing usernames and passwords. The current widely used version is OAuth 2.0.
1.2 Features
Simple: Easy to understand and use for both providers and developers.
Secure: No user credentials are exposed, improving security and flexibility.
Open: Any service provider can implement OAuth, and any software can use it.
1.3 Application Scenarios
Native app authorization: Mobile apps request backend APIs with token‑based authentication.
SPA (single‑page application) with front‑back separation: Front‑end requests backend data and needs OAuth2 security.
Third‑party login (e.g., QQ, Weibo, WeChat): Users log in via external platforms.
1.4 Basic Concepts
Resource Owner: The end user who owns the resources.
Resource Server: Hosts protected resources; grants access when a valid token is presented.
Client: The application (browser, mobile, or server) that requests resources using a token.
Authorization Server: Authenticates the client and issues tokens.
1.5 Pros and Cons
Advantages
More secure – client never handles user passwords.
Widely adopted and continuously evolving.
Short‑lived, encapsulated tokens.
Decouples resource and authorization servers.
Centralized authorization simplifies client logic.
HTTP/JSON friendly, easy token transmission.
Supports diverse client architectures.
Clients can have different trust levels.
Disadvantages
Broad framework leads to compatibility and interoperability issues across implementations.
Not an authentication protocol; it does not provide user identity information by itself.
2. OAuth Authorization Modes
2.1 Four Grant Types
Authorization Code: Standard flow where the client obtains an authorization code then exchanges it for an access token.
Implicit: Skips the authorization code step and directly receives an access token.
Password: Client collects user credentials and exchanges them for a token.
Client Credentials: Client authenticates itself (client_id & client_secret) to obtain a token.
2.2 Authorization Code Flow
Steps:
Client redirects user to the authorization server’s consent page.
User logs in and grants permission.
Authorization server returns an authorization code to the client.
Client forwards the code to its backend, which exchanges it for an access token.
2.3 Password Grant Flow
If the user trusts the application, the client can directly send the username and password to obtain a token.
Client asks the user for credentials.
Client sends credentials to the token endpoint.
Authorization server validates and returns an access token.
3. Third‑Party Login Implementations
3.1 GitHub Login
Register an OAuth App on GitHub to obtain client_id and client_secret . The flow follows the standard Authorization Code grant.
3.1.1 Configuration (application.yml)
github:
clientId: ab3d67630b13025715cf
clientSecret: 29f8c274c7634aa988f42c6507692da4fe118be8
directUrl: http://localhost:8080/oauth/githubCallback
server:
port: 80803.1.2 Bean Class
@Data
@Component
@ConfigurationProperties(prefix = "github")
public class GitHubOAuthInfo {
private String clientId;
private String clientSecret;
private String directUrl;
}3.1.3 State Utility
@Service
public class OauthService {
private Set
stateSet = new HashSet<>();
public String genState() {
String state = UUID.randomUUID().toString();
stateSet.add(state);
return state;
}
public boolean checkState(String state) {
if (stateSet.contains(state)) {
stateSet.remove(state);
return true;
}
return false;
}
}3.1.4 Controller
@RestController
@Slf4j
@RequestMapping("/oauth")
public class AuthController {
@Autowired
private GitHubOAuthInfo gitHubOAuthInfo;
@Autowired
private OauthService oauthService;
private static final String ACCESS_TOKEN_URL = "https://github.com/login/oauth/access_token";
private static final String AUTHORIZE_URL = "https://github.com/login/oauth/authorize";
private static final String RESOURCE_URL = "https://api.github.com/user";
@GetMapping("/githubLogin")
public void githubLogin(HttpServletResponse response) throws IOException {
String state = oauthService.genState();
String param = "response_type=code&client_id=" + gitHubOAuthInfo.getClientId() + "&state=" + state + "&redirect_uri=" + gitHubOAuthInfo.getDirectUrl();
response.sendRedirect(AUTHORIZE_URL + "?" + param);
}
@GetMapping("/githubCallback")
public String githubCallback(String code, String state, HttpServletResponse response) throws Exception {
if (!oauthService.checkState(state)) {
throw new Exception("State verification failed");
}
JSONObject jsonObject = new JSONObject();
jsonObject.put("client_id", gitHubOAuthInfo.getClientId());
jsonObject.put("client_secret", gitHubOAuthInfo.getClientSecret());
jsonObject.put("code", code);
String accessTokenRequestJson = HttpRequest.post(ACCESS_TOKEN_URL)
.header("Accept", " application/json")
.body(jsonObject.toJSONString())
.timeout(30000)
.execute().body();
JSONObject accessTokenObject = JSONObject.parseObject(accessTokenRequestJson);
if (accessTokenObject.containsKey("error")) {
throw new Exception("Token request error");
}
String accessToken = accessTokenObject.getString("access_token");
String tokenType = accessTokenObject.getString("token_type");
String userInfo = HttpRequest.get(RESOURCE_URL)
.header("Authorization", tokenType + " " + accessToken)
.timeout(5000)
.execute().body();
return JSONObject.parseObject(userInfo).toJSONString();
}
}3.2 QQ Login
Similar to GitHub but requires an APP ID and APP Key from QQ. The flow also follows the Authorization Code grant.
3.2.1 Configuration (application.yml)
qq:
qqAppId: 101474821
qqAppKey: 00d91cc7f636d71faac8629d559f9fee
directUrl: http://localhost:8080/oauth/qqCallback3.2.2 Bean Class
@Data
@Component
@ConfigurationProperties(prefix = "qq")
public class QqOAuthInfo {
private String qqAppId;
private String qqAppKey;
private String directUrl;
}3.2.3 Controller (excerpt)
@RestController
@Slf4j
@RequestMapping("/oauth")
public class QqAuthController {
@Autowired
private QqOAuthInfo qqOAuthInfo;
@Autowired
private OauthService oauthService;
private static final String AUTHORIZE_URL = "https://graph.qq.com/oauth2.0/authorize";
private static final String ACCESS_TOKEN_URL = "https://graph.qq.com/oauth2.0/token";
private static final String OPEN_ID_URL = "https://graph.qq.com/oauth2.0/me";
private static final String USER_INFO_URL = "https://graph.qq.com/user/get_user_info";
@GetMapping("/qqLogin")
public void qqLogin(HttpServletResponse response) throws IOException {
String state = oauthService.genState();
String param = "response_type=code&client_id=" + qqOAuthInfo.getQqAppId() + "&state=" + state + "&redirect_uri=" + qqOAuthInfo.getDirectUrl();
response.sendRedirect(AUTHORIZE_URL + "?" + param);
}
@GetMapping("/qqCallback")
public String qqCallback(String code, String state, HttpServletResponse response) throws Exception {
if (!oauthService.checkState(state)) {
throw new Exception("State verification failed");
}
String param = "grant_type=authorization_code&code=" + code + "&redirect_uri=" + qqOAuthInfo.getDirectUrl() + "&client_id=" + qqOAuthInfo.getQqAppId() + "&client_secret=" + qqOAuthInfo.getQqAppKey() + "&fmt=json";
String accessTokenRequestJson = HttpRequest.get(ACCESS_TOKEN_URL).body(param).timeout(30000).execute().body();
JSONObject accessTokenObject = JSONObject.parseObject(accessTokenRequestJson);
String accessToken = accessTokenObject.getString("access_token");
String meBody = HttpRequest.get(OPEN_ID_URL).body("access_token=" + accessToken).execute().body();
JSONObject meJson = JSONObject.parseObject(meBody);
String openid = meJson.getString("openid");
String userInfoParam = "access_token=" + accessToken + "&oauth_consumer_key=" + qqOAuthInfo.getQqAppId() + "&openid=" + openid;
String userInfo = HttpRequest.get(USER_INFO_URL).body(userInfoParam).timeout(5000).execute().body();
return JSONObject.parseObject(userInfo).toJSONString();
}
}3.3 WeChat Login
Follow the official WeChat documentation. The flow mirrors the standard OAuth2.0 Authorization Code process: obtain AppID and AppSecret, redirect users to the WeChat authorization page, receive a code, exchange it for an access token, then retrieve user info.
3.3.1 References
WeChat Login Official Docs
The article concludes with a reminder to star the public account for updates and provides additional reading links.
Architect's Guide
Dedicated to sharing programmer-architect skills—Java backend, system, microservice, and distributed architectures—to help you become a senior architect.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.