blog.itcode.devblog.itcode.dev

[OAuth2.0] Building an OAuth2.0 Authorization Server with ScribeJAVA - 2. Designing the Authorization Server

Now that we've gained some background knowledge about the OAuth2.0 protocol, let's use it to build an authorization server ourselves. The ultimate goal is to build the whole system, split into Frontend and Backend parts, where social login is performed through the web page and processed by an authorization server we implement ourselves.

[OAuth2.0] Building an OAuth2.0 Authorization Server with ScribeJAVA - 2. Designing the Authorization Server

Now that we've gained some background knowledge about the OAuth2.0 protocol, let's use it to build an authorization server ourselves. The ultimate goal is to build the whole system, split into Frontend and Backend parts, where social login is performed through the web page and processed by an authorization server we implement ourselves.
RWB0104
@RWBwritten at 2021-10-14 13:12:25
Building an OAuth2.0 Authorization Server

시리즈 모아보기

Building an OAuth2.0 Authorization Server

2 / 11

Now that we've gained some background knowledge about the OAuth2.0 protocol, let's use it to build an authorization server ourselves.

The ultimate goal is to build the whole system, split into Frontend and Backend parts, where social login is performed through the web page and processed by an authorization server we implement ourselves.

The authentication method for the authorization server will use the Authorization Code Grant.

The project is divided into the Frontend, which is the web page, and the Backend, which is the authorization server that handles API communication.

💬 Language

🧱 Framework

  • 🖼️ Gradle

  • 🖼️ jakarta.servlet-api

  • 🖼️ lombok

  • 🖼️ jjwt

  • 🖼️ scribejava-apis

  • 🖼️ jersey-server

  • 🖼️ jersey-container-servlet

  • 🖼️ jersey-hk2

  • 🖼️ jersey-media-json-jackson

📦 Publish

Jersey is a RESTful API framework, and scribeJAVA is an OAuth framework.

Jersey 3 uses jakarta.*, the latest Servlet 5.0 spec. Because of this, we use Tomcat 10, which implements it. This project cannot be deployed on a WAS that can't use the latest servlet spec, such as anything below Tomcat 10 or one that doesn't implement jakarta.*.

💬 Language

🧱 Framework

📦 Publish

Originally I was deploying it via Raspberry Pi, but since there was no real need for that, I deploy it via GitHub Pages instead.

Since the Frontend simply performs API communication with the authorization server and displays information, I avoided complex technologies like React as much as possible and kept it built with just the basic features.

The authorization server can be broadly divided into three parts.

  • controller - receives requests at designated URLs and delegates them to a process.
  • process - performs the API's operation and generates the response
  • module - modules needed to perform the API's operation

These are separated into packages.

The Jersey framework operates in the controller layer.

With plain Servlets, there are parts you have to implement yourself in order to design a RESTful API.

To design a RESTful API effectively, we use the Jersey framework.

The controller forwards the request to the defined process, and passes the response the process returns back to the requester.

  • /login

    • GET /:platform - API that returns the authentication URL for each platform
    • PUT /put - API that returns a URL to renew consent for information sharing
    • POST /:platform - Login API for each platform
    • POST /auto - Auto-login API
  • /logout

    • POST / - Logout API
  • /revoke

    • POST / - API to revoke the linked account
  • /userinfo

    • POST / - User info API

The above controllers will be implemented in this project.

process is the layer where the actual logic is implemented. Here, modules are called when needed.

The process builds a response object based on JSON in a fixed format for the execution result and returns it to the controller.

JSON

{
    flag: true,
    title: "success",
    message: "test api response success",
    body: {
        key1: "value1",
        key2: true,
        key3: 4932,
        key4: [
            "A",
            "B",
            "C"
        ],
        key5: 93.203
    }
}
ParameterRequiredData TypeDescription
flagYbooleanWhether the response is normal
titleYStringResponse title
messageYStringResponse message
bodyYString | Number | boolean | Array | ObjectResponse payload

The response spec is as above.

process is separated and managed by HTTP Method, such as GET and POST.

A module is an object that implements the modularization of logic that gets reused repeatedly across multiple processes.

Among these, the module handling OAuth authentication, which is the core functionality, is written based on scribeJAVA.

All processes that perform authentication-related logic, such as login and user info requests, call this module, reducing code duplication and improving maintainability.

This is the module responsible for the most important role in this project's Backend, implementing OAuth authentication.

These days, any platform of a certain size offers an OAuth service. Even though the platforms differ, as long as they comply with OAuth, they'll all accept common requests and provide common responses. Since a common protocol is used, we could build a single authentication module and handle all authentication there.

But there's one problem. No matter how much a common protocol is used, each platform sometimes requires additional parameters or headers. Unless you want to stuff the code full of conditional statements, it's problematic to handle each platform's requirements one by one in a single authentication module. Branching through conditionals also isn't a great approach from a maintainability standpoint.



OAuth is closer to being a kind of concept than an object. For this kind of abstract concept, a JAVA interface or abstract object is well suited.

For the authentication module, since problems arise from special requirements of a few platforms, it would be efficient to use the authentication module's common logic by default, and change the logic only for platforms with additional requirements. So an abstract object suits the authentication module better than an interface.

We can design this by creating a single abstract authentication module, and having each social platform inherit from it and implement its own version.

Platforms without issues use the methods already declared in the authentication module as-is, and platforms with additional requirements override the methods in their platform-specific authentication module to redesign them to fit those requirements.

The features that need to be implemented are as follows.

  • Logic to generate the platform login URL
  • Logic to generate a URL for renewing consent to provide information
  • Service login logic (authorization code -> Access Token)
  • Auto-login logic
  • Logout logic
  • Logic to fetch user info
  • Logic to revoke the linked account

At minimum, the above features must be implemented.

For fetching user info, the response given varies wildly from platform to platform.

User info can be obtained by requesting it from the Service Provider using the Access Token received via OAuth. OAuth is, after all, a standard protocol strictly for obtaining authentication, and there are no real constraints on the additional actions performed using the authentication token, so API requests and responses after Access Token issuance vary wildly from platform to platform.

Because of this, the logic for fetching user info is not bound by the OAuth standard protocol. To handle this, let's declare it as an abstract method and force each module to refine the response and return it accordingly.

The structure of the API that uses the OAuth module is diagrammed as above.

Jersey catches the URL and forwards it to the designated process. The process calls the OAuth implementation for the relevant platform to perform the authentication logic. Afterward, the result is returned and delivered to the user in this structure.

So far, we've gone through the design of the authorization server. In the next chapter, we'll actually start building the authorization server based on the above design. In particular, we'll cover scribeJAVA and the OAuth authentication module.

The build order will be module -> process -> controller.

Since the process located innermost is the module, we'll implement things sequentially starting from the module and working outward.

# JAVA# OAuth2.0
ship
blog.itcode.dev

Notes from the π-th Alpaca

7.0.1
Developed by RWB since 2021.057th upgraded at 2026.08