5. Authentication Options

Authentication allows only authorized users to access Oracle Database after successful verification of their identity. This section details the various Oracle Database authentication options supported in node-oracledb.

The Oracle Client libraries used by node-oracledb Thick mode may support additional authentication options that are configured independently of the driver.

5.1. Database Authentication

Database Authentication is the most basic authentication method that allows users to connect to Oracle Database by using a valid database username and their associated password. Oracle Database verifies the username and password specified in the node-oracledb connection method with the information stored in the database. See Database Authentication of Users for more information.

Standalone connections and pooled connections can be created in node-oracledb Thin and Thick modes using database authentication. This can be done by specifying the database username and the associated password in the user and password parameters of oracledb.connect(), oracledb.create_pool(), oracledb.connect_async(), or oracledb.create_pool_async(). An example is:

const connection = await oracledb.getConnection({
    user          : "hr",
    password      : mypw,  // mypw contains the hr schema password
    connectString : "mydbmachine.example.com/orclpdb1"
});

5.2. Proxy Authentication

Proxy authentication allows a user (the “session user”) to connect to Oracle Database using the credentials of a “proxy user”. Statements will run as the session user. Proxy authentication is generally used in three-tier applications where one user owns the schema while multiple end-users access the data. For more information about proxy authentication, see the Oracle documentation.

An alternative to using proxy users is to set connection.clientId after connecting and use its value in statements and in the database, for example for monitoring.

Pool proxy authentication requires a heterogeneous pool.

To grant access, typically a DBA would execute:

ALTER USER sessionuser GRANT CONNECT THROUGH proxyuser;

For example, to allow a user called MYPROXYUSER to access the schema of HR:

SQL> CONNECT system

SQL> ALTER USER hr GRANT CONNECT THROUGH myproxyuser;

SQL> CONNECT myproxyuser[hr]/myproxyuserpassword

SQL> SELECT SYS_CONTEXT('USERENV', 'SESSION_USER') AS SESSION_USER,
  2         SYS_CONTEXT('USERENV', 'PROXY_USER')   AS PROXY_USER
  3  FROM DUAL;

SESSION_USER         PROXY_USER
-------------------- --------------------
HR                   MYPROXYUSER

See the Client Access Through a Proxy section in the Oracle Call Interface manual for more details about proxy authentication.

To use the proxy user with a node-oracledb heterogeneous connection pool you could do:

const myproxyuserpw = ... // the password of the 'myproxyuser' proxy user

const pool = await oracledb.createPool({ connectString: "localhost/orclpdb1", homogeneous: false });
const connection = await pool.getConnection({ user: 'myproxyuser[hr]', password: myproxyuserpw});

. . . // connection has access to the HR schema objects

await connection.close();

Other proxy cases are supported such as:

const myproxyuserpw = ... // the password of the 'myproxyuser' proxy user

const pool = await oracledb.createPool({
    user          : "myproxyuser",
    password      : myproxyuserpw,
    connectString : "localhost/FREEPDB1",
    homogeneous   : false,
    . . .  // other pool options such as poolMax can be used
});

const connection = await pool.getConnection({ user : 'hr' });  // the session user

. . . // connection has access to the HR schema objects

await connection.close();

5.3. External Authentication

External Authentication allows applications to use an external password store (such as an Oracle Wallet), the Transport Layer Security (TLS) or Secure Socket Layer (SSL), or the operating system to validate user access. With an external password store, your application can use an Oracle Wallet to authenticate users. External Authentication using TLS authenticates users with Public Key Infrastructure (PKI) certificates. With operating system authentication, user authentication can be performed if the user has an operating system account on their machine recognized by Oracle Database. One of the benefits of using external authentication is that database credentials do not need to be hard coded in the application.

Note

Connecting to Oracle Database using external authentication with an Oracle Wallet, TLS, or the operating system is supported in node-oracledb Thick mode. See Enabling node-oracledb Thick Mode.

Node-oracledb Thin mode only supports external authentication with TLS. See External Authentication Using TLS for more information.

In node-oracledb Thick Mode

To use external authentication, set the oracledb.externalAuth property to true. This property can also be set in the connAttrs or poolAttrs parameters of the oracledb.getConnection() or oracledb.createPool() calls, respectively.

When externalAuth is set, any subsequent connections obtained using the oracledb.getConnection() or pool.getConnection() calls will use external authentication. Setting this property does not affect the operation of existing connections or pools.

For a standalone connection, you can authenticate as an externally identified user like:

const config = { connectString: "localhost/orclpdb1", externalAuth: true };
const connection = await oracledb.getConnection(config);

. . . // connection has access to the schema objects of the externally identified user

If a user HR has been given the CONNECT THROUGH grant from the externally identified user MYPROXYUSER:

ALTER USER hr GRANT CONNECT THROUGH myproxyuser;

then to specify that the session user of the connection should be HR, use:

const config = { connectString: "localhost/orclpdb1", user: "[hr]", externalAuth: true };
const connection = await oracledb.getConnection(config);

. . . // connection has access to the HR schema objects

For a Pool, you can authenticate as an externally identified user like:

const config = { connectString: "localhost/orclpdb1", externalAuth: true };
const pool = await oracledb.createPool(config);
const connection = await pool.getConnection();

. . . // connection has access to the schema objects of the externally identified user

await connection.close();

If a user HR has been given the CONNECT THROUGH grant from the externally identified user, then to specify that the session user of the connection should be HR, use:

const config = { connectString: "localhost/orclpdb1", externalAuth: true };
const pool = await oracledb.createPool(config);
const connection = await pool.getConnection({ user: "[hr]" });

. . . // connection has access to the HR schema objects

await connection.close();

Using externalAuth in the connAttrs parameter of a pool.getConnection() call is not possible. The connections from a Pool object are always obtained in the manner in which the pool was initially created.

