Skip to content

fix(api): return 403 for authorization failures, reserve 401 for missing session - #41660

Closed
surjeetkumar8006 wants to merge 1 commit into
RocketChat:developfrom
surjeetkumar8006:fix/api-401-403-semantics-v4
Closed

fix(api): return 403 for authorization failures, reserve 401 for missing session#41660
surjeetkumar8006 wants to merge 1 commit into
RocketChat:developfrom
surjeetkumar8006:fix/api-401-403-semantics-v4

Conversation

@surjeetkumar8006

@surjeetkumar8006 surjeetkumar8006 commented Aug 2, 2026

Copy link
Copy Markdown

Proposal
Fixes REST API HTTP status code semantics for authentication vs authorization failures and aligns validation errorType naming consistency across the typed router, resolving #41589.

Endpoints
ApiClass, Router, permissionsMiddleware, rooms.getMembers, rooms.hide, rooms.bannedUsers

Notes

  • Reserve 401 status strictly for unauthenticated requests (!user / missing session).
  • Remap permission denials (error-unauthorized / error-not-authorized) to 403 (forbidden).
  • Align Router.ts body validation error type from invalid-params to error-invalid-params matching ajvQuery failure responses.
  • Clean up dead applyBreakingChanges branch in permissions.ts middleware and update rooms.ts response schemas to validateForbiddenErrorResponse.
  • Add changeset for patch release.

Task: #41589

Summary by CodeRabbit
Refactor: Standardized REST API error handling to return 403 Forbidden for authorization failures and reserved 401 Unauthorized strictly for unauthenticated missing-session requests.
Bug Fixes: Aligned body validation errorType in Hono typed router to 'error-invalid-params' for consistency with query validation errors across all REST endpoints.

Review in cubic

Summary by CodeRabbit

  • Bug Fixes

    • Authorization failures now consistently return 403 Forbidden for authenticated requests lacking access; 401 Unauthorized is reserved for missing sessions.
    • Room access and administration endpoints now correctly report insufficient permissions with 403 responses.
    • API error handling now recognizes additional authorization error formats.
    • Invalid query and request-body parameters now consistently use error-invalid-params.
  • Documentation

    • Updated API migration guidance to reflect standardized validation errors.

@surjeetkumar8006
surjeetkumar8006 requested a review from a team as a code owner August 2, 2026 13:08
@dionisio-bot

dionisio-bot Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Looks like this PR is not ready to merge, because of the following issues:

  • This PR is missing the 'stat: QA assured' label
  • This PR is missing the required milestone or project

Please fix the issues and try again

If you have any trouble, please check the PR guidelines

@changeset-bot

changeset-bot Bot commented Aug 2, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: c7cefd3

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 6 packages
Name Type
@rocket.chat/meteor Patch
@rocket.chat/http-router Patch
@rocket.chat/core-services Patch
@rocket.chat/federation-matrix Patch
@rocket.chat/core-typings Patch
@rocket.chat/rest-typings Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@coderabbitai

coderabbitai Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 2ced8831-2d05-4821-80b7-bc5e81deecac

📥 Commits

Reviewing files that changed from the base of the PR and between c7223ec and c7cefd3.

📒 Files selected for processing (7)
  • .changeset/real-mails-count.md
  • apps/meteor/server/api/ApiClass.ts
  • apps/meteor/server/api/v1/middlewares/permissions.ts
  • apps/meteor/server/api/v1/rooms.ts
  • docs/api-endpoint-migration.md
  • packages/http-router/src/Router.spec.ts
  • packages/http-router/src/Router.ts
🚧 Files skipped from review as they are similar to previous changes (7)
  • packages/http-router/src/Router.ts
  • .changeset/real-mails-count.md
  • apps/meteor/server/api/v1/middlewares/permissions.ts
  • apps/meteor/server/api/ApiClass.ts
  • packages/http-router/src/Router.spec.ts
  • apps/meteor/server/api/v1/rooms.ts
  • docs/api-endpoint-migration.md

