Skip to content

Feature/msg signing on refactor#8

Open
adriantuk wants to merge 16 commits intomainfrom
feature/msg_signing_onRefactor
Open

Feature/msg signing on refactor#8
adriantuk wants to merge 16 commits intomainfrom
feature/msg_signing_onRefactor

Conversation

@adriantuk
Copy link
Copy Markdown

This PR includes @KMilej backend quickstart refactoring that combines all logic into one easy-to-understand file, instead of three separate servers. He also improved the documentation to be easier to understand. I've added comments throughout the codebase and additional logging that, in my opinion, improve the debugging experience and will help users get a better understanding of how it works, or what's going wrong in case of issues. I've also implemented HTTP message signing by vendoring a ready repository and hooking it up to Approov logic. This ends up with a new endpoint specifically to verify token and message signature.

Work still might be added to this PR, but I'm creating it for visibility.

@adriantuk adriantuk added the enhancement New feature or request label Feb 4, 2026
@adriantuk adriantuk self-assigned this Feb 4, 2026
@adriantuk adriantuk requested a review from Copilot February 4, 2026 15:40
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors the Node.js backend quickstart by consolidating three separate servers into a single, unified application and adds HTTP message signing verification using the RFC 9421 standard.

Changes:

  • Consolidated unprotected, token-check, and token-binding servers into one application (ApproovApplication.js)
  • Implemented HTTP message signing verification with support for both install and account signing modes
  • Added comprehensive testing scripts (test.sh, test-message-signing.sh) with automated test harness
  • Improved documentation and deployment process with Docker-based build system

Reviewed changes

Copilot reviewed 29 out of 98 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
test.sh Automated test harness for Approov token verification scenarios
test-message-signing.sh Test suite for HTTP message signing validation
ApproovApplication.js Unified server implementation with token and signature verification
README.md Comprehensive quickstart guide with examples
package.json Root package configuration
.env.example Environment variable template
Dockerfile Simplified container build configuration
scripts/build.sh Docker orchestration script
scripts/install-prerequisites.sh Dependency installation script
run-server.sh Server startup wrapper
Files not reviewed (3)
  • src/approov-protected-server/token-binding-check/package-lock.json: Language not supported
  • src/approov-protected-server/token-check/package-lock.json: Language not supported
  • src/unprotected-server/package-lock.json: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread test.sh
Comment on lines +223 to +232
state_response="$(curl -i -s "${BASE_URL}/approov-state")"
state_http_code="$(
printf '%s\n' "${state_response}" |
grep -m1 '^HTTP/' |
awk '{print $2}'
)"

if [[ "${state_http_code}" != "200" || -z "${state_http_code}" ]]; then
err "Failed to get Approov state from ${BASE_URL}/approov-state (status=${state_http_code:-unknown})"
exit 1
Copy link

Copilot AI Feb 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error message should be more specific about what went wrong. Consider including details about whether it was a connection failure, unexpected status code, or empty response.

Suggested change
state_response="$(curl -i -s "${BASE_URL}/approov-state")"
state_http_code="$(
printf '%s\n' "${state_response}" |
grep -m1 '^HTTP/' |
awk '{print $2}'
)"
if [[ "${state_http_code}" != "200" || -z "${state_http_code}" ]]; then
err "Failed to get Approov state from ${BASE_URL}/approov-state (status=${state_http_code:-unknown})"
exit 1
local curl_exit
state_response="$(curl -i -s "${BASE_URL}/approov-state")"
curl_exit=$?
state_http_code="$(
printf '%s\n' "${state_response}" |
grep -m1 '^HTTP/' |
awk '{print $2}'
)"
if [[ "${curl_exit}" -ne 0 ]]; then
err "Failed to connect to ${BASE_URL}/approov-state (curl exit code=${curl_exit})"
exit 1
elif [[ -z "${state_http_code}" ]]; then
err "Received empty or malformed HTTP response from ${BASE_URL}/approov-state"
exit 1
elif [[ "${state_http_code}" != "200" ]]; then
err "Unexpected HTTP status from ${BASE_URL}/approov-state (status=${state_http_code}, expected=200)"
exit 1

Copilot uses AI. Check for mistakes.
Comment thread test-message-signing.sh
exit 1
fi

if [[ -n "${APPROOV_ACCOUNT_MESSAGE_SIGNING_SECRET_BASE64URL:-}" || -n "${APPROOV_ACCOUNT_MESSAGE_SIGNING_SECRET_BASE64:-}" || -n "${APPROOV_ACCOUNT_MESSAGE_SIGNING_SECRET_RAW:-}" || -n "${APPROOV_ACCOUNT_MESSAGE_SIGNING_KEY_ID:-}" ]]; then
Copy link

Copilot AI Feb 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line is excessively long (over 200 characters) and difficult to read. Consider splitting the condition checks into multiple lines or storing intermediate results in variables.

Suggested change
if [[ -n "${APPROOV_ACCOUNT_MESSAGE_SIGNING_SECRET_BASE64URL:-}" || -n "${APPROOV_ACCOUNT_MESSAGE_SIGNING_SECRET_BASE64:-}" || -n "${APPROOV_ACCOUNT_MESSAGE_SIGNING_SECRET_RAW:-}" || -n "${APPROOV_ACCOUNT_MESSAGE_SIGNING_KEY_ID:-}" ]]; then
if [[ -n "${APPROOV_ACCOUNT_MESSAGE_SIGNING_SECRET_BASE64URL:-}" || \
-n "${APPROOV_ACCOUNT_MESSAGE_SIGNING_SECRET_BASE64:-}" || \
-n "${APPROOV_ACCOUNT_MESSAGE_SIGNING_SECRET_RAW:-}" || \
-n "${APPROOV_ACCOUNT_MESSAGE_SIGNING_KEY_ID:-}" ]]; then

Copilot uses AI. Check for mistakes.
Comment thread README.md
- `/token-binding` - requires a valid Approov token which is bound to a header value.
- `/token-double-binding` - requires a valid Approov token which is bound to two header values.

In this example, Approov protection is enforced by [approovTokenVerifier](https://github.com/approov/quickstart-nodejs-token-check/blob/refactor/nodejs-quickstart/ApproovApplication.js#L199-L235), which reads the `Approov-Token` header, and validates the token `signature` and `exp` claim in [verifyApproovToken](https://github.com/approov/quickstart-nodejs-token-check/blob/refactor/nodejs-quickstart/ApproovApplication.js#L237-L251). Protected endpoints are those with `requiresApproov: true` in [ROUTES](https://github.com/approov/quickstart-nodejs-token-check/blob/refactor/nodejs-quickstart/ApproovApplication.js#L32-L88).
Copy link

Copilot AI Feb 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The GitHub URLs contain a hardcoded branch name 'refactor/nodejs-quickstart' that may not exist after the PR is merged. Consider using relative links or updating to point to the main branch.

Suggested change
In this example, Approov protection is enforced by [approovTokenVerifier](https://github.com/approov/quickstart-nodejs-token-check/blob/refactor/nodejs-quickstart/ApproovApplication.js#L199-L235), which reads the `Approov-Token` header, and validates the token `signature` and `exp` claim in [verifyApproovToken](https://github.com/approov/quickstart-nodejs-token-check/blob/refactor/nodejs-quickstart/ApproovApplication.js#L237-L251). Protected endpoints are those with `requiresApproov: true` in [ROUTES](https://github.com/approov/quickstart-nodejs-token-check/blob/refactor/nodejs-quickstart/ApproovApplication.js#L32-L88).
In this example, Approov protection is enforced by [approovTokenVerifier](https://github.com/approov/quickstart-nodejs-token-check/blob/main/ApproovApplication.js#L199-L235), which reads the `Approov-Token` header, and validates the token `signature` and `exp` claim in [verifyApproovToken](https://github.com/approov/quickstart-nodejs-token-check/blob/main/ApproovApplication.js#L237-L251). Protected endpoints are those with `requiresApproov: true` in [ROUTES](https://github.com/approov/quickstart-nodejs-token-check/blob/main/ApproovApplication.js#L32-L88).

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should do it - when all is merged, double check later lines correspond to correct code snippets

Comment thread ApproovApplication.js Outdated
Comment on lines +505 to +507
// case the SDK may skip message signing entirely. How you handle those
// requests (reject, allow, or fallback to account-level signing) is a
// customer policy decision.
Copy link

Copilot AI Feb 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment indicates this is a production consideration but the code throws an error unconditionally. The documentation should clarify whether this is the intended production behavior or if the TODO needs implementation.

Suggested change
// case the SDK may skip message signing entirely. How you handle those
// requests (reject, allow, or fallback to account-level signing) is a
// customer policy decision.
// case the SDK may skip message signing entirely.
//
// This implementation enforces message signing and therefore REJECTS
// such requests by throwing an error when no signing claims are present.
// If your security policy requires allowing these requests or falling
// back to a different verification strategy, you must explicitly change
// this behavior in code.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

doesnt apply as this is a quickstart

@adriantuk adriantuk requested a review from ivolz February 5, 2026 12:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants