- Print
- PDF
Building OAuth2.0
- Print
- PDF
Available in Classic and VPC
This section describes the basic build method for Node.js-based OAuth2.0 servers. See the guide to integrate existing member and authentication system into services where the OAuth2.0 server is not implemented.
Project configuration
Describes how to configure a project.
Use version
The use version information is as follows:
- Node.js Latest LTS (as of October 10, 2023)
- node: 18.18.0
- npm: 9.8.1
Use library
The use library information is as follows:
- express
- node-oauth2-server
- https://github.com/oauthjs/node-oauth2-server
npm install --save node-oauth2-server
- https://github.com/oauthjs/node-oauth2-server
You can find more information on https://oauth2-server.readthedocs.io/en/latest. For official examples using this library, see https://github.com/14gasher/oauth-example.
Scope of build guide
The build guide is a description of examples through a simple login page. When implementing an actual service, integrate the existing login page with the following OAuth2.0 Login API.
An encryption algorithm, token generation algorithm, and more need to be developed according to the policies of each service. As they are beyond the scope of this guide, those areas are annotated.
node-oauth2-server
Node-oauth2-server implements a predefined model (details for the necessary functions in the *OAuth2.0 process) and provides features in line with the logic of the implemented Model by calling the 3 options: authenticate, authorize, and token.
The features required for OAuth2.0 are abstracted through the Model, and implementing and injecting these contents allows you to easily use the features of authentication, authorization, and token issuance.
Provided features
The provided features are as follows:
Features | Description |
---|---|
Authenticate | Provides authentication processing in API entry based on the issued token |
Authorize | Provides the authorization feature using methods such as code and password |
Token | Provides token issuing and storing features for authorized users |
Library Model list
In the B2B PRISM Live Studio OAuth2.0 integration process, only Authorization Code/Refresh Token Grant are required, and the feature for Scope is not provided.
Model list required for PRISM OAuth2.0
The list of Models covered here is as follows:
For the complete list of Models, see the following:
Features | Description |
---|---|
generateAccessToken | Responsible for the logic of generating Access Token |
generateRefreshToken | Responsible for the logic of generating Refresh Token |
generateAuthorizationCode | Responsible for the logic of generating Authorization Code used in the authorization process |
getAccessToken | Used to retrieve and validate the Access Token stored at the Token issuance stage |
getRefreshToken | Used to retrieve and validate the Refresh Token stored at the Token issuance stage |
getAuthorizationCode | Used to retrieve and validate the Authorization stored at the Token issuance stage |
getClient | Used to retrieve the Client information (Client ID, Client Secret, Redirect URI) |
saveToken | Used to save the token created at the Token issuance stage |
saveAuthorizationCode | Used to save the Authorization Code created at the Authorization stage |
For roles and features of each, see the actual implementation examples. You can view more information, including the latest detailed information about each model, here.
While the implementation of Models can be done using various methods such as Promise-based, async-await, callback, and more, we use the Promise-based method in the example. Check the following example syntax:
const model = {
// We support returning promises.
getAccessToken: function() {
return new Promise('works!');
},
// Or, calling a Node-style callback.
getAuthorizationCode: function(done) {
done(null, 'works!');
},
// Or, using generators.
getClient: function*() {
yield somethingAsync();
return 'works!';
},
// Or, async/wait (using Babel).
getUser: async function() {
await somethingAsync();
return 'works!';
}
};
const OAuth2Server = require('oauth2-server');
let oauth = new OAuth2Server({model: model});
1. OAuth2.0 Login API (Authorization Code Issuance API)
The Models that need to be implemented for the Authorization Code issuance feature are as follows:
generateAuthorizationCode
This feature is optional. If not implemented, a 40-character code is automatically created. If a custom issuance algorithm is required, implement it directly.
Arguments
The description of the arguments is as follows:
Field | Type | Description |
---|---|---|
client | Object |
|
user | Object | Contains the information about the user for whom the Access Token/Refresh Token is generated |
[callback] | Function | Callback function that can be used if not returning in Promise format |
Return Value
Returns as a String (Authorization Code value) type.
Example Code
The example syntax of generateAuthorizationCode is as follows:
{
generateAuthorizationCode: function(client, user) {
// Write custom logic to generate AccessToken, RefreshToken
return new Promise(accessToken);
}
}
getClient
This is a feature to retrieve Redirect URI and Token Lifetime information with Client ID and Client Secret information. Depending on the implementation, views information from DBs or other places and returns. The returned information is used in Code and Token issuance within each feature of OAuth2Server.
Arguments
The description of the arguments is as follows:
Field | Type | Description |
---|---|---|
clientId | String | Client ID for the Client handling authentication and authorization |
clientSecret | String | Client Secret for the Client handling authentication and authorization |
[callback] | Function | Callback function that can be used if not returning in Promise format |
Return Value
The description of the response bodies is as follows:
Field | Type | Description |
---|---|---|
client | Object | Object containing the information about the Client generating the Access Token/Refresh Token |
client.id | String | Client ID for the Client handling authentication and authorization |
[client.redirectUris] | Array<String> | Array of the Redirect URIs for the Client; only the Redirect URIs in that URLs can be processed |
[client.accessTokenLifetime] | Number | Expiration time of the Access Token (seconds) |
[client.refreshTokenLifetime] | Number | Expiration time of the Refresh Token (seconds) |
Example Code
The example syntax of generateAuthorizationCode is as follows:
{
getClient: function(clientId, clientSecret) {
// Retrieves information from DB and then creates and returns a Client Object
return new Promise(client);
}
}
saveAuthorizationCode
Serves the role of storing the Authorization Code generated by generateAuthorizationCode. Depending on the implementation, can be stored in DB or In Memory Storage. The stored Authorization Code can be retrieved from the getAuthorizationCode Model when issuing a Token to validate its validity.
Arguments
The description of the arguments is as follows:
Field | Type | Description |
---|---|---|
code | Object | Code to be stored |
code.authorizationCode | String | Authorization Code |
code.expiresAt | Date | Expiration time |
code.redirectUri | String | Redirect URI used for the issued Authorization Code |
client | Object | Client information of the issued Authorization Code |
user | Object | User information of the issued Authorization Code |
[callback] | Function | Callback function that can be used if not returning in Promise format |
Return Value
The description of the response bodies is as follows:
Field | Type | Description |
---|---|---|
code | Object | Code to be stored |
code.authorizationCode | String | Authorization Code |
code.expiresAt | Date | Expiration time |
code.redirectUri | String | Redirect URI used for the issued Authorization Code |
code.client | Object | Client information of the issued Authorization Code |
code.client.id | String | Client ID of the issued Authorization Code |
code.user | Object | User information of the issued Authorization Code |
OAuth2.0 Login API (Authorization Code Issuance API) example
The example syntax of authenticate is as follows:
const oauth = new OAuth2Server({model: ...}); // Forwards the previously implemented Model Object
function authorizeHandler(options) {
return function(req, res, next) {
let request = new Request(req);
let response = new Response(res);
Calls "return oauth.authorize(request, response, options) // calls oauth.authorize"; the previously implemented Models are internally called and the authorization code is issued
.then(function(code) {
res.locals.oauth = {code: code};
next();
})
.catch(function(err) {
// handle error condition
});
}
}
2. Issue Token API
Provides the feature to exchange/store the Authorization Code issued in the previous step for/as Access Token/Refresh Token. Or, it obtains a new Access Token through the Refresh Token.
The Models that need to be implemented for the Token issuance feature are as follows:
generateAccessToken/generateRefreshToken
This feature is optional. If not implemented, a 40-character token is automatically generated. If a custom token issuance algorithm is required, implement it directly. The 2 Models represent the same specification.
Arguments
The description of the arguments is as follows:
Field | Type | Description |
---|---|---|
client | Object |
|
user | Object |
|
[callback] | Function | Callback function that can be used if not returning in Promise format |
Return Value
Returns as a String (Access Token, Refresh Token value) type.
Example Code
The example syntax for generateAccessToken is as follows:
{
generateAccessToken: function(client, user) {
// Write custom logic to generate AccessToken, RefreshToken.
return new Promise(accessToken);
}
}
getRefreshToken
Used to view the Refresh Token forwarded from the user, verifying whether the Refresh Token actually exists.
You can view the Refresh Token from DBs and other places. After the Refresh Token is verified, the Grant Refresh Token issuing procedure starts.
Arguments
The description of the arguments is as follows:
Field | Type | Description |
---|---|---|
refreshToken | String | Refresh Token to be checked |
[callback] | Function | Callback function that can be used if not returning in Promise format |
Return Value
The description of the response bodies is as follows:
Field | Type | Description |
---|---|---|
token | Object | Access Token to be checked |
token.refreshToken | String | Refresh Token forwarded by getRefreshToken |
token.refreshTokenExpiresAt | Date | Expiration time |
token.client | Object | |
token.client.id | String | Client ID for the Access Token |
Example Code
The example syntax for getAccessToken is as follows:
{
getRefreshToken: token => {
if (!token || token === 'undefined') return false
return new Promise(resolve => {
// Checks the validity (existence) of the token forwarded from DB, and then responds accordingly
})
}
}
getClient
You can use the getClient implemented in the Authorization Code as is.
getAuthorizationCode
Serves the role of retrieving the Authorization Code stored by saveAuthorizationCode. Depending on the implementation, can be retrieved from DB or In Memory Storage. The stored AuthorizationCode can be retrieved from the getAuthorizationCode Model when issuing a Token to validate its validity.
Arguments
The description of the arguments is as follows:
Field | Type | Description |
---|---|---|
authorizationCode | String | Authorization Code to be viewed |
[callback] | Function | Callback function that can be used if not returning in Promise format |
Return Value
The description of the response bodies is as follows:
Field | Type | Description |
---|---|---|
code | Object | Code viewed |
code.code | String | Authorization Code |
code.expiresAt | Date | Expiration time |
code.redirectUri | String | Redirect URI used for the issued Authorization Code |
code.client | Object | Client information of the issued Authorization Code |
code.client.id | String | Client ID of the issued Authorization Code |
code.user | Object | User information of the issued Authorization Code |
saveToken
Serves the role of storing the Token generated by generateAccessToken/generateRefreshToken. Depending on the implementation, can be stored in DB or In Memory Storage. Be careful when saving, as both Access Token and Refresh Token must be saved when saving in saveToken. Both tokens are saved within a single Model, but each token is viewed from individual Models.
Arguments
The description of the arguments is as follows:
Field | Type | Description |
---|---|---|
token | Object | Token to be saved |
token.accessToken | String | Access Token to be saved |
token.accessTokenExpiresAt | Date | Expiration time of the Access Token |
token.refreshToken | String | Refresh Token to be saved |
token.refreshTokenExpiresAt | Date | Expiration time of the Refresh Token |
client | Object | Client information of the issued Token |
user | Object | User information of the issued Token |
[callback] | Function | Callback function that can be used if not returning in Promise format |
Return Value
The description of the response bodies is as follows:
Field | Type | Description |
---|---|---|
token | Object | Saved Token |
token.accessToken | String | Saved Access Token |
token.accessTokenExpiresAt | Date | Expiration time of the Access Token |
token.refreshToken | String | Saved Refresh Token |
token.refreshTokenExpiresAt | Date | Expiration time of the Refresh Token |
token.client | Object | Client information of the issued Token |
token.client.id | String | Client ID information of the issued Token |
token.user | Object | User information of the issued Token |
Integrating Token issuance example
The example syntax of authenticate is as follows:
const oauth = new OAuth2Server({model: ...}); // Forwards the previously implemented Model Object
// Can set the following Handler to operate in /prism/v1/service/oauth2/token Router according to the PRISM OAuth2.0 guide
function tokenHandler(options) { // Options such as Token Life Time can be added to "options" (https://oauth2-server.readthedocs.io/en/latest/api/oauth2-server.html#token-request-response-options-callback)
return function(req, res, next) {
let request = new Request(req);
let response = new Response(res);
Calls "return oauth.token(request, response, options) // oauth.authenticate", the previously implemented Models internally called, and authorization code/refresh token starts to issue a new token
.then(function(code) {
res.locals.oauth = {token: token};
next();
})
.catch(function(err) {
// handle error condition
});
}
}
The Handler wrapping "oauth.token(..)" was implemented in the example, but "oauth.token(...)" of the above example can be used as a response for /prism/v1/service/oauth2/token API for PRISM OAuth2.0 integration by calling it in the Router requiring API authentication and so on.
3. Authenticate
node-oauth2-server also provides an authentication feature that uses the Access Token. The Model to be implemented for the authentication feature is getAccessToken.
getAccessToken Model
Used to view the accessToken forwarded by the user, verifying whether the accessToken actually exists. You can view the accessToken from DBs and other places.
Arguments
The description of the arguments is as follows:
Field | Type | Description |
---|---|---|
accessToken | String | Access Token to be checked |
[callback] | Function | Callback function that can be used if not returning in Promise format |
Return Value
The description of the response bodies is as follows:
Field | Type | Description |
---|---|---|
token | Object | Access Token to be checked |
token.accessToken | String | Access Token forwarded by getAccessToken |
token.accessTokenExpiresAt | Date | Expiration time |
token.client | Object | |
token.client.id | String | Client ID for the AccessToken |
Example Code
The example syntax for getAccessToken is as follows:
{
getAccessToken: token => {
if (!token || token === 'undefined') return false
return new Promise(resolve => {
// Checks the validity (existence) of the token forwarded from DB, and then responds accordingly
})
}
}
Authenticate example
The example syntax of authenticate is as follows:
const oauth = new OAuth2Server({model: ...}); // Forwards the previously implemented Model Object
function authenticateHandler(options) {
return function(req, res, next) {
let request = new Request(req);
let response = new Response(res);
return oauth.authenticate(request, response, options) // The implemented getAccessToken is internally called by calling "oauth.authenticate", and Token validation is performed
.then(function(token) {
res.locals.oauth = {token: token};
next(); // The Access Token is successfully authenticated and proceeds to the next MiddleWare
})
.catch(function(err) {
// handle error condition
});
}
}
By registering oauth.authenticate(...) as Middleware in Router requiring API authentication, you can separately authentication from business logic.