For pools created with external authentication, the number of connections initially created is zero even if a larger value is specified for poolMin. The pool increment is always 1, regardless of the value of poolIncrement. Once the number of open connections exceeds poolMin and connections are idle for more than the oracledb.poolTimeout seconds, then the number of open connections does not fall below poolMin.

In node-oracledb Thin mode

In node-oracledb Thin mode, you can use external authentication combined with proxy authentication when using a homogeneous pool. To use this, set the externalAuth property to true and define the proxy user in the user property of the oracledb.createPool().

In the following example, ssl_user (authenticated externally through SSL) is allowed to connect as a proxy for password_user:

CREATE USER password_user IDENTIFIED BY <password>;
GRANT CONNECT TO password_user;

CREATE USER ssl_user IDENTIFIED EXTERNALLY AS 'CN=ssl_user';
GRANT CONNECT TO ssl_user;

ALTER USER password_user GRANT CONNECT THROUGH ssl_user;

You can then connect to Oracle Database using:

const proxyUserConnectionAttributes = {
    walletLocation: "/opt/OracleCloud",
    connectString: "tcps://localhost:2484/FREEPDB1",
    walletPassword: wp,
    externalAuth: true,
    user: "[PASSWORD_USER]",
};
await oracledb.createPool(proxyUserConnectionAttributes);
const connection = await pool.getConnection();
await connection.close();

5.3.1. External Authentication Using TLS

External authentication with Transport Layer Security (TLS) uses Public Key Infrastructure (PKI) certificates to authenticate users. This authentication method can be used in both node-oracledb Thin and Thick modes.

To use TLS external authentication, you must set the oracledb.externalAuth property to true. This property can also be set in the externalAuth parameter of the oracledb.getConnection() or oracledb.createPool() calls. TLS external authentication can only be done for connections that are configured to use the TCPS protocol.

For a standalone connection, you can use TLS authentication to authenticate the user as shown in the example below:

const config = { connectString: "tcps://localhost/orclpdb1", externalAuth: true };
const connection = await oracledb.getConnection(config);

Note that TLS external authentication will not be enabled if you are using token-based authentication (that is, the accessToken property is set in oracledb.getConnection() or oracledb.createPool()).

For a connection pool, you can authenticate with TLS as shown in the example below:

const config = { connectString: "tcps://localhost/orclpdb1", externalAuth: true };
const pool = await oracledb.createPool(config);
const connection = await pool.getConnection();

. . . // connection has access to the schema objects of the externally identified user

await connection.close();

In node-oracledb Thick mode, ensure that the SQLNET.AUTHENTICATION_SERVICES parameter contains TCPS as a value in the sqlnet.ora file. Note that TCPS is the default value of this parameter.

Additional server side configuration is also required to enable external authentication using TLS:

  1. Create a user corresponding to the distinguished name (DN) in the certificate using:

    CREATE USER user_name IDENTIFIED EXTERNALLY AS 'user DN on certificate';
    
  2. Set the SSL_CLIENT_AUTHENTICATION parameter to TRUE in the server-side sqlnet.ora file.

5.4. Multi-Factor Authentication

Multi-Factor authentication (MFA) requires database users to verify their identity using more than one authentication method in order to connect to Oracle Database. This provides an additional layer of security to access the database, enhancing database security and reducing unauthorized access.

MFA is supported in both node-oracledb Thin and Thick modes. It is available from Oracle Database 23.9 (or later) and Oracle Database 19c Release Update 19.28 (and future 19c Release Updates).

With MFA, the primary authentication factor used is user credential authentication (user name and password). On successful credential authentication, the user is then required to verify their identity using another authentication method. Oracle Database supports the following authentication methods that can be configured as MFA:

5.4.1. MFA Push Notifications

You can add push notifications as an additional method to verify the identity of database users. MFA Push Notifications can be configured for use with either the Oracle Mobile Authenticator (OMA) or Cisco Duo applications. For more information, see MFA Push Notifications in the Oracle Database Security Guide.

To use OMA or Cisco Duo push notifications as the secondary authentication method, you must add certain configurations in the database. Also, the database adminstrators must add OMA or Cisco Duo as the secondary authentication method when creating a new database user or when altering an existing user. For the steps to configure OMA or Cisco Duo as the MFA factor, see the OMA and Cisco Duo sections in the Oracle Database Security Guide.

Once a database administrator adds OMA or Cisco Duo as the secondary authentication method for a user, they will receive an email that contains information to download and register their device with the OMA or Cisco Duo application respectively.

Once the device is registered, you can use OMA or Cisco Duo Push Notification authentication as the secondary authentication factor when connecting to the database using standalone connections or connection pools. Using a standalone connection, for example:

connection = await oracledb.getConnection({
  user: "smith",
  password: mypw,
  connectString: "localhost/orclpdb1"
});

The authentication begins with database credentials verification of the user. Once the password is successfully verified, the user receives a notification on their registered device in the OMA or Cisco Duo application to approve or deny an Oracle Database connection attempt. If you approve the notification, the authentication is completed and you can connect to Oracle Database.

5.4.2. MFA Certificate-based Authentication

With MFA Certificate-based authentication, you can add a Public Key Infrastructure (PKI) certificate as an additional authentication method to verify the identity of database users. When a PKI certificate is configured as the second factor in MFA, the user can connect to the database using a signed user certificate stored in their wallet or smart card.

To use certificate-based authentication as the secondary authentication method, you must ensure that users have a signed certificate with the Distinguished Name (DN) value matching the value specified in the walletLocation property in node-oracledb Thin mode. For node-oracledb Thick mode, it should match the value specified in WALLET_LOCATION in the sqlnet.ora file. Also, database administrators must add certificate-based authentication as the secondary authentication method when creating a new database user or altering an existing user. For the steps to configure certificate-based MFA, see MFA Certificate-based Authentication in the Oracle Database Security Guide.

You can use certificate-based authentication to authenticate the user using standalone connections or connection pools. Using a standalone connection in node-oracledb Thin mode, for example:

