Authentication
Every OpenAPI request must be authenticated. This page explains the supported authentication methods, environment variable configuration, and token refresh mechanism.
Authentication Methods
OpenAPI supports two authentication methods:
Method 1: OAuth 2.0 (Recommended)
OAuth 2.0 is a modern authentication method using Bearer Tokens. No HMAC signing is needed — it's more secure and convenient.
Step 1: Register an OAuth Client
Run the following command to register an OAuth client and obtain a client_id:
curl -X POST https://openapi.futunn.com/oauth2/register \
-H "Content-Type: application/json" \
-d '{
"redirect_uris": ["http://localhost:60355/callback"],
"token_endpoint_auth_method": "none",
"grant_types": ["authorization_code","refresh_token"],
"response_types": ["code"],
"client_name": "My Futu OpenAPI"
}'Response example:
{
"client_id": "72d9caaf-0bd4-4000-85a7-8c7978c74544",
"client_id_issued_at": 1773311221,
"client_secret_expires_at": 1773314821,
"client_name": "My Futu OpenAPI",
"redirect_uris": ["http://localhost:60355/callback"],
"grant_types": ["authorization_code", "refresh_token"],
"token_endpoint_auth_method": "none",
"response_types": ["code"],
"registration_access_token": "BVlMLEtNUUu4FoRFNItC2FfeR/rLpqLNyEuCJNNTCWE=",
"registration_client_uri": "https://openapi.futunn.com/oauth2/register/72d9caaf-0bd4-4000-85a7-8c7978c74544"
}Save the client_id for later use.
Step 2: Authorize and Obtain Token
The SDK provides built-in OAuth support. Use OAuthBuilder to complete the browser authorization flow, then use Config.from_oauth() to create the configuration. Tokens are automatically persisted and refreshed on expiry.
Token storage path: macOS/Linux: ~/.futu/openapi/tokens/<client_id>, Windows: %USERPROFILE%\.futu\openapi\tokens\<client_id>.
Python
from futu.openapi import Config, OAuthBuilder
oauth = OAuthBuilder("your-client-id").build(
lambda url: print(f"Please visit this URL to authorize: {url}")
)
config = Config.from_oauth(oauth)JavaScript
const { Config, OAuth } = require('@futu/openapi')
const oauth = await OAuth.build('your-client-id', (_, url) => {
console.log('Please visit this URL to authorize: ' + url)
})
const config = Config.fromOAuth(oauth)OAuth Advantages
- More secure (no shared secrets)
- Simpler (no signature computation)
- Modern token-based authentication
- Automatic token persistence and refresh
:::caution Token Security OAuth Tokens should be stored securely in your application (e.g., encrypted files, secure keychain). Do not store them in environment variables. :::
Method 2: Traditional API Key (Legacy)
Obtaining App Key, App Secret, and Access Token
Sign in to the Developer Portal and navigate to User Center.
The page will display your Application Credentials (App Key, App Secret, Access Token). Note that this Access Token is a legacy API Key credential, which is different from the access token returned by OAuth.
:::caution Protect your Access Token carefully — anyone who obtains it can trade on your account via OpenAPI! :::
Environment Variables
Traditional API Key credentials (only 3 required):
| Variable | Description |
|---|---|
FUTU_APP_KEY | App Key obtained from the portal |
FUTU_APP_SECRET | App Secret obtained from the portal |
FUTU_ACCESS_TOKEN | Access Token obtained from the Developer Portal (User Center → Application Credentials) |
Other environment variables:
| Name | Description |
|---|---|
FUTU_HTTP_URL | HTTP API endpoint (default: https://openapi.futunn.com) |
FUTU_QUOTE_WS_URL | Quote WebSocket endpoint |
FUTU_TRADE_WS_URL | Trade WebSocket endpoint |
FUTU_LANGUAGE | Language identifier: zh-CN, zh-HK, or en (default: en) |
FUTU_REGION | Override access point. SDK auto-selects based on network; set manually if incorrect |
FUTU_LOG_PATH | Log file path (default: no logging) |
About Environment Variables
Environment variables are not mandatory. If setting them is inconvenient, you can initialize directly in code with parameters. The SDK Config can use Config.from_env() to create from environment variables, or Config.new(app_key, app_secret, access_token) with explicit parameters.
macOS / Linux
Open a terminal and run:
export FUTU_APP_KEY="Your App Key"
export FUTU_APP_SECRET="Your App Secret"
export FUTU_ACCESS_TOKEN="Your Access Token"Windows
Using CMD:
C:\Users\user> setx FUTU_APP_KEY "Your App Key"
SUCCESS: Specified value was saved.
C:\Users\user> setx FUTU_APP_SECRET "Your App Secret"
SUCCESS: Specified value was saved.
C:\Users\user> setx FUTU_ACCESS_TOKEN "Your Access Token"
SUCCESS: Specified value was saved.:::caution Windows Environment Variables After running the commands above, you need to restart Windows or log out and back in for the variables to take effect. :::
After restarting, verify with:
C:\Users\user> set FUTU
FUTU_APP_KEY=xxxxxxx
FUTU_APP_SECRET=xxxxxx
FUTU_ACCESS_TOKEN=xxxxxxxRequest Signature
When using traditional API Key, each HTTP request is signed with HMAC-SHA256 over the canonical string METHOD\nPATH\nTIMESTAMP\nBODY using your App Secret as the key. The resulting signature is sent in the X-Api-Signature header:
POST /v1/quote/snapshot HTTP/1.1
Host: openapi.futunn.com
X-Api-Key: {appKey}
X-Api-Timestamp: 1714032000
X-Api-Signature: {hmacSha256Hex}
Authorization: Bearer {accessToken}
Content-Type: application/jsonTimestamps older than 60 seconds are rejected to mitigate replay attacks.
Refreshing the Access Token
INFO
This section applies to traditional API Key authentication only. OAuth 2.0 tokens are refreshed automatically by the SDK.
The traditional API Key Access Token expires after 90 days by default. Call the refresh method before expiry to obtain a new token, then update your FUTU_ACCESS_TOKEN.
Python
from datetime import datetime, timedelta
from futu.openapi import Config
config = Config.from_env()
# Set expiry to 3 years from now
new_token = config.refresh_access_token(
expired_at=datetime.now() + timedelta(days=365 * 3)
)
print("New Access Token:", new_token)JavaScript
const { Config } = require('@futu/openapi')
const config = Config.fromEnv()
const expiredAt = new Date()
expiredAt.setFullYear(expiredAt.getFullYear() + 3)
const newToken = await config.refreshAccessToken(expiredAt)
console.log('New Access Token:', newToken)The expired_at parameter specifies the new token's expiry time (default: 90 days from now).
Revoking Credentials
If a credential is leaked, revoke it immediately from the Developer Portal. Revocation takes effect within 30 seconds across all endpoints.