Walkthrough

The API now returns 403 for authenticated authorization failures and reserves 401 for missing sessions. HTTP router body validation uses error-invalid-params, with updated tests and migration documentation.

Changes

API error response standardization

Layer / File(s) Summary
Authorization forbidden responses
apps/meteor/server/api/ApiClass.ts, apps/meteor/server/api/v1/middlewares/permissions.ts, apps/meteor/server/api/v1/rooms.ts, .changeset/real-mails-count.md
Error mapping recognizes additional authorization error shapes. Permission failures and restricted room endpoints now return or declare HTTP 403 Forbidden.
Validation error type
packages/http-router/src/Router.ts, packages/http-router/src/Router.spec.ts, docs/api-endpoint-migration.md
Request-body validation uses error-invalid-params. Tests and migration guidance cover query and body validation.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

Suggested labels: type: bug

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main API change from 401 authorization failures to 403 responses.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Warning

Review ran into problems

🔥 Problems

Errors were encountered while retrieving linked issues.

Errors (1)
  • API-401: Request failed with status code 401

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c7223ecd12

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

if (applyBreakingChanges) {
return api.unauthorized(typeof e === 'string' ? e : e.message);
}
case 'error-not-authorized':

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Add 403 schemas for remapped authorization errors

This new mapping also catches plain Error('error-not-authorized'), but several typed routes that can throw that value still only declare 400/401 responses. For example, rooms.adminRooms calls findAdminRooms, which throws error-not-authorized when the caller lacks view-room-administration, while its response block has no 403; because API.v1.get() registers typed routes with typed: true, packages/http-router/src/Router.ts throws a missing-response-validator error under TEST_MODE instead of returning the intended 403. Please add 403: validateForbiddenErrorResponse to all affected routes or keep this remap limited to endpoints whose specs were updated.

Useful? React with 👍 / 👎.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.changeset/real-mails-count.md:
- Around line 1-6: Update the changeset metadata for `@rocket.chat/meteor` and
`@rocket.chat/http-router` to use the breaking-release level that matches the
documented 401-to-403 API behavior, or revise the summary to remove the breaking
marker only if the change is confirmed backward-compatible.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 9f0de4d8-b038-4ec8-b351-2e0f83d15e7a

📥 Commits

Reviewing files that changed from the base of the PR and between 94478c6 and c7223ec.

📒 Files selected for processing (7)
  • .changeset/real-mails-count.md
  • apps/meteor/server/api/ApiClass.ts
  • apps/meteor/server/api/v1/middlewares/permissions.ts
  • apps/meteor/server/api/v1/rooms.ts
  • docs/api-endpoint-migration.md
  • packages/http-router/src/Router.spec.ts
  • packages/http-router/src/Router.ts
📜 Review details
⏰ Context from checks skipped due to timeout. (1)
  • GitHub Check: cubic · AI code reviewer
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)

**/*.{ts,tsx,js}: Write concise, technical TypeScript/JavaScript with accurate typing in Playwright tests
Avoid code comments in the implementation

Files:

  • packages/http-router/src/Router.spec.ts
  • packages/http-router/src/Router.ts
  • apps/meteor/server/api/v1/middlewares/permissions.ts
  • apps/meteor/server/api/v1/rooms.ts
  • apps/meteor/server/api/ApiClass.ts
**/*.spec.ts

📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)

**/*.spec.ts: Use descriptive test names that clearly communicate expected behavior in Playwright tests
Use .spec.ts extension for test files (e.g., login.spec.ts)

Files:

  • packages/http-router/src/Router.spec.ts
🧠 Learnings (9)
📚 Learning: 2025-12-10T21:00:43.645Z
Learnt from: KevLehman
Repo: RocketChat/Rocket.Chat PR: 37091
File: ee/packages/abac/jest.config.ts:4-7
Timestamp: 2025-12-10T21:00:43.645Z
Learning: Adopt the monorepo-wide Jest testMatch pattern: <rootDir>/src/**/*.spec.{ts,js,mjs} (represented here as '**/src/**/*.spec.{ts,js,mjs}') to ensure spec files under any package's src directory are picked up consistently across all packages in the Rocket.Chat monorepo. Apply this pattern in jest.config.ts for all relevant packages to maintain uniform test discovery.