connection = await oracledb.getConnection({
  user: "smith",
  password: mypw,
  connectString: "tcps://localhost/orclpdb1",
  walletLocation: "/opt/OracleCloud"
});

In the above example, the authentication to connect to Oracle Database begins with database credentials verification of the user. Once the credentials are successfully verified, the user’s Distinguished Name (DN) value, cn=j.smith, in the certificate present in the wallet specified in the walletLocation property is checked with the external name in the dictionary. If the DNs match, then the connection is created.

For node-oracledb Thick mode, the wallet location can be specified in the WALLET_LOCATION parameter in the sqlnet.ora file.

5.5. Token-Based Authentication

Token-Based Authentication allows users to connect to a database by using an encrypted authentication token without having to enter a database username and password. The authentication token must be valid and not expired for the connection to be successful. Users already connected will be able to continue work after their token has expired but they will not be able to reconnect without getting a new token.

The two authentication methods supported by node-oracledb are Open Authorization OAuth 2.0 and Oracle Cloud Infrastructure (OCI) Identity and Access Management IAM.

Token-based authentication can be used for both standalone connections and connection pools.

From node-oracledb 7.0 onwards, you can optionally specify a proxy user in the user property by enclosing the name in square brackets, for example “[proxyuser]”. This can be set in both standalone connections and connection pools when using OAuth 2.0 and OCI IAM token-based authentication.

5.5.1. IAM Token-Based Authentication

Token-based authentication allows Oracle Cloud Infrastructure users to authenticate to Oracle Database with Oracle Identity Access Management (IAM) tokens. Both Thin and Thick modes of the node-oracledb driver support IAM token-based authentication.

When using node-oracledb in Thick mode, Oracle Client libraries 19.14 (or later), or 21.5 (or later) are needed.

See Configuring the Oracle Autonomous Database for IAM Integration for more information.

Standalone connections and pooled connections can be created in node-oracledb Thick and Thin modes using IAM token-based authentication. This can be done or by using the OCI CLI or by using OCI SDK or by using node-oracledb’s OCI Cloud Native Authentication Plugin (extensionOci).

5.5.1.1. IAM Token Generation

Authentication tokens can be obtained in several ways.

Token Generation Using OCI CLI

For example, you can use the Oracle Cloud Infrastructure command line interface (OCI CLI) command run externally to Node.js:

oci iam db-token get

On Linux a folder .oci/db-token will be created in your home directory. It will contain the token and private key files needed by node-oracledb.

See Working with the Command Line Interface for more information on the OCI CLI.

Token Generation Using OCI SDK

Alternatively, IAM authentication tokens can be generated in the node-oracledb driver using the Oracle Cloud Infrastructure (OCI) SDK. This was introduced in node-oracledb 6.3. To use the OCI SDK, you must install the oci-sdk package which can be done with the following command:

npm install oci-sdk

See ocitokenauth.js for a runnable example using the OCI SDK.

Token Generation Using extensionOci Plugin

See Cloud Native Authentication with the extensionOci Plugin.

5.5.1.2. IAM Token and Private Key Extraction

Token and private key files created externally can be read by Node.js applications, for example like:

function getIAMToken() {
    const tokenPath = '/home/cjones/.oci/db-token/token';
    const privateKeyPath = '/home/cjones/.oci/db-token/oci_db_key.pem';

    let token = '';
    let privateKey = '';
    try {
        // Read the token file
        token = fs.readFileSync(tokenPath, 'utf8');
        // Read the private key file
        const privateKeyFileContents = fs.readFileSync(privateKeyPath, 'utf-8');
        privateKeyFileContents.split(/\r?\n/).forEach(line => {
            if (line != '-----BEGIN PRIVATE KEY-----' &&
                line != '-----END PRIVATE KEY-----')
            privateKey = privateKey.concat(line);
        });
    } catch (err) {
        console.error(err);
    } finally {
        const tokenBasedAuthData = {
            token       : token,
            privateKey  : privateKey
        };
        return tokenBasedAuthData;
    }
}

The token and key can be used during subsequent authentication.

Token and private key values generated by the OCI SDK can be read by your application. For example:

async function getToken(accessTokenConfig) {
    ... // OCI-specific authentication details
}

See ocitokenauth.js for a runnable example using the OCI SDK. The use of getToken() and accessTokenConfig is shown in subsequent examples.

5.5.1.3. IAM Standalone Connections

Standalone connections can be created in node-oracledb Thin and Thick modes using IAM token-based authentication.

let accessTokenObj;  // the token object. In this app it is also the token "cache"

function tokenCallback(refresh) {
    if (refresh || !accessTokenObj) {
        accessTokenObj = getIAMToken();     // getIAMToken() was shown earlier
    }
    return accessTokenObj;
}

async function run() {
    await oracledb.getConnection({
        accessToken    : tokenCallback,  // the callback returns the token object
        externalAuth   : true,           // must specify external authentication
        connectString  : '...',          // Oracle Autonomous Database connection string
        user           : "[proxyuser]"   // optionally specify the proxy user
    });
}

In this example, the global object accessTokenObj is used to “cache” the IAM access token and private key (using the attributes token and privateKey) so any subsequent callback invocation will not necessarily have to incur the expense of externally getting them. For example, if the application opens two connections for the same user, the token and private key acquired for the first connection can be reused without needing to make a second REST call.

The getConnection() function’s accessToken attribute in this example is set to the callback function that returns an IAM token and private key used by node-oracledb for authentication. This function tokenCallback() will be invoked when getConnection() is called. If the returned token is found to have expired, then tokenCallback() will be called a second time. If the second invocation of tokenCallback() also returns an expired token, then the connection will fail.

The refresh parameter is set internally by the node-oracledb driver depending on the status and validity of the authentication token provided by the application. The value of the refresh parameter will be different every time the callback is invoked:

  • When refresh is true, the token is known to have expired so the application must get a new token and private key. These are then stored in the global object accessTokenObj and returned.

  • When refresh is false, the application can return the token and private key stored in accessTokenObj, if it is set. But if it is not set (meaning there is no token or key cached), then the application externally acquires a token and private key, stores them in accessTokenObj, and returns it.

If you set the accessTokenConfig property in addition to the accessToken, externalAuth, and connectString properties during standalone connection creation, then you can use the OCI SDK to generate tokens in the callback method. For example:

let accessTokenData;  // The token string

async function callbackfn(refresh, accessTokenConfig) {
    if (refresh || !accessTokenData) {
        accessTokenData = await getToken(accessTokenConfig); // getToken() was shown earlier
    }
    return accessTokenData;
}

async function run() {
    await oracledb.getConnection({
        accessToken   : callbackfn,        // the callback returning the token
        accessTokenConfig : {
                                ...        // OCI-specific parameters to be set
                                               // when using OCI SDK
                            }
        externalAuth  : true,              // must specify external authentication
        connectString : '...'              // Oracle Autonomous Database connection string
    });
}

See ocitokenauth.js for a runnable example using the OCI SDK. The callback and refresh parameter descriptions are detailed in the example above.

5.5.1.4. IAM Connection Pooling

Pooled connections can be created using IAM token-based authentication, for example:

let accessTokenObj;  // The token string. In this app it is also the token "cache"

function tokenCallback(refresh) {
    if (refresh || !accessTokenObj) {
        accessTokenObj = getIAMToken();      // getIAMToken() was shown earlier
    }
    return accessToken;
}

async function run() {
    await oracledb.createPool({
        accessToken   : tokenCallback,     // the callback returning the token
        externalAuth  : true,              // must specify external authentication
        homogeneous   : true,              // must use an homogeneous pool
        connectString : connect_string,    // Oracle Autonomous Database connection string
        user          : "[proxyuser]"      // optionally specify the proxy user
    });
}

See IAM Standalone Connections for a description of the callback and refresh parameter. With connection pools, the accessToken attribute sets a callback function which will be invoked at the time the pool is created (even if poolMin is 0). It is also called when the pool needs to expand (causing new connections to be created) and the current token has expired.

If you set the accessTokenConfig property in addition to the accessToken, externalAuth, homogeneous, and connectString properties during connection pool creation, then you can use the OCI SDK to generate tokens in the callback method. For example:

let accessTokenData;  // The token string

async function callbackfn(refresh, accessTokenConfig) {
    if (refresh || !accessTokenData) {
        accessTokenData = await getToken(accessTokenConfig);
    }
    return accessTokenData;
}

async function init() {
    await oracledb.createPool({
        accessToken   : tokenCallback,        // the callback returning the token
        accessTokenConfig : {
                                ...           // OCI-specific parameters to be set
                                                  // when using Azure SDK
                            }
        externalAuth  : true,                 // must specify external authentication
        homogeneous   : true,                 // must use an homogeneous pool
        connectString : '...'                 // Oracle Autonomous Database connection string
    });
}

See ocitokenauth.js for a runnable example using the OCI SDK. See IAM Standalone Connections for a description of the callback and refresh parameter.

5.5.1.5. IAM Connection Strings

Applications built with node-oracledb 5.4, or later, should use the connection or pool creation parameters described earlier. However, if you cannot use them, you can use IAM Token Authentication by configuring Oracle Net options.

Note

In this release, IAM connection strings are only supported in node-oracledb Thick mode. See Enabling node-oracledb Thick Mode.

This requires Oracle Client libraries 19.14 (or later), or 21.5 (or later).

Save the generated access token to a file and set the connect descriptor TOKEN_LOCATION option to the directory containing the token file. The connect descriptor parameter TOKEN_AUTH must be set to OCI_TOKEN, the PROTOCOL value must be TCPS, the SSL_SERVER_DN_MATCH value should be ON, and the parameter SSL_SERVER_CERT_DN should be set. For example, if the token and private key are in the default location used by the OCI CLI, your tnsnames.ora file might contain:

db_alias =
  (DESCRIPTION=(ADDRESS=(PROTOCOL=TCPS)(PORT=1522)(HOST=abc.oraclecloud.com))
    (CONNECT_DATA=(SERVICE_NAME=db_low.adb.oraclecloud.com))
      (SECURITY=
        (SSL_SERVER_DN_MATCH=ON)
        (SSL_SERVER_CERT_DN="CN=efg.oraclecloud.com, O=Oracle Corporation, L=Redwood City, ST=California, C=US")
        (TOKEN_AUTH=OCI_TOKEN)
        ))

This reads the IAM token and private key from the default location, for example ~/.oci/db-token/ on Linux.

If the token and private key files are not in the default location then their directory must be specified with the TOKEN_LOCATION parameter. For example in a tnsnames.ora file:

db_alias =
  (DESCRIPTION=(ADDRESS=(PROTOCOL=TCPS)(PORT=1522)(HOST=abc.oraclecloud.com))
    (CONNECT_DATA=(SERVICE_NAME=db_low.adb.oraclecloud.com))
      (SECURITY=
        (SSL_SERVER_DN_MATCH=ON)
        (SSL_SERVER_CERT_DN="CN=efg.oraclecloud.com, O=Oracle Corporation, L=Redwood City, ST=California, C=US")
        (TOKEN_AUTH=OCI_TOKEN)
        (TOKEN_LOCATION="/opt/oracle/token")
        ))

You can alternatively set TOKEN_AUTH and TOKEN_LOCATION in a sqlnet.ora file. The TOKEN_AUTH and TOKEN_LOCATION values in a connection string take precedence over the sqlnet.ora settings.

See Oracle Net Services documentation for more information.

5.5.1.6. Cloud Native Authentication with the extensionOci Plugin

With Cloud Native Authentication, node-oracledb’s extensionOci plugin can automatically generate and refresh IAM tokens when required with the support of the OCI SDK. This ability was introduced in node-oracledb 6.8.

The extensionOci plugin can be used by your application by adding the following line to your code:

