Information Security 21 min read

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.

Architect's Guide
Architect's Guide
Architect's Guide
OAuth 2.0 Overview, Authorization Modes, and Implementation for GitHub, QQ, and WeChat Login

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: 8080

3.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/qqCallback

3.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.

JavaAuthenticationSpringBootQQGitHubOAuth2third-party loginWeChat
Architect's Guide
Written by

Architect's Guide

Dedicated to sharing programmer-architect skills—Java backend, system, microservice, and distributed architectures—to help you become a senior architect.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.