Applied to files:

  • packages/http-router/src/Router.spec.ts
📚 Learning: 2026-02-24T19:22:48.358Z
Learnt from: juliajforesti
Repo: RocketChat/Rocket.Chat PR: 38493
File: apps/meteor/tests/e2e/omnichannel/omnichannel-send-pdf-transcript.spec.ts:66-67
Timestamp: 2026-02-24T19:22:48.358Z
Learning: In Playwright end-to-end tests (e.g., under apps/meteor/tests/e2e/...), prefer locating elements by translated text (getByText) and ARIA roles (getByRole) over data-qa attributes. If translation values change, update the corresponding test locators accordingly. Never use data-qa locators. This guideline applies to all Playwright e2e test specs in the repository and helps keep tests robust to UI text changes and accessible semantics.

Applied to files:

  • packages/http-router/src/Router.spec.ts
📚 Learning: 2026-02-26T19:25:44.063Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 38778
File: packages/ui-voip/src/providers/useMediaSession.ts:192-192
Timestamp: 2026-02-26T19:25:44.063Z
Learning: In the Rocket.Chat repository, do not reference Biome lint rules in code review feedback. Biome is not used even if biome.json exists; only reference Biome rules if there is explicit, project-wide usage documented. For TypeScript files, review lint implications without Biome guidance unless the project enables Biome rules.

Applied to files:

  • packages/http-router/src/Router.spec.ts
  • packages/http-router/src/Router.ts
  • apps/meteor/server/api/v1/middlewares/permissions.ts
  • apps/meteor/server/api/v1/rooms.ts
  • apps/meteor/server/api/ApiClass.ts
📚 Learning: 2026-02-26T19:25:44.063Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 38778
File: packages/ui-voip/src/providers/useMediaSession.ts:192-192
Timestamp: 2026-02-26T19:25:44.063Z
Learning: In this repository (RocketChat/Rocket.Chat), Biome lint rules are not used even if a biome.json exists. When reviewing TypeScript files (e.g., packages/ui-voip/src/providers/useMediaSession.ts), ensure lint suggestions do not reference Biome-specific rules. Rely on general ESLint/TypeScript lint rules and project conventions instead.

Applied to files:

  • packages/http-router/src/Router.spec.ts
  • packages/http-router/src/Router.ts
  • apps/meteor/server/api/v1/middlewares/permissions.ts
  • apps/meteor/server/api/v1/rooms.ts
  • apps/meteor/server/api/ApiClass.ts
📚 Learning: 2026-03-06T18:10:15.268Z
Learnt from: tassoevan
Repo: RocketChat/Rocket.Chat PR: 39397
File: packages/gazzodown/src/code/CodeBlock.spec.tsx:47-68
Timestamp: 2026-03-06T18:10:15.268Z
Learning: In tests (especially those using testing-library/dom/jsdom) for Rocket.Chat components, the HTML <code> element has an implicit ARIA role of 'code'. Therefore, screen.getByRole('code') or screen.findByRole('code') will locate <code> elements even without a role attribute. Do not flag findByRole('code') as invalid in reviews; prefer using the implicit role instead of adding role="code" unless necessary for accessibility.

Applied to files:

  • packages/http-router/src/Router.spec.ts
📚 Learning: 2026-05-06T12:21:44.083Z
Learnt from: juliajforesti
Repo: RocketChat/Rocket.Chat PR: 40256
File: apps/meteor/client/components/CreateDiscussion/CreateDiscussion.tsx:121-149
Timestamp: 2026-05-06T12:21:44.083Z
Learning: Field wrappers in rocket.chat/fuselage-forms (Field, FieldLabel, FieldRow, FieldError, FieldHint) auto-create htmlFor/id associations, aria-describedby, and role="alert" for errors. Do not manually set htmlFor, id, aria-describedby, or role attributes when using these wrappers. This automatic wiring does not apply to plain rocket.chat/fuselage components, which require explicit ID wiring per the accessibility docs. In code reviews, prefer using fuselage-forms wrappers for form fields and verify there is no unnecessary manual ID/aria wiring in files that use these wrappers. If a component uses plain fuselage components, ensure proper id wiring as per docs.

Applied to files:

  • packages/http-router/src/Router.spec.ts
  • packages/http-router/src/Router.ts
  • apps/meteor/server/api/v1/middlewares/permissions.ts
  • apps/meteor/server/api/v1/rooms.ts
  • apps/meteor/server/api/ApiClass.ts
📚 Learning: 2026-03-16T21:50:37.589Z
Learnt from: amitb0ra
Repo: RocketChat/Rocket.Chat PR: 39676
File: .changeset/migrate-users-register-openapi.md:3-3
Timestamp: 2026-03-16T21:50:37.589Z
Learning: For changes related to OpenAPI migrations in Rocket.Chat/OpenAPI, when removing endpoint types and validators from rocket.chat/rest-typings (e.g., UserRegisterParamsPOST, /v1/users.register) document this as a minor changeset (not breaking) per RocketChat/Rocket.Chat-Open-API#150 Rule 7. Note that the endpoint type is re-exposed via a module augmentation .d.ts in the consuming package (e.g., packages/web-ui-registration/src/users-register.d.ts). In reviews, ensure the changeset clearly states: this is a non-breaking change, the major version should not be bumped, and the changeset reflects a minor version bump. Do not treat this as a breaking change during OpenAPI migrations.

Applied to files:

  • .changeset/real-mails-count.md
📚 Learning: 2026-07-31T02:44:35.111Z
Learnt from: ggazzo
Repo: RocketChat/Rocket.Chat PR: 41635
File: apps/meteor/ee/server/api/sessions.ts:114-138
Timestamp: 2026-07-31T02:44:35.111Z
Learning: In Rocket.Chat typed REST response schemas, accept the composition of a Typia-generated entity schema with an `allOf` branch requiring `success: true`: `allOf: [{ $ref: <entity schema> }, { properties: { success: { type: 'boolean', enum: [true] } }, required: ['success'] }]`. Do not flag this pattern when used for REST endpoints, provided TEST_MODE response validation passes, as demonstrated by the `IOAuthApps` and `IEmailInbox` endpoints.

Applied to files:

  • apps/meteor/server/api/v1/middlewares/permissions.ts
  • apps/meteor/server/api/v1/rooms.ts
  • apps/meteor/server/api/ApiClass.ts
📚 Learning: 2026-07-29T23:45:21.859Z
Learnt from: ggazzo
Repo: RocketChat/Rocket.Chat PR: 41632
File: apps/meteor/server/api/v1/groups.ts:948-959
Timestamp: 2026-07-29T23:45:21.859Z
Learning: For API v1 routes under apps/meteor/server/api/v1, keep item-level response schemas strict by using `$ref`-based schemas for list and messages (and ensure they intentionally mirror the corresponding route contracts, as done in channels.ts). Only use “loose”/non-`$ref` item schemas when the underlying data source is inherently partial (e.g., uploads where `content` can be `null`, or queries like `findUsersOfRoom` with a fixed projection). Do not relax item schemas merely because the route supports an optional client `fields` projection—optional field selection alone is not a reason to change schema strictness.

Applied to files:

  • apps/meteor/server/api/v1/rooms.ts
🔇 Additional comments (7)
packages/http-router/src/Router.ts (1)

248-248: LGTM!

packages/http-router/src/Router.spec.ts (1)

210-215: LGTM!

docs/api-endpoint-migration.md (2)

600-600: LGTM!


618-618: LGTM!

apps/meteor/server/api/v1/middlewares/permissions.ts (1)

46-47: LGTM!

apps/meteor/server/api/v1/rooms.ts (1)

1139-1139: 🗄️ Data Integrity & Integration

No change needed. ForbiddenErrorResponseSchema allows optional error, status, and message, so it accepts both API.v1.forbidden() bodies (error: 'unauthorized' and error: 'forbidden').

apps/meteor/server/api/ApiClass.ts (1)

898-904: 🗄️ Data Integrity & Integration

No change needed. The 401/403 mapping matches the current API error-code contract: missing-session/authentication paths return separate unauthorized() responses, while these codes are used for authenticated permission/access failures.

Comment thread .changeset/real-mails-count.md Outdated
Comment on lines +1 to +6
---
"@rocket.chat/meteor": patch
"@rocket.chat/http-router": patch
---

fix(api)!: return 403 for authorization failures, reserve 401 for missing session

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== changeset files =="
git ls-files .changeset | sed -n '1,80p'

echo
echo "== target changeset =="
cat -n .changeset/real-mails-count.md

echo
echo "== package identifiers / monorepo =="
git ls-files package.json "**/package.json" | sed -n '1,120p'
rg -n '"(`@rocket.chat/meteor`|`@rocket.chat/http-router`)"|name:"(`@rocket.chat/meteor`|`@rocket.chat/http-router`)"' package.json $(git ls-files '*package.json') 2>/dev/null | sed -n '1,120p'

echo
echo "== repo policy hints for breaking changesets =="
git ls-files | rg -i '(changeset|change.*set|release|changelog|contribut|README|license|package\.json' | sed -n '1,120p'
rg -n 'breaking|!!!|!|changeset|patch|minor|major|release|change' .changeset README.md package.json 2>/dev/null | sed -n '1,160p'

echo
echo "== related status code descriptions in target package files, if present =="
rg -n '401|403|fix\(api\)|authorization failures|missing session' . 2>/dev/null | sed -n '1,200p'

Repository: RocketChat/Rocket.Chat

Length of output: 6610


🌐 Web query:

Changesets convention breaking change patch release ! exclamation mark semantic version breaking change

💡 Result:

In the Changesets workflow, the exclamation mark (!) convention typically used in Conventional Commits to denote breaking changes is not a native feature of the Changesets tool itself [1][2][3]. Changesets operates on the principle of "intentional releases" rather than parsing commit history [3]. When you create a changeset, you manually declare the intended semantic version bump type (major, minor, or patch) directly within the changeset file’s YAML front matter [4][5][6]. Key distinctions to keep in mind: 1. Intentional vs. Automated: Unlike tools such as semantic-release, which may scan commit messages for the ! convention to automate versioning, Changesets requires the developer to explicitly choose the bump type when running the changeset command [3][5]. 2. Defining Breaking Changes: If a change is breaking, you must manually set the package bump type to major in the changeset file [6][7]. The exclamation mark has no functional impact on the Changesets CLI logic [1][8]. 3. Changelog Documentation: While the ! does not trigger versioning behavior, it is common practice to document breaking changes clearly within the summary section of the changeset file [5][9]. Because Changesets allows you to include markdown in this summary, you should describe the breaking change and provide migration instructions directly there [5][6][9]. If you are seeing the exclamation mark used in conjunction with Changesets in some repositories, it is likely part of the project's internal contribution guidelines (e.g., to help human reviewers identify breaking changes in PRs) rather than a feature of the Changesets tool itself [10].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== .changeset configuration =="
cat -n .changeset/config.json

echo
echo "== .changeset README snippets =="
wc -l .changeset/README.md
sed -n '1,220p' .changeset/README.md

echo
echo "== package metadata =="
python3 - <<'PY'
import json
from pathlib import Path
for p in [Path('package.json'), Path('apps/meteor/package.json'), Path('packages/http-router/package.json')]:
    if p.exists():
        print(f'--- {p} ---')
        data=json.load(open(p))
        print(f"publishConfig={data.get('publishConfig')}")
        print(f"name={data.get('name')}")
        print(f"version={data.get('version')}")
        print()
PY

echo
echo "== search for changeset breaking/major/minor policy or conventional commit usage =="
rg -n 'Breaking|breaking|major|minor|patch|!!!|Conventional|changeset|Version|Release|version' .github .changeset README.md CONTRIBUTING.md package.json scripts scripts/** 2>/dev/null | sed -n '1,220p'

Repository: RocketChat/Rocket.Chat

Length of output: 22882


🌐 Web query:

Google API error 401 auth required 403 forbidden status code REST API authorization breaking change

💡 Result:

When interacting with Google APIs, 401 Unauthorized and 403 Forbidden errors signify distinct issues in the request lifecycle: 401 errors indicate that Google cannot verify who is making the request (authentication), while 403 errors indicate that the authenticated identity lacks permission to access the requested resource (authorization) [1][2][3]. 401 Unauthorized (Authentication Required) A 401 status code means the request is missing a valid access token or the provided credentials are invalid, expired, or malformed [1][4][2]. Common causes include: - Expired or revoked access tokens [1][2][5]. - An incorrect or missing Authorization header [2]. - Mismatched credentials (e.g., the token project does not match the resource project) [2]. - Improperly registered or disabled OAuth 2.0 clients [6]. Resolution: Ensure your application provides a valid OAuth 2.0 access token [1][3]. If using client libraries, they often handle token refreshes automatically; otherwise, you must implement logic to refresh the token using a long-lived refresh token or re-run the OAuth flow [1][4]. 403 Forbidden (Permission Denied) A 403 status code means the request was successfully authenticated, but the identity lacks the necessary privileges to perform the requested action [1][2][7]. Common causes include: - Insufficient Identity and Access Management (IAM) permissions [2][8]. - Exceeding API rate limits or usage quotas [4][2]. - The requested resource does not exist or is protected by a policy that explicitly denies access [2][8]. - API usage restrictions, such as the API not being enabled for the project or the user not being added to an application's test user list [6][9]. Resolution: Evaluate the reason field in the API's JSON error response to determine the specific cause [1][2]. Use the Policy Troubleshooter in the Google Cloud Console to identify which IAM policies are blocking access for a specific principal, resource, and permission [8][10]. Breaking Changes and REST API Authorization Google maintains strict compatibility standards [11]. While minor and patch updates must not break existing client code, major version changes (encoded in the URI path) may introduce incompatible changes [12][11]. Google recommends consulting AIP-180 and AIP-181 for guidance when breaking changes are necessary for an API [12]. Always prefer official client libraries, as they are designed to handle authentication, retries, and versioning complexities behind the scenes, reducing the impact of underlying API surface updates [1][4]. For further troubleshooting, consult the specific documentation for the Google API you are using, as error details vary by service [1][4][13]. Log API errors on the client side, as Google does not provide full API request logs to developers for privacy and security reasons [13].

Citations:


Align the patch-level changeset with the visible API behavior.

The entries for @rocket.chat/meteor and @rocket.chat/http-router are patch, while the summary documents a change in observable status codes from 401 to 403. Use the breaking-release level for these packages, or replace fix(api)! with a non-breaking summary if this change can be demonstrated as compatible at patch time.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.changeset/real-mails-count.md around lines 1 - 6, Update the changeset
metadata for `@rocket.chat/meteor` and `@rocket.chat/http-router` to use the
breaking-release level that matches the documented 401-to-403 API behavior, or
revise the summary to remove the breaking marker only if the change is confirmed
backward-compatible.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

2 issues found across 7 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name=".changeset/real-mails-count.md">

<violation number="1" location=".changeset/real-mails-count.md:6">
P2: The summary marks this as a breaking change with `fix(api)!:`, yet both packages are bumped at `patch` in the frontmatter. Since the PR rewrites REST error-status semantics (401→403 for authorization failures), clients depending on the old codes are impacted; either bump to `major` to match the `!` marker, or drop the `!` if the intent is a non-breaking patch.</violation>
</file>

<file name="apps/meteor/server/api/ApiClass.ts">

<violation number="1" location="apps/meteor/server/api/ApiClass.ts:898">
P2: This remap causes any `Error('error-not-authorized')` thrown from typed routes to resolve to a 403 response, but several routes registered with `typed: true` (e.g. `rooms.adminRooms`) don't declare a `403` schema in their response map — only `400`/`401`. Since the typed Router validates responses against declared schemas under `TEST_MODE`, those routes will throw a missing-response-validator error instead of returning the intended 403. Add `403: validateForbiddenErrorResponse` to all typed routes that can throw `error-not-authorized`, or scope this remap to endpoints whose specs were already updated.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread .changeset/real-mails-count.md Outdated
"@rocket.chat/http-router": patch
---

fix(api)!: return 403 for authorization failures, reserve 401 for missing session

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2: The summary marks this as a breaking change with fix(api)!:, yet both packages are bumped at patch in the frontmatter. Since the PR rewrites REST error-status semantics (401→403 for authorization failures), clients depending on the old codes are impacted; either bump to major to match the ! marker, or drop the ! if the intent is a non-breaking patch.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .changeset/real-mails-count.md, line 6:

<comment>The summary marks this as a breaking change with `fix(api)!:`, yet both packages are bumped at `patch` in the frontmatter. Since the PR rewrites REST error-status semantics (401→403 for authorization failures), clients depending on the old codes are impacted; either bump to `major` to match the `!` marker, or drop the `!` if the intent is a non-breaking patch.</comment>

<file context>
@@ -0,0 +1,6 @@
+"@rocket.chat/http-router": patch
+---
+
+fix(api)!: return 403 for authorization failures, reserve 401 for missing session
</file context>

} catch (e: any) {
result = ((e: any) => {
switch (e.error) {
const errorKey = typeof e === 'string' ? e : e.error || e.message;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2: This remap causes any Error('error-not-authorized') thrown from typed routes to resolve to a 403 response, but several routes registered with typed: true (e.g. rooms.adminRooms) don't declare a 403 schema in their response map — only 400/401. Since the typed Router validates responses against declared schemas under TEST_MODE, those routes will throw a missing-response-validator error instead of returning the intended 403. Add 403: validateForbiddenErrorResponse to all typed routes that can throw error-not-authorized, or scope this remap to endpoints whose specs were already updated.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/meteor/server/api/ApiClass.ts, line 898:

<comment>This remap causes any `Error('error-not-authorized')` thrown from typed routes to resolve to a 403 response, but several routes registered with `typed: true` (e.g. `rooms.adminRooms`) don't declare a `403` schema in their response map — only `400`/`401`. Since the typed Router validates responses against declared schemas under `TEST_MODE`, those routes will throw a missing-response-validator error instead of returning the intended 403. Add `403: validateForbiddenErrorResponse` to all typed routes that can throw `error-not-authorized`, or scope this remap to endpoints whose specs were already updated.</comment>

<file context>
@@ -895,14 +895,13 @@ export class APIClass<TBasePath extends string = '', TOperations extends Record<
 						} catch (e: any) {
 							result = ((e: any) => {
-								switch (e.error) {
+								const errorKey = typeof e === 'string' ? e : e.error || e.message;
+								switch (errorKey) {
 									case 'error-too-many-requests':
</file context>

@surjeetkumar8006
surjeetkumar8006 force-pushed the fix/api-401-403-semantics-v4 branch from c7223ec to c7cefd3 Compare August 2, 2026 13:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants