How to access OAuth 2.0 securely and quickly?

Today, we continue to delve into the details of OAuth 2.0 system access. Now that we've learned about the workflow of the OAuth 2.0 authorization service, we're going to look at how to securely and quickly access OAuth 2.0 from two new perspectives—third-party applications and protected resource services.

In order to make it easier for you to understand, this article will show the key work and security details of these two roles in the form of code snippets and comments when connecting to OAuth 2.0.

1. How can third-party applications access OAuth 2.0?

In the OAuth 2.0 process, the third-party application (client) is the "intermediary" that the user uses to access the protected resource. It guides the user to authorize, obtain a token, and then use that token to access the resource. Here, we take a simulated third-party application "Little Rabbit" as an example to analyze the code implementation step by step.

1.1 Process for obtaining authorization codes

In the Authorization Code Grant model of OAuth 2.0, the third-party application needs to first direct the user to the authorization server, complete the authorization, and obtain the authorization code. The following is an example of a request to obtain an authorization code:

String authorizationUrl = "https://authserver.com/authorize?"
        + "response_type=code"
        + "&client_id=" + CLIENT_ID
        + "&redirect_uri=" + URLEncoder.encode(REDIRECT_URI, "UTF-8")
        + "&scope=" + URLEncoder.encode(SCOPE, "UTF-8")
        + "&state=" + generateRandomState();
response.sendRedirect(authorizationUrl);
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

Code parsing

  • response_type=code: specifies that the authorization type is Authorization Code Mode.
  • client_id: The ID of the third-party application (obtained from the authorization server).
  • redirect_uri: the URI that is redirected after the authorization is successful, which is used to receive the authorization code.
  • scope: the scope of the request.
  • state: A randomly generated string that is used to prevent CSRF attacks and ensure that requests are made from third-party applications.

Safety Precautions

  • CSRF Protection: The state parameter protects against CSRF attacks. state should be saved in the user session to ensure that the request to redirect back is valid.
  • Parameter encryption: If possible, sensitive information in the request should be encrypted.

1.2 Obtain an access token through an authorization code

Once the user authorizes, the authorization server returns the authorization code attached to the redirect URL. Next, the third-party app uses the authorization code to request an access token.

String tokenUrl = "https://authserver.com/token";
URL url = new URL(tokenUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setDoOutput(true);

String payload = "grant_type=authorization_code"
        + "&code=" + authorizationCode
        + "&redirect_uri=" + URLEncoder.encode(REDIRECT_URI, "UTF-8")
        + "&client_id=" + CLIENT_ID
        + "&client_secret=" + CLIENT_SECRET;

OutputStream os = conn.getOutputStream();
os.write(payload.getBytes());
os.flush();

BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line;
StringBuilder response = new StringBuilder();
while ((line = in.readLine()) != null) {
    response.append(line);
}
in.close();

// 解析JSON响应,提取access_token
String accessToken = parseAccessToken(response.toString());
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.

Code parsing

  • grant_type=authorization_code: the authorization type, indicating that the authorization code mode is used.
  • code: the authorization code obtained in the previous step.
  • client_id and client_secret: the ID and key of a third-party application that is used to authenticate the identity of the application.
  • access_token: An access token resolved from the response to access the protected resource.

Safety Precautions

  • Transmission security: Ensure that this process is done over HTTPS to prevent sensitive information from being attacked by man-in-the-middle.
  • Client Key Protection: client_secret should not be exposed to client code and is best handled on a backend server.

1.3 Use an access token to access protected resources

Once a third-party app obtains an access token, it can attach it to the request header to access protected resources.

String resourceUrl = "https://resource-server.com/userinfo";
URL url = new URL(resourceUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Authorization", "Bearer " + accessToken);

BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line;
StringBuilder response = new StringBuilder();
while ((line = in.readLine()) != null) {
    response.append(line);
}
in.close();
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.

Safety Precautions

  • Token expiration handling: Third-party apps should consider token expiration and re-acquire it if necessary.
  • Limit resource access frequency: To avoid misuse of access tokens, you should control the frequency of requests to prevent excessive consumption of server resources.

2. How to connect the protected resource service to OAuth 2.0

A Protected Resource Server is a provider of protected data or services. One of the tasks of OAuth 2.0 is to ensure that only authorized applications can access protected resources. The following is the key implementation part of the Protected Resource Service, using JD as an example to show the code and logic.

2.1 Verify the validity of the access token

Before each request enters the Protected Resource service, the validity of the access token is first verified. The general practice is to hand over the token to the authorization server for validation.

public boolean validateAccessToken(String accessToken) {
    String introspectionUrl = "https://authserver.com/introspect";
    URL url = new URL(introspectionUrl);
    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
    conn.setRequestMethod("POST");
    conn.setDoOutput(true);

    String payload = "token=" + accessToken
            + "&client_id=" + CLIENT_ID
            + "&client_secret=" + CLIENT_SECRET;

    OutputStream os = conn.getOutputStream();
    os.write(payload.getBytes());
    os.flush();

    BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
    String response = in.readLine();
    in.close();

    // 判断token是否有效
    return parseTokenValidity(response);
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.

Code parsing

  • introspectionUrl: The authorization server interface used to validate the token.
  • client_id and client_secret: Make sure that the app is authorized to access the resource.
  • parseTokenValidity: parses the returned result to determine whether the token is valid.

Safety Precautions

  • Performance optimizations: Frequent token validation can cause performance issues. A caching mechanism can be introduced to store the state of valid tokens.
  • Error handling: Returns an explicit error message when validation fails for troubleshooting.

2.2 Access resources after verification

If the token is valid, the resource service can process the request and return the appropriate data. Here's an example of an API implementation:

public ResponseEntity<UserInfo> getUserInfo(String accessToken) {
    if (!validateAccessToken(accessToken)) {
        return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
    }

    // 模拟返回的用户信息数据
    UserInfo userInfo = new UserInfo();
    userInfo.setId(12345);
    userInfo.setName("小兔用户");

    return ResponseEntity.ok(userInfo);
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.

Safety Precautions

  • Principle of least privilege: Ensure that the returned data conforms to the permission scope defined by the scope.
  • Error handling: If the token is invalid or the permissions are insufficient, a 401 or 403 status code is returned to prompt the client for correct processing.

2.3 Logging and Monitoring

For security and compliance, resource services need to be logged and monitored when they are connected to OAuth 2.0 to deal with possible security threats and troubleshooting.

public void logAccessAttempt(String accessToken, boolean isValid) {
    String logMessage = String.format("Token: %s, Valid: %s, Timestamp: %s",
            accessToken, isValid, System.currentTimeMillis());
    // 记录到日志系统
    logger.info(logMessage);
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

Code parsing

  • Log content: including tokens, validity status, timestamps, etc.
  • Log privacy protection: Sensitive information, such as user IDs, should be masked in logs.

Safety Precautions

  • Monitoring system integration: Push log information to the monitoring system to analyze whether abnormal access is available in real time.
  • Rate limiting policy: Set a rate limiting policy based on the access frequency and user behavior to prevent malicious access.

summary

In the OAuth 2.0 system, third-party applications and protected resource services need to undertake their own security and authentication tasks:

  1. Third-party application (client): guides users to authorize, obtain, and protect access tokens, and uses tokens to access resources.
  2. Resource Server: Verifies token validity to ensure data security and privacy.

For OAuth 2.0 access security, a number of security measures such as the principle of least privilege, ensuring transmission security, and CSRF protection should be followed. Hopefully, this article will give you a clearer understanding of how to implement a secure and reliable OAuth 2.0 access process through a detailed code explanation.