Skip to Content
Welcome to Novee Developer Portal 🎉

API Keys

API keys in Novee use asymmetric cryptography (public/private key pairs) to sign JSON Web Tokens (JWTs) for secure API authentication. This approach provides stronger security than traditional API keys or secrets.

Why Use JWT Signing?

Traditional API authentication methods have limitations:

MethodDrawback
Static API KeysCan be intercepted and reused indefinitely
Shared SecretsMust be stored on both client and server
Basic AuthCredentials sent with every request

JWT signing with asymmetric keys solves these issues:

  • Your private key never leaves your system — Only the public key is shared with Novee
  • Short-lived tokens — JWTs expire quickly, limiting the window for misuse
  • Non-repudiation — Requests can be cryptographically verified as coming from you
  • No shared secrets — Even if our systems were compromised, your private key remains safe

Generate an EC Key Pair

We use ES256 (ECDSA with P-256 curve) for JWT signing. Generate your key pair using OpenSSL:

# Generate private key openssl ecparam -name prime256v1 -genkey -noout -out private.pem # Generate public key from private key openssl ec -in private.pem -pubout -out public.pem

Keep your private.pem secure! Never share it, commit it to version control, or upload it anywhere. Only the public.pem should be uploaded when creating an API key in the dashboard.

Verify Your Keys

You can verify your keys were generated correctly:

# View private key details openssl ec -in private.pem -text -noout # View public key details openssl ec -in public.pem -pubin -text -noout

Create an API Key

  1. Navigate to Dashboard → API Keys
  2. Click Create API Key
  3. Fill in the details:
    • Name: A descriptive name for the key
    • Description: (Optional) What this key is used for
    • Public Key: Paste the contents of your public.pem file
    • Key Type: Select the appropriate type
    • Environment: Choose test for development or live for production
  4. Click Create

Your API key ID will be displayed. Save this ID — you’ll need it to identify your key when making requests.

Sign a JWT

Use your private key to sign JWTs for API authentication. Here are examples in common languages:

Node.js

import jwt from 'jsonwebtoken'; import fs from 'fs'; const privateKey = fs.readFileSync('private.pem', 'utf8'); const token = jwt.sign( { sub: 'your-api-key-id', iat: Math.floor(Date.now() / 1000), exp: Math.floor(Date.now() / 1000) + 300, // 5 minutes }, privateKey, { algorithm: 'ES256' } ); // Use the token in your API requests fetch('https://api.novee.io/v1/resource', { headers: { 'Authorization': `Bearer ${token}` } });

Python

import jwt import time with open('private.pem', 'r') as f: private_key = f.read() token = jwt.encode( { 'sub': 'your-api-key-id', 'iat': int(time.time()), 'exp': int(time.time()) + 300, # 5 minutes }, private_key, algorithm='ES256' ) # Use the token in your API requests import requests response = requests.get( 'https://api.novee.io/v1/resource', headers={'Authorization': f'Bearer {token}'} )

Go

package main import ( "crypto/ecdsa" "crypto/x509" "encoding/pem" "os" "time" "github.com/golang-jwt/jwt/v5" ) func signJWT(apiKeyID string) (string, error) { keyData, _ := os.ReadFile("private.pem") block, _ := pem.Decode(keyData) privateKey, _ := x509.ParseECPrivateKey(block.Bytes) now := time.Now() token := jwt.NewWithClaims(jwt.SigningMethodES256, jwt.MapClaims{ "sub": apiKeyID, "iat": now.Unix(), "exp": now.Add(5 * time.Minute).Unix(), }) return token.SignedString(privateKey) }

JWT Claims

When signing your JWT, include these claims:

ClaimDescriptionRequired
subYour API key IDYes
iatIssued at timestamp (Unix seconds)Yes
expExpiration timestamp (Unix seconds)Yes
jtiUnique token ID (for replay protection)Recommended

Keep token lifetimes short (5-15 minutes). Generate a fresh token for each request or batch of requests.

Best Practices

Key Security

  • Store private keys in secure key management systems (AWS KMS, HashiCorp Vault, etc.)
  • Use environment variables or secrets managers, never hardcode keys
  • Rotate keys periodically and immediately if compromised
  • Use different keys for test and production environments

Token Handling

  • Generate tokens just before use, not in advance
  • Never log or expose tokens in error messages
  • Implement token refresh logic for long-running processes
  • Include a unique jti claim for critical operations

Environment Separation

  • Test keys: Use for development and staging environments
  • Live keys: Use only in production with restricted access
  • Never use test keys in production or vice versa

Troubleshooting

”Invalid signature” error

  • Ensure you’re using the correct private key matching the public key uploaded
  • Verify you’re using the ES256 algorithm
  • Check that the key is in valid PEM format

”Token expired” error

  • Check that your system clock is synchronized (use NTP)
  • Ensure the exp claim is set correctly in Unix seconds
  • Generate a fresh token and retry

”Invalid key format” error

  • Ensure the public key includes the full PEM header and footer:
    -----BEGIN PUBLIC KEY----- ... -----END PUBLIC KEY-----
  • Check for any extra whitespace or newlines
  • Verify the key was generated with the P-256 curve

Next Steps

  • Webhooks — Set up webhook endpoints for real-time events
Last updated on