const tokenPlugin = require('oracledb/plugins/token/extensionOci');

The plugin has a Node package dependency which needs to be installed separately before the plugin can be used. See Install Modules for the OCI Cloud Native Authentication Plugin.

The above line of code defines and registers a built-in hook function that generates IAM tokens. This function is internally invoked when the tokenAuthConfigOci parameter is specified in calls to oracledb.getConnection() or oracledb.createPool(). The tokenAuthConfigOci object contains the configuration parameters needed for token generation. This hook function sets the accessToken parameter of the connection methods to a callback function which uses the configuration parameters to generate IAM tokens.

The extensionOci plugin is available as part of the plugins/token directory in the node-oracledb package.

For OCI IAM token-based authentication with the extensionOci plugin, the tokenAuthConfigOci connection parameter must be specified. This parameter should be a JavaScript object containing the necessary configuration parameters for Oracle Database authentication. See getConnection(): tokenAuthConfigOci Properties for information on the OCI specific parameters. All keys and values of the OCI parameters other than authType are used by the OCI SDK API calls in the plugin.

Standalone Connections Using IAM Tokens

When using the extensionOci plugin to generate IAM tokens, you need to set the tokenAuthConfigOci, externalAuth, and connectString properties in oracledb.getConnection(). For example:

const tokenPlugin = require('oracledb/plugins/token/extensionOci');

async function run() {
  await oracledb.getConnection({
    tokenAuthConfigOci: {
      authType: ...,           // OCI-specific parameters to be set when
      profile: ...,            // using extensionOci plugin with authType
      configFileLocation: ...  // configFileBasedAuthentication
    }
    externalAuth: true,        // must specify external authentication
    connectString: ...         // Oracle Autonomous Database connection string
  });
}

For information on the Azure specific parameters, see getConnection(): tokenAuthConfigOci Properties.

Connection Pooling Using IAM Tokens

When using the extensionOci plugin to generate IAM tokens, you need to set the tokenAuthConfigOci externalAuth, homogeneous, and connectString properties in oracledb.createPool(). For example:

const tokenPlugin = require('oracledb/plugins/token/extensionOci');

async function run() {
  await oracledb.createPool({
    tokenAuthConfigOci: {
      authType: ...,           // OCI-specific parameters to be set when
      tenancy: ...,            // using extensionOci plugin with authType
      user: ...                // simpleAuthentication
    }
    externalAuth: true,        // must specify external authentication
    connectString: ...         // Oracle Autonomous Database connection string
  });
}

For more information on the OCI specific parameters, see createPool(): tokenAuthConfigOci Object Properties.

See ocicloudnativetoken.js for a runnable example using the extensionOci plugin.

5.5.2. OAuth 2.0 Token-Based Authentication

Oracle Cloud Infrastructure (OCI) users can be centrally managed in a Microsoft Azure Active Directory (Azure AD) service. Open Authorization (OAuth 2.0) token-based authentication allows users to authenticate to Oracle Database using Azure AD OAuth 2.0 tokens. Your Oracle Database must be registered with Azure AD. Both Thin and Thick modes of the node-oracledb driver support OAuth 2.0 token-based authentication.

See Authenticating and Authorizing Microsoft Azure Active Directory Users for Oracle Autonomous Databases for more information.

When using node-oracledb in Thick mode, Oracle Client libraries 19.15 (or later), or 21.7 (or later) are needed.

Standalone connections and pooled connections can be created in node-oracledb Thick and Thin modes using OAuth 2.0 token-based authentication. This can be done by using the Azure Active Directory REST API, or Azure SDK, or node-oracledb’s Azure Cloud Native Authentication Plugin (extensionAzure).

5.5.2.1. OAuth 2.0 Token Generation

Authentication tokens can be obtained in several ways as detailed below.

Token Generation Using a Curl command

For example, you can use a curl command against the Azure Active Directory API such as:

curl -X POST -H 'Content-Type: application/x-www-form-urlencoded'
https://login.microsoftonline.com/[<TENANT_ID>]/oauth2/v2.0/token
-d 'client_id = <APP_ID>'
-d 'scope = <SCOPES>'
-d 'username = <USER_NAME>'
-d 'password = <PASSWORD>'
-d 'grant_type = password'
-d 'client_secret = <SECRET_KEY>'

Substitute your own values as appropriate for each argument.

This returns a JSON response containing an access_token attribute. See Microsoft identity platform and OAuth 2.0 authorization code flow for more details. This attribute can be passed as the oracledb.getConnection() attribute accessToken or as the oracledb.createPool() attribute accessToken.

Token Generation Using Azure Active Directory REST API

Alternatively, authentication tokens can be generated by calling the Azure Active Directory REST API, for example:

function getOauthToken() {
    const requestParams = {
        client_id     : <CLIENT_ID>,
        client_secret : <CLIENT_SECRET>,
        grant_type    : 'client_credentials',
        scope         : <SCOPES>,
    };
    const tenantId = <TENANT_ID>;
    const url = `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/token`;
    return new Promise(function(resolve, reject) {
        request.post({
            url       : url,
            body      : queryString.stringify(requestParams),
            headers   : { 'Content-Type': 'application/x-www-form-urlencoded' }
        }, function(err, response, body) {
            if (err) {
                reject(err);
            } else {
                resolve(JSON.parse(body).access_token);
            }
        });
    });
}

Substitute your own values as appropriate for each argument. The use of getOauthToken() is shown in subsequent examples.

Token Generation Using Azure Software Development Kit

Alternatively, OAuth 2.0 authentication tokens can be generated in the node-oracledb driver using the Azure Software Development Kit (SDK). This was introduced in node-oracledb 6.3. To use the Azure SDK, you must install the Microsoft Authentication Library for Node (msal-node) package which can be done with the following command:

npm install @azure/msal-node

Authentication tokens generated by the Azure SDK can be read by your application. For example:

async function getToken(accessTokenConfig) {
    ... // Azure-specific authentication types
}

See azuretokenauth.js for a runnable example using the Azure SDK. The use of getToken() and accessTokenConfig is shown in subsequent examples.

Token Generation Using extensionAzure Plugin

See Cloud Native Authentication with the extensionAzure Plugin.

5.5.2.2. OAuth 2.0 Standalone Connections

Standalone connections can be created using OAuth2 token-based authentication, for example:

let accessTokenStr;  // the token string. In this app it is also the token "cache"

async function tokenCallback(refresh) {
    if (refresh || !accessTokenStr) {
        accessTokenStr = await getOauthToken(); // getOauthToken() was shown earlier
    }
    return accessTokenStr;
}

async function run() {

    await oracledb.getConnection({
        accessToken   : tokenCallback,    // the callback returning the token
        externalAuth  : true,             // must specify external authentication
        connectString : connect_string,   // Oracle Autonomous Database connection string
        user          : "[proxyuser]"     // optionally specify the proxy user
    });
}

In this example, the global variable accessTokenStr is used to “cache” the access token string so any subsequent callback invocation will not necessarily have to incur the expense of externally getting a token. For example, if the application opens two connections for the same user, the token acquired for the first connection can be reused without needing to make a second REST call.

The getConnection() function’s accessToken attribute in this example is set to the callback function that returns an OAuth 2.0 token used by node-oracledb for authentication. This function tokenCallback() will be invoked when getConnection() is called. If the returned token is found to have expired, then tokenCallback() will be called a second time. If the second invocation of tokenCallback() also returns an expired token, then the connection will fail.

The refresh parameter is set internally by the node-oracledb driver depending on the status and validity of the authentication token provided by the application. The value of the refresh parameter will be different every time the callback is invoked:

  • When refresh is true, the token is known to have expired so the application must get a new token. This is then stored in the global variable accessTokenStr and returned.

  • When refresh is false, the application can return the token stored in accessTokenStr, if it is set. But if it is not set (meaning there is no token cached), then the application externally acquires a token, stores it in accessTokenStr, and returns it.

If you set the accessTokenConfig property in addition to the accessToken, externalAuth, and connectString properties during standalone connection creation, then you can use the Azure SDK to generate tokens in the callback method. For example:

let accessTokenData;  // The token string

async function callbackfn(refresh, accessTokenConfig) {
    if (refresh || !accessTokenData) {
        accessTokenData = await getToken(accessTokenConfig); // getToken() was shown earlier
    }
    return accessTokenData;
}

async function run() {
    await oracledb.getConnection({
        accessToken   : callbackfn,        // the callback returning the token
        accessTokenConfig : {
                                ...        // Azure-specific parameters to be set
                                               // when using Azure SDK
                            }
        externalAuth  : true,              // must specify external authentication
        connectString : '...'              // Oracle Autonomous Database connection string
    });
}

See azuretokenauth.js for a runnable example using the Azure SDK. The callback and refresh parameter descriptions are detailed in the example above.

5.5.2.3. OAuth 2.0 Connection Pooling

Pooled connections can be created using OAuth 2.0 token-based authentication, for example:

let accessTokenStr;  // The token string. In this app it is also the token "cache"

async function tokenCallback(refresh) {
    if (refresh || !accessTokenStr) {
        accessTokenStr = await getOauthToken(); // getOauthToken() was shown earlier
    }
    return accessToken;
}

async function run() {
    await oracledb.createPool({
        accessToken   : tokenCallback,        // the callback returning the token
        externalAuth  : true,                 // must specify external authentication
        homogeneous   : true,                 // must use an homogeneous pool
        connectString : '...',                // Oracle Autonomous Database connection string
        user          : "[proxyuser]"         // optionally specify the proxy user
    });
}

See OAuth 2.0 Standalone Connections for a description of the callback and refresh parameter. With connection pools, the accessToken attribute sets a callback function which will be invoked at the time the pool is created (even if poolMin is 0). It is also called when the pool needs to expand (causing new connections to be created) and the current token has expired.

If you set the accessTokenConfig property in addition to the accessToken, externalAuth, homogeneous, and connectString properties during connection pool creation, then you can use the Azure SDK to generate tokens in the callback method. For example:

let accessTokenData;  // The token string

async function callbackfn(refresh, accessTokenConfig) {
    if (refresh || !accessTokenData) {
        accessTokenData = await getToken(accessTokenConfig);  // getToken() was shown earlier
    }
    return accessTokenData;
}

async function run() {
    await oracledb.createPool({
        accessToken   : tokenCallback,        // the callback returning the token
        accessTokenConfig : {
                                ...           // Azure-specific parameters to be set
                                                  // when using Azure SDK
                            }
        externalAuth  : true,                 // must specify external authentication
        homogeneous   : true,                 // must use an homogeneous pool
        connectString : '...'                 // Oracle Autonomous Database connection string
    });
}

See azuretokenauth.js for a runnable example using the Azure SDK. See OAuth 2.0 Standalone Connections for a description of the callback and refresh parameter.

5.5.2.4. OAuth 2.0 Connection Strings

Applications built with node-oracledb 5.5, or later, should use the connection or pool creation parameters described earlier. However, if you cannot use them, you can use OAuth 2.0 Token Authentication by configuring Oracle Net options.

Note

In this release, OAuth 2.0 connection strings are only supported in node-oracledb Thick mode. See Enabling node-oracledb Thick Mode.

This requires Oracle Client libraries 19.15 (or later), or 21.7 (or later).

Save the generated access token to a file and set the connect descriptor TOKEN_LOCATION option to the directory containing the token file. The connect descriptor parameter TOKEN_AUTH must be set to OAUTH, the PROTOCOL value must be TCPS, the SSL_SERVER_DN_MATCH value should be ON, and the parameter SSL_SERVER_CERT_DN should be set. For example, your tnsnames.ora file might contain:

