Building OAuth2.0
    • PDF

    Building OAuth2.0

    • PDF

    Article Summary

    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
        
    Note

    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.

    Note

    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:

    FeaturesDescription
    AuthenticateProvides authentication processing in API entry based on the issued token
    AuthorizeProvides the authorization feature using methods such as code and password
    TokenProvides 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:

    Note

    For the complete list of Models, see the following:

    FeaturesDescription
    generateAccessTokenResponsible for the logic of generating Access Token
    generateRefreshTokenResponsible for the logic of generating Refresh Token
    generateAuthorizationCodeResponsible for the logic of generating Authorization Code used in the authorization process
    getAccessTokenUsed to retrieve and validate the Access Token stored at the Token issuance stage
    getRefreshTokenUsed to retrieve and validate the Refresh Token stored at the Token issuance stage
    getAuthorizationCodeUsed to retrieve and validate the Authorization stored at the Token issuance stage
    getClientUsed to retrieve the Client information (Client ID, Client Secret, Redirect URI)
    saveTokenUsed to save the token created at the Token issuance stage
    saveAuthorizationCodeUsed 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:

    FieldTypeDescription
    clientObject
    • Object containing information about the Client generating the Access Token/Refresh Token
    • getClient() Model is called, and the information viewed from that Model is automatically forwarded
    userObjectContains the information about the user for whom the Access Token/Refresh Token is generated
    [callback]FunctionCallback 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:

    FieldTypeDescription
    clientIdStringClient ID for the Client handling authentication and authorization
    clientSecretStringClient Secret for the Client handling authentication and authorization
    [callback]FunctionCallback function that can be used if not returning in Promise format

    Return Value

    The description of the response bodies is as follows:

    FieldTypeDescription
    clientObjectObject containing the information about the Client generating the Access Token/Refresh Token
    client.idStringClient 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]NumberExpiration time of the Access Token (seconds)
    [client.refreshTokenLifetime]NumberExpiration 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:

    FieldTypeDescription
    codeObjectCode to be stored
    code.authorizationCodeStringAuthorization Code
    code.expiresAtDateExpiration time
    code.redirectUriStringRedirect URI used for the issued Authorization Code
    clientObjectClient information of the issued Authorization Code
    userObjectUser information of the issued Authorization Code
    [callback]FunctionCallback function that can be used if not returning in Promise format

    Return Value

    The description of the response bodies is as follows:

    FieldTypeDescription
    codeObjectCode to be stored
    code.authorizationCodeStringAuthorization Code
    code.expiresAtDateExpiration time
    code.redirectUriStringRedirect URI used for the issued Authorization Code
    code.clientObjectClient information of the issued Authorization Code
    code.client.idStringClient ID of the issued Authorization Code
    code.userObjectUser 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:

    FieldTypeDescription
    clientObject
    • Object containing information about the Client generating the Access Token/Refresh Token
    • getClient() Model is called, and the information viewed from that Model is automatically forwarded
    userObject
    • Contains information about the User for whom the Access Token/Refresh Token is generated
    • For Authorization Code → Token, contains code.user viewed by Model#getAuthorizationCode, and for Refresh Token → Token, contains token.user viewed by Model#getRefreshToken
    [callback]FunctionCallback 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:

    FieldTypeDescription
    refreshTokenStringRefresh Token to be checked
    [callback]FunctionCallback function that can be used if not returning in Promise format

    Return Value

    The description of the response bodies is as follows:

    FieldTypeDescription
    tokenObjectAccess Token to be checked
    token.refreshTokenStringRefresh Token forwarded by getRefreshToken
    token.refreshTokenExpiresAtDateExpiration time
    token.clientObject
    token.client.idStringClient 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:

    FieldTypeDescription
    authorizationCodeStringAuthorization Code to be viewed
    [callback]FunctionCallback function that can be used if not returning in Promise format

    Return Value

    The description of the response bodies is as follows:

    FieldTypeDescription
    codeObjectCode viewed
    code.codeStringAuthorization Code
    code.expiresAtDateExpiration time
    code.redirectUriStringRedirect URI used for the issued Authorization Code
    code.clientObjectClient information of the issued Authorization Code
    code.client.idStringClient ID of the issued Authorization Code
    code.userObjectUser 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:

    FieldTypeDescription
    tokenObjectToken to be saved
    token.accessTokenStringAccess Token to be saved
    token.accessTokenExpiresAtDateExpiration time of the Access Token
    token.refreshTokenStringRefresh Token to be saved
    token.refreshTokenExpiresAtDateExpiration time of the Refresh Token
    clientObjectClient information of the issued Token
    userObjectUser information of the issued Token
    [callback]FunctionCallback function that can be used if not returning in Promise format

    Return Value

    The description of the response bodies is as follows:

    FieldTypeDescription
    tokenObjectSaved Token
    token.accessTokenStringSaved Access Token
    token.accessTokenExpiresAtDateExpiration time of the Access Token
    token.refreshTokenStringSaved Refresh Token
    token.refreshTokenExpiresAtDateExpiration time of the Refresh Token
    token.clientObjectClient information of the issued Token
    token.client.idStringClient ID information of the issued Token
    token.userObjectUser 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:

    FieldTypeDescription
    accessTokenStringAccess Token to be checked
    [callback]FunctionCallback function that can be used if not returning in Promise format

    Return Value

    The description of the response bodies is as follows:

    FieldTypeDescription
    tokenObjectAccess Token to be checked
    token.accessTokenStringAccess Token forwarded by getAccessToken
    token.accessTokenExpiresAtDateExpiration time
    token.clientObject
    token.client.idStringClient 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.


    Was this article helpful?

    Changing your password will log you out immediately. Use the new password to log back in.
    First name must have atleast 2 characters. Numbers and special characters are not allowed.
    Last name must have atleast 1 characters. Numbers and special characters are not allowed.
    Enter a valid email
    Enter a valid password
    Your profile has been successfully updated.