- 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
- Is it an error or a hang or a crash?
Immediate error on every connect attempt.
- 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.x — OK
- TCP port 1522 reachable — OK
ewallet.pem present and valid — OK
- IAM DB token acquired via
oci iam db-token get — OK (1934 chars, valid)
- Private key file present — OK (1703 chars, PKCS8)
The same token, wallet, and network path work correctly with:
- python-oracledb Thick mode → CONNECTS
- JDBC Thin (SQL Developer) → CONNECTS
- SQL*Plus with OCI Instant Client (Thick) → CONNECTS
- Does your application call init_oracle_client()?
No. Thin mode only. Confirmed via oracledb.is_thin_mode() → True.
- 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 |
Immediate error on every connect attempt.
All pre-connection checks pass:
xx.x.x.x— OKewallet.pempresent and valid — OKoci iam db-token get— OK (1934 chars, valid)The same token, wallet, and network path work correctly with:
No. Thin mode only. Confirmed via
oracledb.is_thin_mode()→True.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_paramswithoci_tokensplugin (ConfigFileAuthentication)This is the primary documented approach for Thin mode in the official docs.
Result:
Test 2 —
access_token2-tuple with TNS alias from wallettnsnames.oraNote:
tnsnames.oradownloaded from ADB-S console does not containTOKEN_AUTHin the SECURITY section — this is the as-is wallet file as downloaded from Oracle Cloud Console.Result:
Test 3 —
access_token2-tuple with explicit DSN, noTOKEN_AUTHResult:
Test 4 —
access_token2-tuple with explicit DSN andTOKEN_AUTH=OCI_TOKENinjected in SECURITY sectionWe explicitly added
TOKEN_AUTH=OCI_TOKENto the DSN SECURITY section to verify whether the driver passes it in the TNS Connect packet.Result:
TOKEN_AUTH=OCI_TOKENin 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:The plugin only sets
access_tokenonConnectParams. It does not injectTOKEN_AUTHor any other parameter into the TNS Connect descriptor. This is consistent with Test 4 showing that even manually addingTOKEN_AUTH=OCI_TOKENin 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_tokenis set as a 2-tuple (OCI IAM token) in Thin mode — either directly or via theoci_tokensplugin — does the driver includeTOKEN_AUTH=OCI_TOKENin 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.
extra_auth_params+oci_tokenspluginaccess_token=(token, key)+ TNS aliasaccess_token=(token, key)+ explicit DSNaccess_token=(token, key)+ explicit DSNTOKEN_AUTH=OCI_TOKENpresentaccess_token=(token, key)