requestshield 0.1.0 → 0.1.3

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.
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # RequestShield CLI
2
2
 
3
3
  Customer-facing CLI for signing in, rotating RequestShield application keys,
4
- and installing the RequestShield skill for Codex.
4
+ and installing the RequestShield skill for Codex or Claude.
5
5
 
6
6
  ## Requirements
7
7
 
@@ -16,7 +16,9 @@ The API defaults to `https://api.intellifend.ai`. For development, set
16
16
  ```console
17
17
  requestshield signin
18
18
  requestshield keys create
19
- requestshield agent setup --agent codex
19
+ requestshield agent setup
20
+ requestshield agent setup --codex
21
+ requestshield agent setup --claude
20
22
  ```
21
23
 
22
24
  `signin` starts a device authorization flow and prints the verification URL and
@@ -30,9 +32,12 @@ application credentials and creates a new `appKey` + `apiSecret`. The public
30
32
  app key and the backend-only secret are printed after success. The secret is
31
33
  not stored by the CLI and cannot be retrieved again.
32
34
 
33
- `agent setup --agent codex` installs the bundled `requestshield` skill into
34
- `$CODEX_HOME/skills`, or `~/.codex/skills` when `CODEX_HOME` is unset. Existing
35
- content is preserved unless `--force` is supplied.
35
+ `agent setup` detects Codex or Claude and installs the bundled `requestshield`
36
+ skill into `~/.agents/skills` for Codex or `~/.claude/skills` for Claude. Use
37
+ `--codex` or `--claude` to select one directly. When both agents are detected,
38
+ an interactive terminal asks which one to use; non-interactive callers must
39
+ provide one of the flags. Existing content is preserved unless `--force` is
40
+ supplied.
36
41
 
37
42
  ## Management API contract
38
43
 
@@ -80,7 +85,9 @@ Run without installing globally:
80
85
  npx requestshield --help
81
86
  npx requestshield signin
82
87
  npx requestshield keys create
83
- npx requestshield agent setup --agent codex
88
+ npx requestshield agent setup
89
+ npx requestshield agent setup --codex
90
+ npx requestshield agent setup --claude
84
91
  ```
85
92
 
86
93
  Pin a specific version for reproducible usage:
@@ -89,6 +96,30 @@ Pin a specific version for reproducible usage:
89
96
  npx requestshield@0.1.0 --help
90
97
  ```
91
98
 
99
+ ## Packaging the bundled skill
100
+
101
+ The canonical RequestShield skill lives at `../skills/requestshield`, outside
102
+ this npm package directory. The `prepack` hook temporarily copies the complete
103
+ skill into `skills/requestshield`, and `postpack` removes that generated copy
104
+ after npm creates the tarball. Do not edit the generated copy.
105
+
106
+ Build and inspect a local package from this directory:
107
+
108
+ ```console
109
+ npm test
110
+ npm run typecheck
111
+ npm run lint
112
+ npm pack --dry-run
113
+ ```
114
+
115
+ To exercise the package entry point and bundled skill, create a tarball and run
116
+ the command through that tarball:
117
+
118
+ ```console
119
+ npm pack
120
+ npx --yes --package=./requestshield-0.1.0.tgz requestshield agent setup --codex
121
+ ```
122
+
92
123
  To automatically accept npm's installation prompt:
93
124
 
94
125
  ```console
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "requestshield",
3
- "version": "0.1.0",
3
+ "version": "0.1.3",
4
4
  "description": "Customer CLI for IntelliFend RequestShield.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -19,6 +19,8 @@
19
19
  "lint": "node scripts/check-package.mjs",
20
20
  "test": "node --test",
21
21
  "typecheck": "tsc -p jsconfig.json --noEmit",
22
+ "prepack": "node scripts/package-skill.mjs stage",
23
+ "postpack": "node scripts/package-skill.mjs clean",
22
24
  "prepublishOnly": "npm run lint && npm run typecheck && npm test"
23
25
  },
24
26
  "devDependencies": {
@@ -1,44 +1,307 @@
1
1
  ---
2
2
  name: requestshield
3
- description: Set up or remove IntelliFend RequestShield protection in a customer application using the repository's Browser SDK and supported backend SDK. Use when the user asks an AI agent to integrate, configure, validate, or remove RequestShield protection.
3
+ description: Install, verify, troubleshoot, or remove IntelliFend RequestShield bot protection in a customer codebase the browser SDK in Seamless or Manual mode, plus Java backend enforcement via the Spring Boot 3 starter or the Java core SDK — driving the `requestshield` CLI for sign-in, app keys, the integration contract, and traffic checks. Use this skill whenever the user mentions RequestShield, IntelliFend, `X-IntelliFend-Token`, `IntelliFend.getToken()`, `data-protect`, `@RequestShieldProtected`, App Key or API Secret setup, or asks to protect an endpoint such as registration, sign-in, password reset, checkout, or form submission from bots, scripted abuse, or credential stuffing — even when they never name the product. Also use it before hand-editing any file that already contains a RequestShield script tag, `verify()` call, or protection annotation.
4
4
  ---
5
5
 
6
- # RequestShield Integration
7
-
8
- Work only inside the customer's application repository. Do not access or modify
9
- IntelliFend operator infrastructure, Cloudflare resources, or customer records.
10
-
11
- Before editing, identify the frontend and backend frameworks and inspect the
12
- relevant dependency and configuration files. Explain the files that will change.
13
- Do not place the backend Secret Key in source, browser configuration, URLs, logs,
14
- or committed files. The public App Key may be included in browser configuration.
15
-
16
- ## Set up protection
17
-
18
- 1. Obtain the public App Key, backend-only Secret Key, and Challenge Server URL
19
- from the customer. If the Secret Key is unavailable, stop and ask the user to
20
- put it in their backend secret manager; never ask them to paste it into chat.
21
- 2. Configure the Browser SDK with the App Key, Challenge Server URL, and exact
22
- protected endpoint URLs. Query strings and fragments do not participate in
23
- matching; path case and trailing slash do.
24
- 3. Configure the supported backend SDK with the same App Key and a secret-store
25
- reference for the Secret Key. For Spring Boot 3 MVC, protect the actual
26
- mutation method with `@RequestShieldProtected`.
27
- 4. For a new endpoint, start in `MONITOR`; move to `BLOCK` only after verifying
28
- browser matching, backend outcomes, and CORS. Cross-origin customer APIs must
29
- allow `X-IntelliFend-Token`.
30
- 5. Run the project's normal lint, build, and tests. Report any manual secret or
31
- deployment step without performing external deployment unless requested.
32
-
33
- Do not combine a manual `RequestShieldClient.verify(token)` call with annotation
34
- enforcement on the same request: the token is single-use and would be consumed
35
- twice.
36
-
37
- ## Remove protection
38
-
39
- Remove only RequestShield-owned integration: browser initialization/protected
40
- URL entries, backend annotation/configuration, and dependencies that have no
41
- remaining callers. Preserve unrelated CORS, environment, build, and application
42
- configuration. Never delete or rotate remote keys as part of source removal.
43
- Run the project's normal validation after the change.
6
+ # RequestShield integration
44
7
 
8
+ Every RequestShield integration has two halves, and the split is the thing to
9
+ understand before writing any code:
10
+
11
+ 1. **The browser** obtains a short-lived token and transports it with the protected
12
+ request, as the `X-IntelliFend-Token` header.
13
+ 2. **The backend** evaluates that token and enforces the decision before the protected
14
+ operation runs.
15
+
16
+ The browser half is a *transport*, never a gate. A page that obtains tokens whose
17
+ backend never verifies them has zero protection while looking fully integrated — the
18
+ most common way this integration silently fails. Equally, an annotation on a handler
19
+ creates no browser configuration. **Browser configuration and backend protection are
20
+ configured independently, and neither one implies the other.** Land both halves in the
21
+ same change and verify both.
22
+
23
+ Protect the operation that performs the business mutation — registration, sign-in,
24
+ password reset, checkout, form submission — not a read-only route in front of it.
25
+
26
+ ## Before touching integration files
27
+
28
+ ```bash
29
+ requestshield --version # is the CLI present?
30
+ requestshield auth status # {"authenticated":true,...} — most commands need this
31
+ ```
32
+
33
+
34
+ If `requestshield --version` fails, the CLI is not installed. **Stop and say so.** Ask
35
+ the user to install it; do not substitute hand-crafted HTTP calls, and do not fall back
36
+ to the example values in this skill — the contract is the only authoritative source for
37
+ the script URL, header name, and released modes, and a guessed script URL produces a
38
+ page that silently loads nothing.
39
+
40
+ If `auth status` shows the user signed out, ask them to run `requestshield signin`
41
+ themselves — it is interactive. Never script around it or ask for credentials.
42
+
43
+ Those commands are the preflight for integration-changing work. For read-only CLI
44
+ questions, go to **Classify the request** and run only the matching command.
45
+
46
+ ## Classify the request
47
+
48
+ Only **Install** and **Uninstall** are step-locked sequences. Every other intent is a
49
+ single CLI call or a short answer. Match on what the user wants, not on exact wording.
50
+
51
+ | Intent | Sounds like | Do this |
52
+ | --- | --- | --- |
53
+ | **General info** | "what version", "is there a newer CLI", "am I up to date" | `requestshield --version`, then `requestshield update check`. Report both and the gap between them. No credentials check, no repo scan. |
54
+ | **Authentication** | "sign me in", or preflight `auth status` came back unauthenticated | Ask the user to run `requestshield signin` in their own terminal, and wait. It is interactive — never automate it, never run it for them, never ask for credentials. Re-run `auth status` once they confirm. |
55
+ | **Key / secret management** | "create an app key", "I need an API Secret", "rotate the secret", "deactivate a key" | **Hand the command over; do not run it.** → "Key and secret management" below. |
56
+ | **Install** | "add RequestShield", "protect /api/register" | `references/integration-planning.md` full flow → **Installing** → **Verifying** → **Negative test**. Do not reorder or skip a step. |
57
+ | **Uninstall** | "remove it", "roll it back" | `references/integration-planning.md` (Detect existing integration only) → **Uninstalling**. |
58
+ | **Verify / troubleshoot** | "is it set up right?", "why is it not blocking?", a reason code | `references/integration-planning.md` (Detect existing integration only) → **Verifying**. For a reason code, also read `references/troubleshooting.md`. |
59
+ | **Challenge volume** | "how much traffic", "how many challenges", "show me the volume" | Ask for the time range first. `challenge volume` takes `--from`/`--to`/`--granularity`; a guessed window produces a confident wrong answer. Then run it with the App Key. |
60
+ | **Billing** | "am I being charged", "what plan", "what are my limits" | `requestshield get billing`. |
61
+ | **Service health** | "is the service up", "is it degraded" | `requestshield server`. |
62
+ | **Agent setup** | "set this up for Codex too", "install the skill for Claude" | Run `requestshield agent setup` for auto-detection, or pass the requested agent: `--agent codex` or `--agent claude`. This installs agent guidance; it does not mint keys or edit customer application code. |
63
+ | **Anything else** | | Look the command up in `references/cli.md`. If it is not there, run `requestshield --help` rather than guessing at a flag. |
64
+
65
+ Full CLI surface, output shapes, and which commands need auth: `references/cli.md`.
66
+
67
+
68
+ For Install, `references/integration-planning.md` owns the full planning sequence:
69
+ Credentials check, Detect existing integration, Contract check, Gate, Then act on what
70
+ you found, and Choosing the mode. Keep the browser-mode and backend-path decisions
71
+ independent.
72
+
73
+ ## Key and secret management
74
+
75
+ `keys create`, `app key rotate`, and `keys deactive` are the one place you do **not**
76
+ drive the CLI. Two independent reasons, and each is sufficient on its own:
77
+
78
+ - `keys create` and `app key rotate` print the API Secret to stdout exactly once. A
79
+ command you run puts that value in your tool output and transcript.
80
+ - `keys deactive` and `app key rotate` change state for a live App Key. Deactivating the
81
+ wrong one stops verifying real traffic.
82
+
83
+ So hand it over. Tell the user which command to run in their own terminal:
84
+
85
+ ```bash
86
+ requestshield keys create --app-name <name> # new App Key + API Secret pair
87
+ requestshield app key rotate --app-key <app-key> # new secret, App Key unchanged
88
+ requestshield keys deactive --app-key <app-key> # stops verification for that key
89
+ ```
90
+
91
+ Warn them **before** they run secret creation or rotation that the secret appears once
92
+ and they need somewhere to put it. Afterwards, confirm by presence only and use
93
+ `requestshield credentials status <app-key>` for the server-side view. Never ask the
94
+ user to paste the secret back, and never read it out of a file or the environment.
95
+
96
+ A lost or exposed secret cannot be re-displayed. The fix is `app key rotate`, run by
97
+ the user. Deleting a leaked value from a repo, log, artifact, or transcript does not
98
+ un-expose it.
99
+
100
+ ## Installing
101
+
102
+ For Install, run the full planning flow in `references/integration-planning.md` before
103
+ writing integration code: **Credentials check** → **Detect existing integration** →
104
+ **Contract check** → **Gate** → **Then act on what you found** → **Choosing the mode**.
105
+ It must settle the App Key, the existing-integration state, the contract values, the
106
+ backend path, and the browser mode before step 1 below.
107
+
108
+ 1. **Browser side** — add the hosted script once in `<head>`, using the `script_url`
109
+ from `requestshield contract`, then follow the chosen browser reference:
110
+ - Seamless → `references/browser-seamless.md`
111
+ - Manual → `references/browser-manual.md`
112
+ 2. **Backend side** — add the dependency, configure `app-key` and `api-secret` from
113
+ environment variables, and enforce the decision before the mutation:
114
+ - Spring Boot 3 starter → `references/backend-spring-boot.md`
115
+ - Java core SDK → `references/backend-java-core.md`
116
+ 3. **Cross-origin API**, if the protected endpoint is on another origin — its CORS
117
+ response must allow the page origin, intended methods, and `X-IntelliFend-Token`.
118
+ 4. **CSP**, if the app sends one — merge, never replace. See
119
+ `references/browser-manual.md`.
120
+ 5. **Verify** — run the checklist below, then the negative test when safe.
121
+
122
+ ## Handling the App Key and API Secret
123
+
124
+ These two values have opposite handling rules:
125
+
126
+ - **App Key** is public. It belongs in the browser script tag and backend configuration.
127
+ The same value must appear on both sides or every token fails.
128
+ - **API Secret** is backend-only. It must reach the backend through an environment
129
+ variable or secret manager. Never write it into a source file, a committed `.env`, an
130
+ image layer, a CI config in the repo, or the chat transcript — and never echo it back
131
+ after reading it.
132
+
133
+ You never run the commands that display the API Secret, and you never read it back. The
134
+ hand-off and warning are in **Key and secret management** above. Afterwards refer to it
135
+ only as "the secret you just received".
136
+
137
+ If a secret has already reached a repo, a log, an artifact, or this transcript, the fix
138
+ is `requestshield app key rotate --app-key <app-key>`, run by the user.
139
+
140
+ ## Verifying
141
+
142
+ For standalone Verify / Troubleshoot, first run **Detect existing integration only** in
143
+ `references/integration-planning.md`. You are observing which browser mode and backend
144
+ path are in use, not choosing them — **Credentials check**, **Contract check**,
145
+ **Gate**, and **Choosing the mode** belong to the Install flow unless troubleshooting
146
+ evidence specifically points to a credential failure or an unreleased mode.
147
+
148
+ Then the static checks. They are deterministic and catch most real breakage.
149
+
150
+ - Exactly **one** SDK script tag, in `<head>`, loaded before any bundle that can issue a
151
+ protected request, with a real `data-app-key`.
152
+ - Seamless: every protected endpoint appears in `data-protect`, spelled as the exact
153
+ origin and pathname the browser actually requests — case and trailing slash included.
154
+ - Manual: every protected call site obtains a fresh token immediately before the request
155
+ and attaches it, including retry paths.
156
+ - Neither mode applied twice to the same operation.
157
+ - Backend: the dependency resolves, the App Key matches the browser's, the secret comes
158
+ from the environment, and the decision gates the mutation rather than only being
159
+ logged. Exactly one verification path per request.
160
+ - Cross-origin endpoints: CORS allows `X-IntelliFend-Token`.
161
+ - No token or secret in logs, analytics, URLs, or error reporting.
162
+
163
+ Structural correctness is not proof of enforcement. For runtime evidence, exercise the
164
+ endpoint and confirm the platform saw the traffic:
165
+
166
+ ```bash
167
+ requestshield challenge volume <app-key> \
168
+ --from <start> \
169
+ --to <end> \
170
+ --granularity hour
171
+ ```
172
+
173
+ Report static correctness and platform traffic separately. A flat zero after real
174
+ traffic means the browser half is not firing; go back to the selected browser reference
175
+ before changing backend code.
176
+
177
+ ### The negative test — the only proof of enforcement
178
+
179
+ Neither static checks nor `challenge volume` can prove the backend refuses a tokenless
180
+ mutation. The proof is a request the backend should reject.
181
+
182
+ Before running it, establish:
183
+
184
+ 1. `requestshield server` is healthy. This reports platform health only; it does not prove
185
+ that the backend under test can reach the Challenge Server or that its local circuit
186
+ has closed. A healthy platform can still produce a degraded result at that backend.
187
+ 2. The endpoint's effective mode is `BLOCK`, not `MONITOR`. Include any method-level
188
+ override when resolving the effective mode. `MONITOR` allows every request by design.
189
+ 3. A valid control request is available. Its authentication, session, CSRF state, route,
190
+ method, and body must remain valid during the comparison.
191
+ 4. Establish a way to observe degradation for the backend instance and App Key under
192
+ test. For the Spring Boot starter, use the `intellifend.requestshield.requests` metric and distinguish
193
+ `outcome=allowed, reason=ok` from `outcome=degraded, reason=service_unavailable`. For
194
+ the Java core SDK, use existing safe metrics or logs derived from `isDegraded()` and
195
+ `getReason().getCode()`. Never log the raw token, API Secret, session, or CSRF value.
196
+
197
+ **Confirm with the user before running this anywhere shared.** It exercises a real
198
+ mutation, so use a local or staging environment, or an endpoint whose write can be
199
+ undone. Do not fire it at production to "just check", and do not invent a body that
200
+ could create a real account.
201
+
202
+ First, send the control request through the normal integrated path with a fresh
203
+ RequestShield token. Confirm that it succeeds, reaches the intended mutation, and records
204
+ a non-degraded `ok` decision at the backend. A successful response produced by degraded
205
+ fail-open is not a valid control. Use a new token for every control attempt because
206
+ RequestShield tokens are single-use.
207
+
208
+ Then repeat the same request while preserving its valid authentication, session, CSRF
209
+ state, route, method, body, and other relevant headers. Remove only
210
+ `X-IntelliFend-Token`. Send it through a client that bypasses the Browser SDK so Seamless
211
+ mode cannot attach another token:
212
+
213
+ ```bash
214
+ curl -i -X POST https://<host>/api/register \
215
+ -H '<the same valid authentication and CSRF context>' \
216
+ -H 'Content-Type: application/json' \
217
+ -d '{ ...the same valid test body... }'
218
+ ```
219
+
220
+ Attribute the result to RequestShield rather than treating every 4xx as a pass.
221
+ Authentication, authorization, CSRF, and request validation can independently return a
222
+ 401, 403, or 400 before the protected mutation.
223
+
224
+ - **Spring Boot 3 starter:** pass only when the response is HTTP 403 with
225
+ `CHALLENGE_FAILED` and reason `missing_token`, and the handler produced no side effect.
226
+ - **Java core SDK:** read the handler before testing. Confirm that its
227
+ `!result.isAllowed()` branch rejects before the mutation, then verify that the
228
+ observed rejection corresponds to RequestShield's `missing_token` decision and
229
+ produced no side effect.
230
+ - **Any unrelated or unattributable 4xx:** inconclusive, not a pass. Fix the control
231
+ request or add safe RequestShield-specific observability before drawing a conclusion.
232
+ - **Any backend-specific degraded evidence, including `service_unavailable`:**
233
+ inconclusive. The SDK intentionally allows the request under its availability policy;
234
+ restore the backend's Challenge Server connectivity, wait for its circuit to recover,
235
+ and repeat with a new control token.
236
+
237
+ A `2xx`, or evidence that the mutation happened, is a confirmed missing-token
238
+ enforcement bypass only when backend-specific degradation has been ruled out for that
239
+ request. If backend-specific degradation evidence is absent or cannot be checked,
240
+ report the test as inconclusive—not as proof that enforcement is absent. When degradation
241
+ is ruled out, treat the bypass as the finding and go to `references/troubleshooting.md`.
242
+
243
+ ## Uninstalling
244
+
245
+ Run `references/integration-planning.md` Detect existing integration only before this
246
+ section. Remove only what RequestShield introduced, and confirm the list with the user
247
+ first:
248
+
249
+ 1. The script tag, including `data-protect` and any other RequestShield attributes.
250
+ 2. Manual-mode `getToken()` calls and the header lines they feed — leave the surrounding
251
+ request intact.
252
+ 3. The backend dependency, client configuration, and the enforcement: `verify()` calls
253
+ or `@RequestShieldProtected` annotations.
254
+ 4. RequestShield entries in the CSP header and in CORS allowed headers — leave every
255
+ other source and header in place.
256
+ 5. Configuration keys and environment variable references.
257
+
258
+ Then ask whether to also deactivate the keys server-side:
259
+ `requestshield keys deactive --app-key <app-key>`. That is not reversible the way a
260
+ code edit is, so it stays the user's explicit call.
261
+
262
+ ## Non-negotiables
263
+
264
+ These separate an integration that protects traffic from one that only looks like it:
265
+
266
+ - **Enforcement lives in the backend.** Application code in the browser must never
267
+ decide to allow, block, retry around, or interpret a token.
268
+ - **Browser configuration and backend protection are independent.** Neither implies the
269
+ other.
270
+ - **One browser mode and one backend path are selected independently.** Seamless is not
271
+ Spring Boot, and Manual is not Java core. Either browser mode may pair with either
272
+ supported backend path.
273
+ - **One token per protected request; a new token before every retry.** Tokens are
274
+ single-use; replaying one returns `token_replayed` and blocks the request.
275
+ - **One verification per request.** Never combine `@RequestShieldProtected` with a
276
+ manual `RequestShieldClient.verify()` on the same handler.
277
+ - **Forward a non-empty token unchanged.** Do not trim, re-encode, inspect, cache,
278
+ persist, log, or place it in a URL.
279
+ - When `getToken()` returns an empty string in Manual mode, omit the header and let the
280
+ backend apply its configured policy.
281
+ - **The API Secret stays at the backend.** Never put it in browser code,
282
+ client-visible responses, source control, logs, build artifacts, or chat transcripts.
283
+ - **You never run a command that mints, rotates, or deactivates a key.** Hand those
284
+ commands to the user and verify by presence only.
285
+
286
+ ## Reference files
287
+
288
+ | File | Read it when |
289
+ | --- | --- |
290
+ | `references/cli.md` | Any CLI invocation — exact syntax, output shape, auth requirements |
291
+ | `references/integration-planning.md` | Credentials check, existing-integration detection, the contract check, backend gating (Java version, Spring Boot 3 MVC vs WebFlux, other frameworks), and browser-mode selection |
292
+ | `references/browser-manual.md` | Installing or auditing Manual mode; CSP rules |
293
+ | `references/browser-seamless.md` | Installing or auditing Seamless mode; matching and coverage limits |
294
+ | `references/backend-spring-boot.md` | Backend work on Spring Boot 3 MVC — the annotation path |
295
+ | `references/backend-java-core.md` | Backend work on any other Java 17 backend — the `verify()` path |
296
+ | `references/troubleshooting.md` | A block, a degraded result, or a reason code to explain |
297
+
298
+ ## For agent setup
299
+
300
+ `requestshield agent setup` installs this skill for the detected or requested agent.
301
+ Use `--agent codex` or `--agent claude` when the user names the target agent. For Codex
302
+ repositories that also use `AGENTS.md`, the CLI can write the managed block from
303
+ `assets/AGENTS.codex.md` so repo-local guidance points back to the installed skill and
304
+ the same reference files.
305
+
306
+ Agent setup installs guidance only. It does not mint keys, rotate secrets, deactivate
307
+ keys, or edit customer application code.
@@ -0,0 +1,62 @@
1
+ <!-- requestshield:begin — managed by `requestshield agent setup --agent codex`. Edit the skill source, not this block. -->
2
+ ## RequestShield integration
3
+
4
+ This repository uses IntelliFend RequestShield to protect selected operations from
5
+ automated abuse. Before installing, verifying, changing, or removing that protection —
6
+ and before hand-editing any file that already contains a RequestShield script tag,
7
+ `data-protect`, `X-IntelliFend-Token`, `IntelliFend.getToken()`, `verify()`, or
8
+ `@RequestShieldProtected` — read `.requestshield/skill/SKILL.md` and follow it.
9
+
10
+ The procedure exists because the failure mode here is silent. Every integration has two
11
+ halves: the browser obtains and transports a token, and the backend evaluates it before
12
+ the protected operation. They are configured **independently and neither implies the
13
+ other** — a page that obtains tokens whose backend never verifies them has zero
14
+ protection and looks fully integrated, and an annotated handler creates no browser
15
+ configuration.
16
+
17
+ The backend path is decided by the backend stack, not by browser preference: the
18
+ **Spring Boot 3 starter** needs Spring Boot 3 with Spring MVC and Java 17+, while the
19
+ **Java core SDK** needs Java 17+. The browser mode is a separate transport choice:
20
+ Seamless needs a released Seamless mode and a protected request sent by `fetch` or
21
+ asynchronous XHR; Manual is for explicit token timing or other supported carriers.
22
+ Check both halves before proposing edits — finding a backend blocker afterwards leaves
23
+ tokens flowing with nothing enforcing them. Java below 17 blocks both backend paths.
24
+
25
+ Orientation:
26
+
27
+ - `.requestshield/skill/SKILL.md` — the procedure. Start here.
28
+ - `.requestshield/skill/references/integration-planning.md` — the planning flow:
29
+ credentials check, detecting an existing integration, gating on the backend stack
30
+ (Java version, Spring MVC vs WebFlux, other frameworks), and choosing the browser mode.
31
+ Read it before any install, verify, or uninstall.
32
+ - `.requestshield/skill/references/cli.md` — the `requestshield` CLI; every platform
33
+ action (sign-in, keys, contract, traffic checks) goes through it.
34
+ - `.requestshield/skill/references/browser-seamless.md` — Seamless mode: exact-endpoint
35
+ matching, and the transports it does not cover.
36
+ - `.requestshield/skill/references/browser-manual.md` — Manual mode, carriers, CORS, CSP.
37
+ - `.requestshield/skill/references/backend-spring-boot.md` — enforcement on Spring Boot 3
38
+ MVC: the `@RequestShieldProtected` annotation path.
39
+ - `.requestshield/skill/references/backend-java-core.md` — enforcement on any other
40
+ Java 17 backend: the `verify()` path.
41
+ - `.requestshield/skill/references/troubleshooting.md` — reason codes and diagnosis.
42
+
43
+ Five rules worth carrying without opening a file:
44
+
45
+ - The **API Secret** never enters source control, logs, or a reply. It belongs in backend
46
+ runtime secret storage, and `requestshield app key rotate` is the fix if it leaks. The
47
+ **App Key** is public and must be identical in browser and backend.
48
+ - **Never run `keys create`, `app key rotate`, or `keys deactive` yourself.** They print
49
+ the secret or change state for a live key. Hand the command to the user, have them
50
+ export `INTELLIFEND_REQUESTSHIELD_APP_KEY` and
51
+ `INTELLIFEND_REQUESTSHIELD_API_SECRET`, and confirm by presence only.
52
+ - Every protected request needs its **own token, verified exactly once**. Reuse or a
53
+ second verification path returns `token_replayed` and blocks a legitimate request.
54
+ - **Enforcement lives in the backend.** Never put allow/block/retry logic in the browser,
55
+ and never build a decision table from reason codes in application code.
56
+ - In Manual mode, attach `X-IntelliFend-Token` **only when `getToken()` returns a
57
+ non-empty string**; when it is empty, omit the header and let the backend apply its
58
+ configured policy.
59
+
60
+ Run `requestshield contract` before writing integration code — it is authoritative for
61
+ the script URL, header name, released modes, and backend baseline.
62
+ <!-- requestshield:end -->
@@ -0,0 +1,128 @@
1
+ # Backend SDK — Java core SDK
2
+
3
+ The backend is where protection actually happens. Everything the browser does is
4
+ transport to deliver a token here; this file is where the request is allowed or refused.
5
+
6
+ This is one of two backend paths. It is framework-neutral: the SDK returns a decision and
7
+ **the application enforces it**. The other path is the declarative Spring Boot 3 starter
8
+ → `backend-spring-boot.md`; prefer that one when the stack allows it, because it removes
9
+ the enforcement code below and the mistakes that come with it.
10
+
11
+ **Requires Java 17 or newer** — nothing else. So this is the path for every backend that
12
+ is not Spring Boot 3 MVC, including a Spring Boot 3 app built on WebFlux, which is not
13
+ Spring MVC. Also needed: the same App Key the browser uses, the backend-only API Secret,
14
+ and a web framework that can extract the token carrier.
15
+
16
+ Confirm the baseline and supported languages with `requestshield contract` first. If the
17
+ customer's backend language is not listed, the honest answer is that the integration is
18
+ not supported yet, because a browser-only install protects nothing.
19
+
20
+ The browser mode does not decide this path. Either Seamless or Manual mode delivers the
21
+ token, and the application extracts it and passes the value unchanged to `verify()`.
22
+
23
+ Use exactly **one** verification path per request. A RequestShield token is used once, so
24
+ a handler already covered by `@RequestShieldProtected` must not also call `verify()`.
25
+
26
+ ## 1. Dependency
27
+
28
+ ```xml title="pom.xml"
29
+ <repositories>
30
+ <repository>
31
+ <id>intellifend-maven</id>
32
+ <url>https://sdk.intellifend.com/packages/maven</url>
33
+ </repository>
34
+ </repositories>
35
+
36
+ <dependency>
37
+ <groupId>com.intellifend.requestshield</groupId>
38
+ <artifactId>requestshield-backend-sdk</artifactId>
39
+ <version>2.0.0</version>
40
+ </dependency>
41
+ ```
42
+
43
+ ## 2. One reusable client
44
+
45
+ ```java
46
+ RequestShieldClient requestShield = RequestShieldClient.builder()
47
+ .appKey(appKey)
48
+ .apiSecret(apiSecret)
49
+ .build();
50
+ ```
51
+
52
+ One client per App Key, reused across requests, rather than one per request. Keep the
53
+ API secret in backend runtime secret storage.
54
+
55
+ Bind the secret with no fallback default. A backend that starts with a placeholder
56
+ secret rejects every real token, which surfaces days later as "RequestShield is blocking
57
+ all our users" — a startup failure is far cheaper to diagnose than that.
58
+
59
+ ## 3. Verify before the protected operation
60
+
61
+ ```java
62
+ String token = request.getHeader("X-IntelliFend-Token");
63
+ VerificationResult result = requestShield.verify(token);
64
+
65
+ if (!result.isAllowed()) {
66
+ rejectRequest(result.getReason().getCode());
67
+ return;
68
+ }
69
+
70
+ continueProtectedOperation();
71
+ ```
72
+
73
+ Pass the extracted value unchanged. Do not trim, decode, or pre-validate the shape;
74
+ `verify()` owns that, and pre-parsing only adds a way to reject a valid token.If the
75
+ header is absent, `null`, or empty, pass that value to `verify()` as-is. Do not add a
76
+ separate decision based on token presence.
77
+
78
+ Always enforce `isAllowed()`. Use `getReason().getCode()` for controlled diagnostics or
79
+ a sanitized response contract only — **do not build a separate decision table in
80
+ application code.** Reason codes explain a decision; they do not amend it, and an
81
+ override that allows a blocked reason quietly removes the protection.
82
+
83
+ If the application contract carries the token in a request-body field instead of the
84
+ header, extract that field before verification; everything after that is identical.
85
+
86
+ ## 4. Validate the request path
87
+
88
+ 1. Browser and backend use the same App Key.
89
+ 2. A token reaches the backend unchanged.
90
+ 3. The protected operation runs only after `isAllowed()` is checked.
91
+ 4. A new browser token is obtained before each application retry.
92
+ 5. Tokens and the API secret are excluded from logs.
93
+
94
+ ## VerificationResult
95
+
96
+ | Method | Returns | Use |
97
+ | --- | --- | --- |
98
+ | `isAllowed()` | `boolean` | The decision to enforce. Never override it based on a reason code. |
99
+ | `getReason()` | `VerificationReason` | Stable reason; `getReason().getCode()` is safe to log and chart. |
100
+ | `isDegraded()` | `boolean` | The decision was made under a platform availability failure rather than from a real token. |
101
+
102
+ `isDegraded()` deserves attention on first integration. Confirm the exact behaviour in
103
+ the customer documentation before relying on it, and tell the user which behaviour you
104
+ assumed. The documented intent is that a degraded result reflects a platform
105
+ availability failure rather than a real token decision — so a degraded result is not
106
+ evidence that a token was valid. Log the degraded count as its own metric; a persistent nonzero rate is an
107
+ infrastructure signal, not a bot signal.
108
+
109
+ Reason codes and what each means for debugging: `troubleshooting.md`.
110
+
111
+ ## Align the browser side
112
+
113
+ Configure exactly one browser mode for the same operation — Seamless
114
+ (`browser-seamless.md`) or Manual (`browser-manual.md`). Browser configuration does not
115
+ create backend protection, and a `verify()` call does not create browser configuration.
116
+ Land both halves in the same change. For a cross-origin API, configure CORS to allow the
117
+ token header.
118
+
119
+ ## Security requirements
120
+
121
+ - The API Secret lives in backend runtime secret storage only — never in source, a
122
+ committed `.env`, an image layer, a client-visible response, or a log line.
123
+ - The App Key must be identical in browser and backend, or every token fails.
124
+ - One token per protected request, verified exactly once.
125
+ - Never log or persist raw tokens, decoded claims, or the secret. Reason codes exist so
126
+ diagnostics need none of that.
127
+ - Enforce the decision before the business mutation, not after — verification that runs
128
+ after the order is written is an audit log, not protection.