zuplo 6.69.4 → 6.69.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,191 @@
1
+ ---
2
+ title: When to Use API Keys
3
+ sidebar_label: When to Use Them
4
+ ---
5
+
6
+ Choosing the right authentication method is one of the first decisions you make
7
+ when building an API. This guide explains when API keys are the right choice,
8
+ when they are not, and how they compare to JWT and OAuth.
9
+
10
+ ## API keys vs JWT vs OAuth
11
+
12
+ API keys, JWTs, and OAuth solve different problems. Picking the wrong one
13
+ creates friction for your consumers or security gaps in your API.
14
+
15
+ | | API Keys | JWT (self-issued) | OAuth 2.0 |
16
+ | ------------------------ | --------------------------------------------------------------- | ------------------------------------------------------------------ | ---------------------------------------------------------------- |
17
+ | **Identifies** | An organization, system, or service | A user or service (claims embedded in token) | A user acting through a third-party app |
18
+ | **Credential format** | Opaque string - no embedded data | Encoded JSON with claims (readable by anyone) | Access token issued by an authorization server |
19
+ | **Revocation** | Instant - delete the key and it stops working | Not instant - valid until expiry (unless you maintain a blocklist) | Depends on token lifetime and refresh flow |
20
+ | **Developer experience** | Single string in a header, works in curl | Requires token generation, sometimes a signing key | Requires redirect flow, client registration, token exchange |
21
+ | **Best for** | Server-to-server integrations, developer platforms, public APIs | Internal service-to-service auth, short-lived sessions | User-facing apps that need delegated access ("act on behalf of") |
22
+
23
+ :::note
24
+
25
+ API key authentication, like all bearer token authentication, requires HTTPS in
26
+ production. Without TLS, keys are transmitted in plaintext and can be
27
+ intercepted in transit.
28
+
29
+ :::
30
+
31
+ ### When to use API keys
32
+
33
+ API keys are the right choice when your API consumers are **organizations,
34
+ services, or developers integrating server-to-server** - not individual
35
+ end-users acting on their own behalf.
36
+
37
+ This is why the most successful API-first companies use API keys:
38
+
39
+ - **Stripe** - every API call uses an API key scoped to the organization
40
+ - **Twilio** - Account SID + Auth Token (functionally an API key pair)
41
+ - **Resend** - API keys with scoped permissions per key
42
+ - **Datadog, Cloudflare, PagerDuty** - all use API keys for their public APIs
43
+
44
+ Use API keys when:
45
+
46
+ - Your consumers are developers integrating with your API from their backend
47
+ - You want the simplest possible developer experience - a single string, no
48
+ token refresh, works in curl
49
+ - You need to identify and rate-limit individual consumers or organizations
50
+ - You want the ability to revoke access instantly (unlike JWTs, which remain
51
+ valid until they expire)
52
+ - You are building a developer platform, partner API, or public API
53
+
54
+ :::warning
55
+
56
+ Do not embed API keys in frontend JavaScript, mobile apps, or any client-side
57
+ code. Keys in client bundles are trivially extractable and cannot be scoped to a
58
+ user session. Use OAuth for scenarios where individual end-users authenticate
59
+ from a browser or device.
60
+
61
+ :::
62
+
63
+ ### When to use JWT or OAuth
64
+
65
+ Use JWT or OAuth when:
66
+
67
+ - You need to authenticate **on behalf of an individual end-user** (the redirect
68
+ and consent flow - often called the "OAuth dance" - exists for this reason)
69
+ - Your use case requires **delegated authorization with scoped permissions**
70
+ (e.g., "this app can read my repos but not delete them")
71
+ - You are building a **user-facing login flow** where the user interacts with
72
+ your auth provider directly
73
+
74
+ ### Quick decision checklist
75
+
76
+ | Question | If yes | If no |
77
+ | -------------------------------------------------------- | -------------------------------------- | --------------------------------------------- |
78
+ | Are your consumers machines or backend services? | API keys are a strong fit | Consider OAuth for human users |
79
+ | Do you need delegated user consent ("act on behalf of")? | Use OAuth | API keys work well |
80
+ | Do consumers need to refresh credentials periodically? | OAuth handles this with refresh tokens | API keys are simpler - no refresh flow needed |
81
+
82
+ ## Why API keys over JWTs for public APIs
83
+
84
+ Developers sometimes default to JWTs for everything because they are a
85
+ "standard." But for public and partner APIs, API keys have concrete advantages:
86
+
87
+ ### Simpler developer experience
88
+
89
+ An API key is a single string. Your consumer puts it in a header and makes a
90
+ request:
91
+
92
+ ```bash
93
+ curl https://api.example.com/v1/orders \
94
+ -H "Authorization: Bearer zpka_d67b7e241bb948758f415b79..."
95
+ ```
96
+
97
+ No token endpoint, no client credentials, no refresh flow, no clock skew issues.
98
+ The time from "I got my API key" to "I made my first successful request" is
99
+ measured in seconds.
100
+
101
+ ### Opaque by design
102
+
103
+ A JWT is a base64url-encoded JSON object. Anyone can decode it and see the
104
+ claims inside - user IDs, email addresses, roles, org names. This is a feature
105
+ when you need claims on the client side, but it is a liability when you are
106
+ issuing credentials to third parties. Leaking a JWT leaks its contents.
107
+
108
+ API keys are opaque strings. They contain no embedded data. The consumer's
109
+ identity and metadata are stored server-side and resolved at validation time.
110
+ Nothing is leaked if the key is intercepted, beyond the key itself.
111
+
112
+ ### Instant revocation
113
+
114
+ When you revoke a JWT, it remains valid until it expires. The only way to
115
+ force-invalidate a JWT before expiry is to maintain a server-side blocklist -
116
+ which eliminates the main advantage of JWTs (stateless validation).
117
+
118
+ When you delete or expire an API key in Zuplo, the change propagates globally in
119
+ seconds. A revoked key stops working as soon as edge caches refresh - within the
120
+ configured `cacheTtlSeconds` (default 60 seconds). Compare this to a JWT with a
121
+ 15-minute or 1-hour expiry: there is no equivalent long expiry window to wait
122
+ out.
123
+
124
+ ### Per-consumer identity without token management
125
+
126
+ With API keys, the identity is the key itself. Zuplo resolves the consumer on
127
+ every request and populates `request.user` with the consumer's name and
128
+ metadata. There is no token to decode, validate, or refresh.
129
+
130
+ This makes downstream logic simpler - your handlers and policies always have a
131
+ consistent `request.user.sub` and `request.user.data` regardless of which API
132
+ key the consumer used.
133
+
134
+ Once you decide that API keys are the right fit, the next question is how keys
135
+ are stored and surfaced to consumers.
136
+
137
+ ## Retrievable vs irretrievable keys
138
+
139
+ One architectural decision in API key systems is whether keys are
140
+ **retrievable** (the consumer can view the key again after creation) or
141
+ **irretrievable** (the key is shown once at creation time and then stored as a
142
+ hash).
143
+
144
+ | | Retrievable | Irretrievable |
145
+ | ------------------ | ------------------------------------------------------ | -------------------------------------------------------- |
146
+ | **Examples** | Twilio, Airtable | Stripe, AWS |
147
+ | **After creation** | Consumer can view the key again in the portal | Key is shown once - consumer must copy it immediately |
148
+ | **Storage** | Key can be returned to authorized users | Only a hash is stored - original key cannot be recovered |
149
+ | **Trade-off** | More convenient; reduces support burden from lost keys | Forces immediate key storage discipline |
150
+
151
+ The conventional wisdom is that irretrievable keys are more secure because they
152
+ are never stored in plaintext. But this has a counterintuitive downside:
153
+ **irretrievable keys force consumers to copy the key somewhere else** - often a
154
+ password manager, a `.env` file, a Slack message, or a sticky note. The key
155
+ still exists in plaintext, just in a location you don't control.
156
+
157
+ Retrievable keys let consumers go back to the portal when they need the key
158
+ again, reducing the pressure to store it in an insecure location. For teams with
159
+ less rigorous secret management practices, this can actually be the safer
160
+ option.
161
+
162
+ **Zuplo keys are retrievable.** Consumers can view their keys in the developer
163
+ portal or through the API using the `key-format=visible` parameter. This
164
+ balances security with the reality of how most development teams actually manage
165
+ secrets.
166
+
167
+ ## They are not mutually exclusive
168
+
169
+ Many APIs use both. A common pattern:
170
+
171
+ - **API keys** for system-level access - your customers' backends call your API
172
+ with an API key that identifies their organization
173
+ - **OAuth** for user-level access - end-users authorize a third-party app to act
174
+ on their behalf through your API
175
+
176
+ Zuplo supports both patterns. You can apply
177
+ [API Key Authentication](../policies/api-key-inbound.mdx) and
178
+ [JWT Authentication](../policies/open-id-jwt-auth-inbound.mdx) to different
179
+ routes in the same project, or even
180
+ [combine multiple auth methods](./multiple-auth-policies.mdx) on a single route.
181
+
182
+ ## Next steps
183
+
184
+ - [API Keys Overview](./api-key-management.mdx) - set up API key authentication
185
+ in minutes
186
+ - [API Key Best Practices](./api-key-best-practices.mdx) - the 8 practices that
187
+ define a well-designed API key system
188
+ - [API Key Authentication policy](../policies/api-key-inbound.mdx) - configure
189
+ the policy on your routes
190
+ - [Authentication concepts](../concepts/authentication.mdx) - how all
191
+ authentication methods work in Zuplo
@@ -0,0 +1,37 @@
1
+ ---
2
+ title: "Zuplo CLI: Info"
3
+ sidebar_label: info
4
+ ---
5
+
6
+ <CliCommand
7
+ command="info"
8
+ description="Alias for `project info`"
9
+ options={[
10
+ {
11
+ "name": "dir",
12
+ "type": "string",
13
+ "description": "The directory containing your Zuplo API",
14
+ "default": ".",
15
+ "required": false,
16
+ "deprecated": false,
17
+ "hidden": true,
18
+ "normalize": true
19
+ }
20
+ ]}
21
+ examples={[
22
+ [
23
+ "$0 info",
24
+ "Display information about the current linked project"
25
+ ]
26
+ ]}
27
+ usage="$0 info [options]"
28
+ >
29
+
30
+ </CliCommand>
31
+
32
+ ## Global options
33
+
34
+ The following global options are available for all commands:
35
+
36
+ - [`--help`](./global-options.mdx#help)
37
+ - [`--api-key`](./global-options.mdx#api-key)
@@ -0,0 +1,37 @@
1
+ ---
2
+ title: "Zuplo CLI: Project Info"
3
+ sidebar_label: project info
4
+ ---
5
+
6
+ <CliCommand
7
+ command="project info"
8
+ description="Displays information about the current project and linked environment"
9
+ options={[
10
+ {
11
+ "name": "dir",
12
+ "type": "string",
13
+ "description": "The directory containing your Zuplo API",
14
+ "default": ".",
15
+ "required": false,
16
+ "deprecated": false,
17
+ "hidden": true,
18
+ "normalize": true
19
+ }
20
+ ]}
21
+ examples={[
22
+ [
23
+ "$0 project info",
24
+ "Display information about the current linked project"
25
+ ]
26
+ ]}
27
+ usage="$0 project info [options]"
28
+ >
29
+
30
+ </CliCommand>
31
+
32
+ ## Global options
33
+
34
+ The following global options are available for all commands:
35
+
36
+ - [`--help`](./global-options.mdx#help)
37
+ - [`--api-key`](./global-options.mdx#api-key)
@@ -21,15 +21,25 @@ The API key system has three core objects:
21
21
  metadata.
22
22
 
23
23
  See [API Key Management](../articles/api-key-management.mdx) for a full
24
- overview, and [API Key Administration](../articles/api-key-administration.mdx)
25
- for managing consumers in the portal.
24
+ overview, and
25
+ [Manage Keys in the Portal](../articles/api-key-administration.mdx) for managing
26
+ consumers in the portal.
26
27
 
27
28
  ## How validation works
28
29
 
29
30
  When a request includes an API key, the
30
31
  [API Key Authentication](../policies/api-key-inbound.mdx) policy validates it
31
- against Zuplo's globally distributed key service. Validation happens at the edge
32
- in 300+ data centers, keeping latency low and load off your backend.
32
+ through a multi-step process at the edge in 300+ data centers:
33
+
34
+ 1. **Format check** - the key is checked for the correct `zpka_` prefix and
35
+ structure. Malformed keys are rejected immediately without any network call.
36
+ 2. **Checksum validation** - the key's built-in checksum signature is verified.
37
+ This catches typos and garbage keys in microseconds.
38
+ 3. **Cache lookup** - the edge checks its local cache for this key. If the key
39
+ was recently validated (or recently rejected), the cached result is used.
40
+ 4. **Key service lookup** - if the key is not cached, Zuplo's globally
41
+ distributed key service is queried. The result is then cached for the
42
+ configured TTL (default 60 seconds).
33
43
 
34
44
  Key changes (creation, revocation, deletion) replicate globally in seconds.
35
45
 
@@ -42,6 +52,16 @@ This lets downstream policies and handlers make authorization decisions, apply
42
52
  per-consumer [rate limits](./rate-limiting.md), or forward identity to your
43
53
  backend.
44
54
 
55
+ :::note
56
+
57
+ The `cacheTtlSeconds` option on the API Key Authentication policy controls how
58
+ long validation results are cached at each edge location. Higher values reduce
59
+ latency but delay the effect of key revocation. A revoked key could still be
60
+ accepted for up to `cacheTtlSeconds` after revocation. The default of 60 seconds
61
+ is a good balance for most use cases.
62
+
63
+ :::
64
+
45
65
  See [Authentication](./authentication.mdx) for how `request.user` works across
46
66
  all auth methods, and [RequestUser](../programmable-api/request-user.mdx) for
47
67
  the full type reference.
@@ -74,7 +94,7 @@ organizing consumers via the API). Tags are not sent to the runtime.
74
94
  API keys are the right authentication method when you need to identify an
75
95
  organization, system, or service calling your API. Companies like Stripe,
76
96
  Twilio, and SendGrid use API keys because they offer a simple developer
77
- experience a single string in a header, easy to test with curl, and no token
97
+ experience - a single string in a header, easy to test with curl, and no token
78
98
  refresh flow.
79
99
 
80
100
  Use API keys when:
@@ -94,6 +114,10 @@ Use OAuth or JWT when:
94
114
  API keys and JWT/OAuth are not mutually exclusive. Many APIs use API keys for
95
115
  system-level access and OAuth for user-level actions.
96
116
 
117
+ For a full comparison including a decision checklist and retrievable vs
118
+ irretrievable keys, see
119
+ [When to Use API Keys](../articles/when-to-use-api-keys.md).
120
+
97
121
  ## API key format
98
122
 
99
123
  Zuplo API keys use a structured three-part format:
@@ -104,21 +128,21 @@ zpka_<random>_<checksum>
104
128
 
105
129
  Each part serves a specific purpose:
106
130
 
107
- - **`zpka_` prefix** identifies the string as a Zuplo API key. This enables
131
+ - **`zpka_` prefix** - identifies the string as a Zuplo API key. This enables
108
132
  automated [leak detection](../articles/api-key-leak-detection.mdx) via GitHub
109
133
  secret scanning (scanners match the prefix pattern), helps support teams
110
134
  identify key types during debugging, and distinguishes Zuplo keys from other
111
135
  credentials in logs and config files.
112
- - **Random body** a cryptographically random string that serves as the actual
136
+ - **Random body** - a cryptographically random string that serves as the actual
113
137
  credential. This portion is generated using a secure random source and
114
138
  provides the entropy that makes each key unique.
115
- - **Checksum signature** a suffix that allows instant format validation. When
139
+ - **Checksum signature** - a suffix that allows instant format validation. When
116
140
  a request arrives, Zuplo can verify the checksum mathematically in
117
141
  microseconds to confirm the key is structurally valid before making any
118
142
  network call. This rejects typos, truncated keys, and garbage strings without
119
143
  touching the database.
120
144
 
121
- The underscore separators are also intentional they ensure that a double-click
145
+ The underscore separators are also intentional - they ensure that a double-click
122
146
  on the key in most text editors and terminals selects the entire string,
123
147
  reducing the chance of accidentally copying a partial key.
124
148
 
@@ -155,9 +179,6 @@ when a user signs in using
155
179
  [Auth0](../dev-portal/dev-portal-create-consumer-on-auth.mdx) or another
156
180
  identity provider.
157
181
 
158
- You can also embed the key management UI directly in your own application using
159
- the [API Key React Component](../articles/api-key-react-component.mdx).
160
-
161
182
  ## Buckets and environments
162
183
 
163
184
  Each project has separate buckets for production, preview, and working copy
@@ -187,20 +208,19 @@ See the [API Reference](/docs/api) for the complete endpoint documentation.
187
208
 
188
209
  ## Related documentation
189
210
 
190
- - [API Key Management](../articles/api-key-management.mdx) -- Overview and
211
+ - [API Keys Overview](../articles/api-key-management.mdx) -- Overview and
191
212
  getting started
192
213
  - [API Key Authentication Policy](../policies/api-key-inbound.mdx) -- Policy
193
214
  configuration reference
194
- - [API Key Administration](../articles/api-key-administration.mdx) -- Managing
195
- keys in the portal
196
- - [Using the API Key API](../articles/api-key-api.mdx) -- Programmatic
215
+ - [Manage Keys in the Portal](../articles/api-key-administration.mdx) --
216
+ Managing keys in the portal
217
+ - [Use the Developer API](../articles/api-key-api.mdx) -- Programmatic
197
218
  management
198
- - [End User Access](../articles/api-key-end-users.mdx) -- Self-serve in the
199
- developer portal
200
- - [React Component](../articles/api-key-react-component.mdx) -- Embed key
201
- management in your app
202
- - [Leak Detection](../articles/api-key-leak-detection.mdx) -- GitHub secret
203
- scanning
204
- - [Buckets](../articles/api-key-buckets.mdx) -- Bucket configuration
205
- - [Service Limits](../articles/api-key-service-limits.mdx) -- Rate limits and
206
- quotas
219
+ - [Share Keys with End Users](../articles/api-key-end-users.mdx) -- Self-serve
220
+ in the developer portal
221
+ - [API Key Leak Detection](../articles/api-key-leak-detection.mdx) -- GitHub
222
+ secret scanning
223
+ - [Buckets and Environments](../articles/api-key-buckets.mdx) -- Bucket
224
+ configuration
225
+ - [API Key Service Limits](../articles/api-key-service-limits.mdx) -- Rate
226
+ limits and quotas
@@ -46,5 +46,5 @@ configuration details.
46
46
 
47
47
  ## Related resources
48
48
 
49
- - [API Key Authentication](../articles/api-key-authentication.mdx)
50
- - [API Key Administration](../articles/api-key-administration.mdx)
49
+ - [Authentication and Authorization](../articles/api-key-authentication.mdx)
50
+ - [Manage Keys in the Portal](../articles/api-key-administration.mdx)
@@ -4,7 +4,7 @@
4
4
  "type": "object",
5
5
  "title": "Monetization",
6
6
  "isDeprecated": false,
7
- "isPaidAddOn": true,
7
+ "isPaidAddOn": false,
8
8
  "isEnterprise": false,
9
9
  "isInternal": false,
10
10
  "isBeta": false,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zuplo",
3
- "version": "6.69.4",
3
+ "version": "6.69.6",
4
4
  "type": "module",
5
5
  "description": "The programmable API Gateway",
6
6
  "author": "Zuplo, Inc.",
@@ -19,9 +19,9 @@
19
19
  "zuplo": "zuplo.js"
20
20
  },
21
21
  "dependencies": {
22
- "@zuplo/cli": "6.69.4",
23
- "@zuplo/core": "6.69.4",
24
- "@zuplo/runtime": "6.69.4",
22
+ "@zuplo/cli": "6.69.6",
23
+ "@zuplo/core": "6.69.6",
24
+ "@zuplo/runtime": "6.69.6",
25
25
  "@zuplo/test": "1.4.0"
26
26
  }
27
27
  }