db_alias =
  (DESCRIPTION=(ADDRESS=(PROTOCOL=TCPS)(PORT=1522)(HOST=abc.oraclecloud.com))
    (CONNECT_DATA=(SERVICE_NAME=db_low.adb.oraclecloud.com))
      (SECURITY=
        (SSL_SERVER_DN_MATCH=ON)
        (SSL_SERVER_CERT_DN="CN=efg.oraclecloud.com, O=Oracle Corporation, L=Redwood City, ST=California, C=US")
        (TOKEN_AUTH=OAUTH)
        (TOKEN_LOCATION="/opt/oracle/token")
        ))

You can alternatively set TOKEN_AUTH and TOKEN_LOCATION in a sqlnet.ora file. The TOKEN_AUTH and TOKEN_LOCATION values in a connection string take precedence over the sqlnet.ora settings.

See Oracle Net Services documentation for more information.

5.5.2.5. Cloud Native Authentication with the extensionAzure Plugin

With Cloud Native Authentication, node-oracledb’s extensionAzure plugin can automatically generate and refresh OAuth 2.0 tokens when required with the support of the Microsoft Authentication Library for Node (msal-node). This ability was introduced in node-oracledb 6.8.

The extensionAzure plugin can be used by your application by adding the following line to your code:

const tokenPlugin = require('oracledb/plugins/token/extensionAzure');

The plugin has a Node package dependency which needs to be installed separately before the plugin can be used. See Install Modules for the Azure Cloud Native Authentication Plugin.

The above line of code defines and registers a built-in hook function that generates OAuth 2.0 tokens. This function is internally invoked when the tokenAuthConfigAzure parameter is specified in calls to oracledb.getConnection() or oracledb.createPool(). The tokenAuthConfigAzure object contains the configuration parameters needed for token generation. This hook function sets the accessToken parameter of the connection methods to a callback function which uses the configuration parameters to generate OAuth 2.0 tokens.

The extensionAzure plugin is available as part of the plugins/token directory in the node-oracledb package.

For OAuth 2.0 token-based authentication with the extensionAzure plugin, the tokenAuthConfigAzure connection parameter must be specified. This parameter should be a JavaScript object containing the necessary configuration parameters for Oracle Database authentication. See getConnection(): tokenAuthConfigAzure Object Properties for information on the Azure specific parameters. All keys and values of the Azure parameters other than authType are used by Microsoft Authentication Library for Node (msal-node) API calls in the plugin.

Standalone Connections Using OAuth 2.0 Tokens

When using the extensionAzure plugin to generate OAuth 2.0 tokens, you need to set the tokenAuthConfigAzure, externalAuth, and connectString properties of oracledb.getConnection(). For example:

const tokenPlugin = require('oracledb/plugins/token/extensionAzure');

async function run() {
  await oracledb.getConnection({
    tokenAuthConfigAzure: {
      authType: ...,    // Azure-specific parameters to
      clientId: ...,    // be set when using extensionAzure
      authority: ...,   // plugin
      scopes: ...,
      clientSecret: ...
    }
    externalAuth: true, // must specify external authentication
    connectString: ...  // Oracle Autonomous Database connection string
  });
}

For information on the Azure specific parameters, see getConnection(): tokenAuthConfigAzure Object Properties.

Connection Pools Using OAuth 2.0 Tokens

When using the extensionAzure plugin to generate OAuth 2.0 tokens, you need to set the tokenAuthConfigAzure, externalAuth, homogeneous, and connectString properties in oracledb.createPool(). For example:

const tokenPlugin = require('oracledb/plugins/token/extensionAzure');

async function run() {
  await oracledb.createPool({
    tokenAuthConfigAzure: {
      authType: ...,    // Azure-specific parameters to
      clientId: ...,    // be set when using extensionAzure
      authority: ...,   // plugin
      scopes: ...,
      clientSecret: ...
    }
    externalAuth: true, // must specify external authentication
    homogeneous: true,  // must use a homogeneous pool
    connectString: ...  // Oracle Autonomous Database connection string
  });
}

For information on the Azure specific parameters, see createPool(): tokenAuthConfigAzure Object Properties.

See azurecloudnativetoken.js for a runnable example using the extensionAzure plugin.

5.6. Instance Principal Authentication

With Instance Principal Authentication, Oracle Cloud Infrastructure (OCI) compute instances can be authorized to access services on Oracle Cloud such as Oracle Autonomous Database (ADB). Node-oracledb applications running on such a compute instance do not need to provide database user credentials.

Each compute instance behaves as a distinct type of Identity and Access Management (IAM) Principal, that is, each compute instance has a unique identity in the form of a digital certificate which is managed by OCI. When using Instance Principal Authentication, a compute instance authenticates with OCI IAM using this identity and obtains a short-lived token. This token is then used to access Oracle Cloud services without storing or managing any secrets in your application.

The example below demonstrates how to connect to Oracle Autonomous Database using Instance Principal authentication. To enable this, use node-oracledb’s pre-supplied extensionOci plugin.

Step 1: Create an OCI Compute Instance

An OCI compute instance is a virtual machine running within OCI that provides compute resources for your application. This compute instance will be used to authenticate access to Oracle Cloud services when using Instance Principal Authentication.

To create an OCI compute instance, see the steps in Creating an Instance section of the Oracle Cloud Infrastructure documentation.

For more information on OCI compute instances, see Calling Services from a Compute Instance.

Step 2: Install the OCI CLI on your compute instance

The OCI Command Line Interface (CLI) that can be used on its own or with the Oracle Cloud console to complete OCI tasks.

To install the OCI CLI on your compute instance, see the installation instructions in the Installing the CLI section of Oracle Cloud Infrastructure documentation.

Step 3: Create a Dynamic Group

A Dynamic Group is used to define rules to group the compute instances that require access.

To create a dynamic group using the Oracle Cloud console, see the steps in the To create a dynamic group section of the Oracle Cloud Infrastructure documentation.

Step 4: Create an IAM Policy

An IAM Policy is used to grant a dynamic group permission to access the required OCI services such as Oracle Autonomous Database. If the scope is not set, the policy should be for the specified tenancy.

To create an IAM policy using Oracle Cloud console, see the steps in the Create an IAM Policy section of the Oracle Cloud Infrastructure documentation.

Step 5: Map an Instance Principal to an Oracle Database User

You must map the Instance Principal to an Oracle Database user. For more information, see Accessing the Database Using an Instance Principal.

Also, make sure that external authentication is enabled on Oracle ADB and the Oracle Database parameter IDENTITY_PROVIDER_TYPE is set to OCI_IAM. For the steps, see Enable IAM Authentication on ADB.

Step 6: Deploy your application on the Compute Instance

To use Instance Principal authentication, set the tokenAuthConfigOci, externalAuth, and connectString properties when creating a standalone connection or a connection pool. For example:

const tokenPlugin = require('oracledb/plugins/token/extensionOci');

async function run() {
  await oracledb.getConnection({
    tokenAuthConfigOci: {
      authType: "instancePrincipal"
    }
    externalAuth: true,        // must specify external authentication
    connectString: ...         // Oracle ADB connection string
  });
}

For information on the OCI specific parameters, see getConnection(): tokenAuthConfigOci Properties.

5.7. Authentication Methods for Centralized Configuration Providers

You may need to provide authentication methods to access a centralized configuration provider. The authentication methods for the following centralized configuration providers are detailed in this section:

5.7.1. OCI Object Storage and OCI Vault Configuration Provider Authentication Methods

An Oracle Cloud Infrastructure (OCI) authentication method can be used to access the OCI Object Storage centralized configuration provider. The authentication methood can be set in the <option>=<value> parameter of an OCI Object Storage connection string. Depending on the specified authentication method, you must also set the corresponding authentication parameters in the connection string.

You can specify one of the authentication methods listed below.

API Key-based Authentication

The authentication to OCI is done using API key-related values. This is the default authentication method. Note that this method is used when no authentication value is set or by setting the option value to OCI_DEFAULT.

The optional authentication parameters that can be set for this method are OCI_PROFILE, OCI_TENANCY, OCI_USER, OCI_FINGERPRINT, OCI_KEY_FILE, and OCI_PROFILE_PATH. These authentication parameters can also be set in an OCI Authentication Configuration file which can be stored in a default location ~/.oci/config, or in location ~/.oraclebmc/config, or in the location specified by the OCI_CONFIG_FILE environment variable. See Authentication Parameters for Oracle Cloud Infrastructure (OCI) Object Storage.

Instance Principal Authentication

The authentication to OCI is done using VM instance credentials running on OCI. To use this method, set the option value to OCI_INSTANCE_PRINCIPAL. There are no optional authentication parameters that can be set for this method.

Resource Principal Authentication

The authentication to OCI is done using OCI resource principals. To use this method, you must set the option value to OCI_RESOURCE_PRINCIPAL. There are no optional authentication parameters that can be set for this method.

For more information on these authentication methods, see OCI Authentication Methods.

5.7.2. Azure App Configuration Provider Authentication Methods

A Microsoft Azure authentication method can be used to access the Azure App centralized configuration provider. The authentication methood can be set in the <option>=<value> parameter of an Azure App connection string. Depending on the specified authentication method, you must also set the corresponding authentication parameters in the connection string.

Default Azure Credential

The authentication to Azure App Configuration is done as a service principal (using either a client secret or client certificate) or as a managed identity depending on which parameters are set. This authentication method also supports reading the parameters as environment variables. This is the default authentication method. This method is used when no authentication value is set or by setting the option value to AZURE_DEFAULT.

The optional parameters that can be set for this option include AZURE_CLIENT_ID, AZURE_CLIENT_SECRET, AZURE_CLIENT_CERTIFICATE_PATH, AZURE_TENANT_ID, and AZURE_MANAGED_IDENTITY_CLIENT_ID. For more information on these parameters, see Authentication Parameters for Azure App Configuration Store.

Service Principal with Client Secret

The authentication to Azure App Configuration is done using the client secret. To use this method, you must set the option value to AZURE_SERVICE_PRINCIPAL. The required parameters that must be set for this option include AZURE_SERVICE_PRINCIPAL, AZURE_CLIENT_ID, AZURE_CLIENT_SECRET, and AZURE_TENANT_ID. For more information on these parameters, see Authentication Parameters for Azure App Configuration Store.

Service Principal with Client Certificate

The authentication to Azure App Configuration is done using the client certificate. To use this method, you must set the option value to AZURE_SERVICE_PRINCIPAL. The required parameters that must be set for this option are AZURE_CLIENT_ID, AZURE_CLIENT_CERTIFICATE_PATH, and AZURE_TENANT_ID. For more information on these parameters, see Authentication Parameters for Azure App Configuration Store.

Note that the Service Principal with Client Certificate authentication method overrides Service Principal with Client Secret authentication method.

Managed Identity

The authentication to Azure App Configuration is done using managed identity or managed user identity credentials. To use this method, you must set the option value to AZURE_MANAGED_IDENTITY. If you want to use a user-assigned managed identity for authentication, then you must specify the required parameter AZURE_MANAGED_IDENTITY_CLIENT_ID. For more information on these parameters, see Authentication Parameters for Azure App Configuration Store.

5.7.3. AWS S3 and AWS Secrets Manager Configuration Providers Authentication

An Amazon Web Service (AWS) authentication method can be used to access the AWS Simple Storage Service (S3) and AWS Secrets Manager centralized configuration providers. The authentication to these configuration providers can be set by specifying the following AWS access keys:

  • AWS_ACCESS_KEY_ID: Specifies the Access Key ID.

  • AWS_SECRET_ACCESS_KEY: Specifies the Secret Access Key.

  • AWS_SESSION_TOKEN: Specifies a unique identifier for temporary credentials.

See AWS Access Keys for more information.

These AWS Access Keys can be defined in: