Skip to content

DPY-6005 / ORA-12506: All documented Thin mode IAM token approaches fail on ADB-S Private Endpoint — TOKEN_AUTH not included in TNS Connect packet #579

@alexmocciaoci

Description

@alexmocciaoci
  1. What versions are you using?
platform.platform: Windows-11-10.0.xxxxx-xxx
sys.maxsize > 2**32: True
platform.python_version: 3.12.0
oracledb.__version__: 3.4.2
Oracle Database: Autonomous Database Serverless (ADB-S) — Private Endpoint on OCI VCN private subnet
init_oracle_client(): NOT called — Thin mode confirmed via oracledb.is_thin_mode() → True
  1. Is it an error or a hang or a crash?

Immediate error on every connect attempt.

  1. What error(s) or behavior you are seeing?
DPY-6005: cannot connect to database.
DPY-6000: Listener refused connection. (Similar to ORA-12506)

All pre-connection checks pass:

  • DNS resolves PE hostname to private IP xx.x.x.xOK
  • TCP port 1522 reachable — OK
  • ewallet.pem present and valid — OK
  • IAM DB token acquired via oci iam db-token getOK (1934 chars, valid)
  • Private key file present — OK (1703 chars, PKCS8)

The same token, wallet, and network path work correctly with:

  • python-oracledb Thick modeCONNECTS
  • JDBC Thin (SQL Developer) → CONNECTS
  • SQL*Plus with OCI Instant Client (Thick) → CONNECTS
  1. Does your application call init_oracle_client()?

No. Thin mode only. Confirmed via oracledb.is_thin_mode()True.

  1. Include a runnable Python script that shows the problem.

We tested all documented Thin mode approaches for OCI IAM token authentication as described in the official documentation at:
https://python-oracledb.readthedocs.io/en/stable/user_guide/authentication_methods.html

All four tests fail with the same identical error.


Test 1 — extra_auth_params with oci_tokens plugin (ConfigFileAuthentication)

This is the primary documented approach for Thin mode in the official docs.

import oracledb
import oracledb.plugins.oci_tokens

WALLET_DIR = r"path\to\wallet"
WALLET_PWD = "wallet_password"
PE_HOST    = "<pe-host>.adb.xx-xxxxx-x.oraclecloud.com"
PE_PORT    = 1522
SERVICE    = "<hash>_<dbname>_high.adb.oraclecloud.com"

dsn = (
    f"(DESCRIPTION=(ADDRESS=(PROTOCOL=TCPS)(PORT={PE_PORT})(HOST={PE_HOST}))"
    f"(CONNECT_DATA=(SERVICE_NAME={SERVICE}))"
    f"(SECURITY=(SSL_SERVER_DN_MATCH=YES)))"
)

conn = oracledb.connect(
    dsn=dsn,
    config_dir=WALLET_DIR,
    wallet_location=WALLET_DIR,
    wallet_password=WALLET_PWD,
    extra_auth_params={
        "auth_type": "ConfigFileAuthentication",
        "profile": "DEFAULT"
    }
)

Result:

DPY-6005: cannot connect to database.
DPY-6000: Listener refused connection. (Similar to ORA-12506)

Test 2 — access_token 2-tuple with TNS alias from wallet tnsnames.ora

import oracledb

WALLET_DIR = r"path\to\wallet"
WALLET_PWD = "wallet_password"

with open(r"~\.oci\db-token\token") as f:
    db_token = f.read().strip()
with open(r"~\.oci\db-token\oci_db_key.pem") as f:
    db_key = f.read().strip()

conn = oracledb.connect(
    dsn="<tns_alias>",
    config_dir=WALLET_DIR,
    wallet_location=WALLET_DIR,
    wallet_password=WALLET_PWD,
    access_token=(db_token, db_key)
)

Note: tnsnames.ora downloaded from ADB-S console does not contain TOKEN_AUTH in the SECURITY section — this is the as-is wallet file as downloaded from Oracle Cloud Console.

Result:

DPY-6005: cannot connect to database.
DPY-6000: Listener refused connection. (Similar to ORA-12506)

Test 3 — access_token 2-tuple with explicit DSN, no TOKEN_AUTH

import oracledb

WALLET_DIR = r"path\to\wallet"
WALLET_PWD = "wallet_password"
PE_HOST    = "<pe-host>.adb.xx-xxxxx-x.oraclecloud.com"
PE_PORT    = 1522
SERVICE    = "<hash>_<dbname>_high.adb.oraclecloud.com"

with open(r"~\.oci\db-token\token") as f:
    db_token = f.read().strip()
with open(r"~\.oci\db-token\oci_db_key.pem") as f:
    db_key = f.read().strip()

dsn = (
    f"(DESCRIPTION=(ADDRESS=(PROTOCOL=TCPS)(PORT={PE_PORT})(HOST={PE_HOST}))"
    f"(CONNECT_DATA=(SERVICE_NAME={SERVICE}))"
    f"(SECURITY=(SSL_SERVER_DN_MATCH=YES)))"
)

conn = oracledb.connect(
    dsn=dsn,
    wallet_location=WALLET_DIR,
    wallet_password=WALLET_PWD,
    access_token=(db_token, db_key)
)

Result:

DPY-6005: cannot connect to database.
DPY-6000: Listener refused connection. (Similar to ORA-12506)

Test 4 — access_token 2-tuple with explicit DSN and TOKEN_AUTH=OCI_TOKEN injected in SECURITY section

We explicitly added TOKEN_AUTH=OCI_TOKEN to the DSN SECURITY section to verify whether the driver passes it in the TNS Connect packet.

import oracledb

WALLET_DIR = r"path\to\wallet"
WALLET_PWD = "wallet_password"
PE_HOST    = "<pe-host>.adb.xx-xxxxx-x.oraclecloud.com"
PE_PORT    = 1522
SERVICE    = "<hash>_<dbname>_high.adb.oraclecloud.com"

with open(r"~\.oci\db-token\token") as f:
    db_token = f.read().strip()
with open(r"~\.oci\db-token\oci_db_key.pem") as f:
    db_key = f.read().strip()

dsn = (
    f"(DESCRIPTION=(ADDRESS=(PROTOCOL=TCPS)(PORT={PE_PORT})(HOST={PE_HOST}))"
    f"(CONNECT_DATA=(SERVICE_NAME={SERVICE}))"
    f"(SECURITY=(SSL_SERVER_DN_MATCH=YES)(TOKEN_AUTH=OCI_TOKEN)))"
)

conn = oracledb.connect(
    dsn=dsn,
    wallet_location=WALLET_DIR,
    wallet_password=WALLET_PWD,
    access_token=(db_token, db_key)
)

Result:

DPY-6005: cannot connect to database.
DPY-6000: Listener refused connection. (Similar to ORA-12506)

TOKEN_AUTH=OCI_TOKEN in the DSN has no effect — the listener refuses the connection identically.


Additional findings from source code inspection

We inspected the source of oci_tokens.py (installed version 3.4.2). The plugin hook function is:

def oci_token_hook(params: oracledb.ConnectParams):
    if params.extra_auth_params is not None:
        def token_callback(refresh):
            return generate_token(params.extra_auth_params, refresh)
        params.set(access_token=token_callback)

oracledb.register_params_hook(oci_token_hook)

The plugin only sets access_token on ConnectParams. It does not inject TOKEN_AUTH or any other parameter into the TNS Connect descriptor. This is consistent with Test 4 showing that even manually adding TOKEN_AUTH=OCI_TOKEN in the DSN has no effect on the listener response.


Key question to the driver team

The ADB-S Private Endpoint listener applies ACL filtering on the initial TNS Connect packet. Based on our tests and investigation, the hypothesis is:

When access_token is set as a 2-tuple (OCI IAM token) in Thin mode — either directly or via the oci_tokens plugin — does the driver include TOKEN_AUTH=OCI_TOKEN in the serialized TNS Connect packet sent to the listener?

JDBC Thin and OCI Thick clients both successfully connect to the same ADB-S Private Endpoint with the same token and wallet. The only client that fails is python-oracledb Thin mode.

Important note: The official documentation at
https://python-oracledb.readthedocs.io/en/stable/user_guide/authentication_methods.html
states that OCI IAM token-based authentication is supported in both Thin and Thick modes. However, it does not explicitly document whether Private Endpoint is a supported topology for Thin mode with IAM token. All documentation examples appear to target public ADB-S endpoints. If Private Endpoint is a known unsupported topology for Thin mode + IAM token, this should be explicitly documented.


Test Method DSN TOKEN_AUTH Result
1 extra_auth_params + oci_tokens plugin Not present DPY-6005 ORA-12506
2 access_token=(token, key) + TNS alias Not present in tnsnames.ora DPY-6005 ORA-12506
3 access_token=(token, key) + explicit DSN Not present DPY-6005 ORA-12506
4 access_token=(token, key) + explicit DSN TOKEN_AUTH=OCI_TOKEN present DPY-6005 ORA-12506
Thick mode access_token=(token, key) N/A CONNECTS
JDBC Thin Java driver Injected automatically CONNECTS

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions