Authentication
QWeather Developers Service uses JWT (JSON Web Token) and API KEY for authentication. We recommend using JWT as the preferred authentication method, which will greatly improve security.
JSON Web Token
JSON web token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties. Whether on the front-end or the back-end, JWT authentication can significantly enhance API security and prevent others to fake your identity for API requests.
QWeather uses the Ed25519 algorithm for signing, Ed25519 is an implementation of EdDSA (Edwards-curve Digital Signature Algorithm) using Curve25519 elliptic curves and SHA-512. You need to generate the private and public keys for Ed25519 in advance, where the private key is used for signing and kept by you, and the public key is used for us to verify the signature. This means that no one (including us) can forge your signature except you.
Generate Ed25519 key
You can generate Ed25519 keys locally using your preferred programming language or third-party libraries, or follow the instructions below. After generating the keys, you’ll need to add the public key to the QWeather Console for JWT authentication.
Terminal
OpenSSL v3+ is recommended; most Linux and macOS support this by default. On Windows, OpenSSL must be installed beforehand.
Run these commands in a terminal:
openssl genpkey -algorithm ED25519 -out ed25519-private.pem
openssl pkey -pubout -in ed25519-private.pem > ed25519-public.pem
This will create two files in the current directory:
- ed25519-private.pem, the private key, which is used for signatures for JWT authentication. You should keep the private key safe and secure.
- ed25519-public.pem, the public key, which is used for signature verification and needs to be uploaded to the QWeather Console.
Browser
Supported on Chrome 137+, Edge 137+, Firefox 129+ and Safari 17+.
Open the browser console (F12), enter the following code and press Enter:
async function generateEd25519Pem() {
const k = await crypto.subtle.generateKey({name:"Ed25519"},true,["sign","verify"]);
const p8 = await crypto.subtle.exportKey("pkcs8",k.privateKey);
const spki = await crypto.subtle.exportKey("spki",k.publicKey);
const pem = (d,t)=>{
let b=btoa(String.fromCharCode(...new Uint8Array(d)));
return`-----BEGIN ${t}-----\n${b.match(/.{1,64}/g).join("\n")}\n-----END ${t}-----`;
};
const priv=pem(p8,"PRIVATE KEY");
const pub=pem(spki,"PUBLIC KEY");
console.log("PrivateKey:\n",priv,"\n\nPublicKey:\n",pub);
return{priv,pub};
}
You will see PrivateKey and PublicKey printed in the browserconsole.
JWT Tools
Refer to JWT Debugging.
Upload public key
Once your Ed25519 keys is generated, you need to add the public key to the QWeather console for JWT authentication.
- Go to Console-Project
- Choose the project where you want to add the public key.
- Click the Add Credential button in the credential section.
- Enter the credential name.
- Select the authentication method: JSON Web Token.
- Use any text editor to open the public key (like ed25519-public.pem which was generated in the previous step), and copy the entire contents of it. The content looks like:
-----BEGIN PUBLIC KEY----- MCowBQYDK2VwAyEAARbeZ5AhklFG4gg1Gx5g5bWxMMdsUd6b2MC4wV0/M9Q= -----END PUBLIC KEY----- - Paste the public key in the textarea.
- Click Save button
You will see the Create Credential Success page and it shows the creation date, credential ID and SHA-256. For security reasons, you cannot view this public key in the Console again. However, you can use the SHA-256 value of the public key to compare it with the local SHA-256 in order to confirm that the correct public key was used (leading/trailing whitespace and line breaks of the uploaded public key will be removed before SHA256 calculation).
Generate JWT
QWeather supports the JWT protocol and specification, in most cases you don’t need to write your own code for generating JWT, almost all programming languages have third-party open source libraries for JWT generation, you can find these libraries in JWT.io.
A complete JWT consists of three parts: Header, Payload and Signature. we will introduce the mandatory parameters in each part:
Header
Header includes the following parameters and saved in JSON object format:
algThe signature algorithm, set the value to EdDSA.kidYour Credential ID, you can copy it in Console - Project Management.
For example:
{
"alg": "EdDSA",
"kid": "ABCDE12345"
}
Payload
Payload includes the following parameters and saved in JSON object format:
subSubject, this value is your Project ID of the Credential.iatIssue time, this value indicates the time when the JWT was generated and effective, in UNIX timestamp format.expexpiration time, this value indicates when the JWT expires, in UNIX timestamp format. A longer expiration time reduces overhead, but a shorter time improves security. The maximum expiration time is 24 hours(86400 seconds).
For example:
{
"sub": "ABC2345DEF",
"iat": 1703912400,
"exp": 1703912940
}
Warning: Only add the specified parameters above in the Header and Payload, do not add any other sensitive information and irrelevant parameters.
Signature
Encode the Header and Payload using Base64URL and separate them by a dot, then sign them with your private key using the Ed25519 algorithm. Once you have this signature, encode signature with Base64URL as well.
Putting all together
Finally, put the Base64URL-encoded Header, Payload, and Signature together and separate them with dots, like header.payload.signature, that’s the Token we need, for example:
eyJhbGciOiAiRWREU0EiLCJraWQiOiAiQUJDRDEyMzQifQ.eyJpc3MiOiJBQkNEMTIzNCIsImlhdCI6MTcwMzkxMjQwMCwiZXhwIjoxNzAzOTEyOTQwfQ.MEQCIFGLmpmAEwuhB74mR04JWg_odEau6KYHYLRXs8Bp_miIAiBMU5O13vnv9ieEBSK71v4UULMI4K5T9El6bCxBkW4BdA
Reserved fields
The following are reserved fields in the JWT Header and Payload, but are not currently used for authentication.
Some JWT libraries may include these fields by default. We recommend removing them to avoid potential issues when these fields are enforced for authentication in the future.
typMust be set to JWT if it is added.issaudnbf
Authorize request
Add the Token as a parameter to the Authorization: Bearer request header, for example:
curl --compressed \
-H 'Authorization: Bearer eyJhbGciOiAiRWREU0EiLCJraWQiOiAiQUJDRDEyMzQifQ.eyJpc3MiOiJBQkNEMTIzNCIsImlhdCI6MTcwMzkxMjQwMCwiZXhwIjoxNzAzOTEyOTQwfQ.MEQCIFGLmpmAEwuhB74mR04JWg_odEau6KYHYLRXs8Bp_miIAiBMU5O13vnv9ieEBSK71v4UULMI4K5T9El6bCxBkW4BdA' \
'https://abcxyz.qweatherapi.com/v7/weather/now?location=101010100'
Debugging
We provide two tools to help with JWT generation and validation:
JWT Debugger
An open-source, offline JWT debugging tool to generate Ed25519 key and create JWTs for testing.
Note: This tool is for debugging and testing only. Generate JWT in your project using application code or third-party libraries.
- Go https://jwt.qweather.com
- Copy or download the Ed25519 key. Click “Re-generate” or refresh your browser to generate a new key.
- Click the orange text, replace it with your
kid,sub,iat, andexp, paste your private key into the private key field, and the JWT will be generated immediately.
JWT Validator
If the API returns a 401 error, use the Console JWT Validator to check your token:
Note: For security reasons, only JWTs that match your account can be verified.
- Go to Console-JWT Validation
- Paste your token into the textbox
- Click the “Validate” button
JWT demo
Please replace YOUR_KEY_ID, YOUR_PROJECT_ID, YOUR_PRIVATE_KEY or PATH_OF_YOUR_PRIVATE_KEY in the code with your values.
Hint: These demos are for reference and test only, we can’t guarantee that they will work in any environment.
Java 15+
// Private key
String privateKeyString = "YOUR PRIVATE KEY";
privateKeyString = privateKeyString.replace("-----BEGIN PRIVATE KEY-----", "").replace("-----END PRIVATE KEY-----", "").trim();
byte[] privateKeyBytes = Base64.getDecoder().decode(privateKeyString);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("EdDSA");
PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
// Header
String headerJson = "{\"alg\": \"EdDSA\", \"kid\": \"YOUR_KEY_ID\"}";
// Payload
long iat = ZonedDateTime.now(ZoneOffset.UTC).toEpochSecond() - 30;
long exp = iat + 900;
String payloadJson = "{\"sub\": \"YOUR_PROJECT_ID\", \"iat\": " + iat + ", \"exp\": " + exp + "}";
// Base64url header+payload
String headerEncoded = Base64.getUrlEncoder().encodeToString(headerJson.getBytes(StandardCharsets.UTF_8));
String payloadEncoded = Base64.getUrlEncoder().encodeToString(payloadJson.getBytes(StandardCharsets.UTF_8));
String data = headerEncoded + "." + payloadEncoded;
// Sign
Signature signer = Signature.getInstance("EdDSA");
signer.initSign(privateKey);
signer.update(data.getBytes(StandardCharsets.UTF_8));
byte[] signature = signer.sign();
String signatureEncoded = Base64.getUrlEncoder().encodeToString(signature);
String jwt = data + "." + signatureEncoded;
// Print Token
System.out.println("Signature:\n" + signatureEncoded);
System.out.println("JWT:\n" + jwt);
Java 8+
Required dependency: ed25519-java
<dependency>
<groupId>net.i2p.crypto</groupId>
<artifactId>eddsa</artifactId>
<version>0.3.0</version>
</dependency>
// Private key
byte[] privateKeyBytes = Base64.getDecoder().decode("YOUR_PRIVATE_KEY".trim().replace("-----BEGIN PRIVATE KEY-----", "").replace("-----END PRIVATE KEY-----", ""));
PKCS8EncodedKeySpec encoded = new PKCS8EncodedKeySpec(privateKeyBytes);
PrivateKey privateKey = new EdDSAPrivateKey(encoded);
// Header
String headerJson = "{\"alg\": \"EdDSA\", \"kid\": \"YOUR_KEY_ID\"}";
// Payload
long iat = ZonedDateTime.now(ZoneOffset.UTC).toEpochSecond() - 30;
long exp = iat + 900;
String payloadJson = "{\"sub\": \"YOUR_PROJECT_ID\", \"iat\": " + iat + ", \"exp\": " + exp + "}";
// Base64url header+payload
String headerEncoded = Base64.getUrlEncoder().encodeToString(headerJson.getBytes(StandardCharsets.UTF_8));
String payloadEncoded = Base64.getUrlEncoder().encodeToString(payloadJson.getBytes(StandardCharsets.UTF_8));
String data = headerEncoded + "." + payloadEncoded;
EdDSAParameterSpec spec = EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.ED_25519);
// Sign
final Signature s = new EdDSAEngine(MessageDigest.getInstance(spec.getHashAlgorithm()));
s.initSign(privateKey);
s.update(data.getBytes(StandardCharsets.UTF_8));
byte[] signature = s.sign();
String signatureString = Base64.getUrlEncoder().encodeToString(signature);
System.out.println("Signature: \n" + signatureString);
// Print Token
String jwt = data + "." + signatureString;
System.out.println("JWT: \n" + jwt);
Node.js 16+
Required dependency: npm install jose
import {SignJWT, importPKCS8} from "jose";
const YourPrivateKey = 'YOUR_PRIVATE_KEY'
importPKCS8(YourPrivateKey, 'EdDSA').then((privateKey) => {
const customHeader = {
alg: 'EdDSA',
kid: 'YOUR_KEY_ID'
}
const iat = Math.floor(Date.now() / 1000) - 30;
const exp = iat + 900;
const customPayload = {
sub: 'YOUR_PROJECT_ID',
iat: iat,
exp: exp
}
new SignJWT(customPayload)
.setProtectedHeader(customHeader)
.sign(privateKey)
.then(token => console.log('JWT: ' + token))
}).catch((error) => console.error(error))
Python3
You must run pip3 install cryptography PyJWT.
#!/usr/bin/env python3
import sys
import time
import jwt
# Open PEM
private_key = """YOUR_PRIVATE_KEY"""
payload = {
'iat': int(time.time()) - 30,
'exp': int(time.time()) + 900,
'sub': 'YOUR_PROJECT_ID'
}
headers = {
'kid': 'YOUR_KEY_ID'
}
# Generate JWT
encoded_jwt = jwt.encode(payload, private_key, algorithm='EdDSA', headers = headers)
print(f"JWT: {encoded_jwt}")
Shell
#!/bin/bash
# Set `kid`, `sub` and `private_key_path`
kid=YOUR_KEY_ID
sub=YOUR_PROJECT_ID
private_key_path=PATH_OF_YOUR_PRIVATE_KEY
# Set `iat` and `exp`
# `iat` defaults to the current time -30 seconds
# `exp` defaults to `iat` +15 minutes
iat=$(( $(date +%s) - 30 ))
exp=$((iat + 900))
# base64url encoded header and payload
header_base64=$(printf '{"alg":"EdDSA","kid":"%s"}' "$kid" | openssl base64 -e | tr -d '=' | tr '/+' '_-' | tr -d '\n')
payload_base64=$(printf '{"sub":"%s","iat":%d,"exp":%d}' "$sub" "$iat" "$exp" | openssl base64 -e | tr -d '=' | tr '/+' '_-' | tr -d '\n')
header_payload="${header_base64}.${payload_base64}"
# Save $header_payload as a temporary file for Ed25519 signature
tmp_file=$(mktemp)
echo -n "$header_payload" > "$tmp_file"
# Sign with Ed25519
signature=$(openssl pkeyutl -sign -inkey "$private_key_path" -rawin -in "$tmp_file" | openssl base64 | tr -d '=' | tr '/+' '_-' | tr -d '\n')
# Delete temporary file
rm -f "$tmp_file"
# Generate JWT
jwt="${header_payload}.${signature}"
# Print Token
echo "$jwt"
API KEY
API KEY is a common and simple authentication method. Compared to JWT, API KEY is less secure in some scenarios.
Note: To improve security, we will limit the volume of daily requests for authentication using API KEY from 2027-01-01.
Generate API KEY
You can log in to the Console to easily generate an API KEY:
- Click Project in the left menu.
- Click on the project where you want to add the API KEY.
- Click the Create Credential button in the Credential section.
- Choose API KEY as the authentication method.
- Enter the name of the API KEY, e.g. “Travel App Test”.
- Click the Create button
You can always check the API KEY in Console - Project Management.
API KEY authorize request
Warning: Please DO NOT use multiple authentication methods at the same time, it may cause authentication failure.
We support two authentication methods for API KEYs.
Request hearder
Add X-QW-Api-Key: your-key to your request Header. For example:
curl -H "X-QW-Api-Key: ABCD1234EFGH" --compressed \
'https://abcxyz.qweatherapi.com/v7/weather/now?location=101010100'
Query parameter
Add key=your-key to your query parameter. For example:
curl --compressed \
'https://abcxyz.qweatherapi.com/v7/weather/now?location=101010100&key=ABCD1234EFGH'
API KEY signature
API KEY signature authentication is no longer supported.
Compatibility
Refer to the table below for compatibility of authentication methods for various services.
| JWT | API KEY | API KEY signature | |
|---|---|---|---|
| API v7 | ✅ | ✅ | ✅ Only credentials created before 2024-11-01 |
| GeoAPI v2 | ✅ | ✅ | ✅ Only credentials created before 2024-11-01 |
| GeoAPI v3 | ✅ | ✅ | ❌ |
| Air quality API v1 | ✅ | ✅ | ❌ |
| Console API v1 | ✅ | ✅ | ❌ |
| SDK 4+ | ❌ | ❌ | ✅ |
| SDK 5+ | ✅ | ❌ | ❌ |