-
Notifications
You must be signed in to change notification settings - Fork 4.4k
Feat: tokens #8997
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feat: tokens #8997
Conversation
✨ Benchmark results
⚡ Benchmark Comparison
|
""" WalkthroughThis update introduces a comprehensive resource token management system for storage buckets and files. It adds new API endpoints for creating, listing, retrieving, updating, deleting, and obtaining JWTs for resource tokens. Supporting infrastructure includes new database collections, permission scopes, error codes, OpenAPI/Swagger documentation, backend logic for token validation and authorization, and extensive end-to-end tests. The changes span configuration files, controllers, platform modules, validators, response models, and automated tests, ensuring resource tokens are integrated into both the API and the underlying authorization logic. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant API
participant DB
participant JWT
Client->>API: POST /tokens/buckets/{bucketId}/files/{fileId} (create token)
API->>DB: Validate bucket/file, permissions
API->>DB: Insert resourceToken document
API->>Client: Return created token
Client->>API: GET /tokens/{tokenId}/jwt
API->>DB: Fetch resourceToken by tokenId
API->>JWT: Encode JWT with token data
API->>Client: Return JWT
Client->>API: GET /storage/buckets/{bucketId}/files/{fileId}/preview?token=...
API->>DB: Validate resourceToken from JWT
API->>DB: Fetch file if token valid
API->>Client: Return file preview
Suggested reviewers
Poem
""" Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider gi 8000 ving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
Documentation and Community
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Copilot reviewed 19 out of 38 changed files in this pull request and generated no comments.
Files not reviewed (19)
- app/config/collections/projects.php: Language not supported
- app/config/roles.php: Language not supported
- app/config/scopes.php: Language not supported
- app/controllers/api/storage.php: Language not supported
- app/controllers/general.php: Language not supported
- app/controllers/shared/api.php: Language not supported
- app/init/resources.php: Language not supported
- src/Appwrite/Extend/Exception.php: Language not supported
- src/Appwrite/Platform/Appwrite.php: Language not supported
- src/Appwrite/Platform/Modules/Storage/Http/Tokens/Buckets/Files/Action.php: Language not supported
- src/Appwrite/Platform/Modules/Storage/Http/Tokens/Buckets/Files/Create.php: Language not supported
- src/Appwrite/Platform/Modules/Storage/Http/Tokens/Buckets/Files/XList.php: Language not supported
- src/Appwrite/Platform/Modules/Storage/Http/Tokens/Delete.php: Language not supported
- src/Appwrite/Platform/Modules/Storage/Http/Tokens/Get.php: Language not supported
- src/Appwrite/Platform/Modules/Storage/Http/Tokens/JWT/Get.php: Language not supported
- src/Appwrite/Platform/Modules/Storage/Http/Tokens/Update.php: Language not supported
- src/Appwrite/Platform/Modules/Storage/Module.php: Language not supported
- src/Appwrite/Platform/Modules/Storage/Services/Http.php: Language not supported
- src/Appwrite/Platform/Workers/Migrations.php: Language not supported
commit: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 22
🔭 Outside diff range comments (3)
app/config/specs/swagger2-latest-server.json (1)
19179-19262
:⚠️ Potential issueFix duplicate platform entry and malformed
edit
URL.
- The
platforms
array lists"server"
twice; please remove the duplicate.- The
x-appwrite.edit
link is malformed (.../edit/masterList all the tokens...
). It should include the actual file path aftermaster/
, for example:
https://github.com/appwrite/appwrite/edit/master/src/controllers/storageTokensController.php
app/config/specs/open-api3-latest-console.json (1)
26678-26754
:⚠️ Potential issueFix
edit
URL, remove duplicateserver
, and markrequestBody
as required increateFileToken
The
edit
URL is missing a path separator,server
appears twice, and therequestBody
should be required:"x-appwrite": { - "edit": "https://github.com/appwrite/appwrite/edit/masterCreate a new token ...", + "edit": "https://github.com/appwrite/appwrite/edit/master/docs/references/tokens/create-file-token.md", ... - "platforms": ["client","server","server"], + "platforms": ["client","server"], ... "requestBody": { + "required": true, "content": { ... }app/config/specs/swagger2-latest-console.json (1)
27059-27138
: 🛠️ Refactor suggestion
⚠️ Potential issueFix malformed
edit
URL and duplicate platform entry
Theedit
link underx-appwrite
is missing a slash and contains extraneous descriptive text. Also, theplatforms
array includes"server"
twice. Please correct these to:- "edit": "https://github.com/appwrite/appwrite/edit/masterList all the tokens created for a specific file or bucket. You can use the query params to filter your results.", + "edit": "https://github.com/appwrite/appwrite/edit/master/docs/references/tokens/list.md" - "platforms": [ - "client", - "server", - "server" - ], + "platforms": [ + "client", + "server" + ],
♻️ Duplicate comments (2)
app/config/specs/swagger2-latest-server.json (1)
26593-26596
: Duplicate of earliersecret
schema inconsistency.Refer to the feedback at lines 10130–10135 for details on standardizing the
secret
property across all schemas.app/config/specs/swagger2-latest-console.json (1)
36498-36502
: Duplicatesecret
flag addition in variable definitions
Thesecret
flag insertion here is identical to other variable schemas reviewed above. No further changes needed in this block.Also applies to: 36520-36521
🧹 Nitpick comments (29)
tests/e2e/Services/Tokens/TokensBase.php (1)
1-7
: Consider adding common token test functionality to this empty trait.The TokensBase trait is currently empty. Consider adding common test methods or utilities that would be shared across your token test classes to reduce code duplication in the test suite.
For example, you could add helper methods for token creation, validation, and cleanup that would be reused across the TokensConsoleClientTest, TokensCustomClientTest, and TokensCustomServerTest classes.
app/init/resources.php (2)
844-885
: Consider adding explicit token expiration checkWhile the JWT validation includes a maximum age (900 seconds), there's no explicit check against the token's
expire
field from the database. Consider whether an additional verification of the token's expiration timestamp is needed for more granular control.if ($token->isEmpty() || $token->getAttribute('secret') != $secret) { return new Document([]); } +// Verify token hasn't expired if it has an expiration date +$expireTime = $token->getAttribute('expire', null); +if (!empty($expireTime) && new \DateTime($expireTime) < new \DateTime()) { + return new Document([]); +}
856-866
: Consider adding debug logging for token validation failuresFor easier troubleshooting in production, consider adding debug logging when token validation fails, capturing the specific reason (missing fields, secret mismatch, format error, etc.).
try { $payload = $jwt->decode($tokenJWT); } catch (JWTException $error) { + // Log reason: JWT decode failed + App::getResource('logger')->debug("Resource token validation failed: JWT decode error"); return new Document([]); } $tokenId = $payload['tokenId'] ?? ''; $secret = $payload['secret'] ?? ''; if (empty($tokenId) || empty($secret)) { + // Log reason: Missing required fields + App::getResource('logger')->debug("Resource token validation failed: Missing tokenId or secret"); return new Document([]); }src/Appwrite/Platform/Modules/Storage/Http/Tokens/Delete.php (1)
69-71
: Consider adding a transaction for atomic token deletion.For better data integrity, consider wrapping the token deletion operation in a database transaction.
+ $dbForProject->startTransaction(); $dbForProject->deleteDocument('resourceTokens', $tokenId); + $dbForProject->commitTransaction();src/Appwrite/Platform/Modules/Storage/Http/Tokens/Buckets/Files/Action.php (2)
13-14
: Consider adding method documentation.Adding proper PHPDoc comments would improve code maintainability and help other developers understand the purpose and usage of this method.
/** + * Retrieve file and bucket documents with proper permission checks + * + * @param Database $dbForProject Project database instance + * @param string $bucketId ID of the storage bucket + * @param string $fileId ID of the file within the bucket + * @return array Associative array containing 'bucket' and 'file' documents + * @throws Exception When bucket or file not found or user unauthorized + */ protected function getFileAndBucket(Database $dbForProject, string $bucketId, string $fileId): array
20-22
: Separate existence and permission checks for clearer error handling.The combined condition makes it harder to distinguish between different error scenarios. Consider separating these checks for clearer error messages.
- if ($bucket->isEmpty() || (!$bucket->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser)) { - throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); - } + if ($bucket->isEmpty()) { + throw new Exception(Exception::STORAGE_BUCKET_NOT_FOUND); + } + + if (!$bucket->getAttribute('enabled') && !$isAPIKey && !$isPrivilegedUser) { + throw new Exception(Exception::STORAGE_BUCKET_DISABLED); + }tests/e2e/Services/Tokens/TokensCustomServerTest.php (1)
100-111
: Add verification that deleted token cannot be accessed.After deleting the token, add an assertion to verify that the token can no longer be accessed, ensuring complete deletion.
public function testDeleteToken(array $data): array { $tokenId = $data['tokenId']; $res = $this->client->call(Client::METHOD_DELETE, '/tokens/' . $tokenId, array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); $this->assertEquals(204, $res['headers']['status-code']); + + // Verify that the token can no longer be accessed + $getRes = $this->client->call(Client::METHOD_GET, '/tokens/' . $tokenId, array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertEquals(404, $getRes['headers']['status-code']); return $data; }src/Appwrite/Platform/Modules/Storage/Http/Tokens/JWT/Get.php (2)
73-73
: Remove unnecessary semicolon.There's an extra semicolon at the end of this line that should be removed.
- ;
76-76
: Consider making JWT leeway configurable.The JWT is created with a hardcoded leeway of 10 seconds. Consider making this value configurable or aligning it with other JWT usage in the codebase.
- $jwt = new JWT(System::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', $maxAge, 10); // Instantiate with key, algo, maxAge and leeway. + $leeway = (int)System::getEnv('_APP_JWT_LEEWAY', 10); + $jwt = new JWT(System::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', $maxAge, $leeway); // Instantiate with key, algo, maxAge and leeway.src/Appwrite/Platform/Modules/Storage/Http/Tokens/Buckets/Files/XList.php (1)
67-82
: Minor: cursor extraction can be simplified & guarded
reset($cursor)
returnsfalse
when the array is empty; the subsequent code assumes aQuery
instance.
You’re already doing a falsy check, but an explicit type‑check keeps static analysers happy and avoids accidental deaths on refactor.$cursorQuery = reset($cursor); if ($cursorQuery instanceof Query) { $tokenId = $cursorQuery->getValue(); … }src/Appwrite/Platform/Modules/Storage/Http/Tokens/Buckets/Files/Create.php (1)
37-38
: Group name inconsistency (token
vstokens
)
Other endpoints usegroups(['api', 'tokens'])
; keeping the same spelling prevents brittle tooling (e.g., metrics or documentation generators) from silently skipping this route.src/Appwrite/Platform/Modules/Storage/Http/Tokens/Update.php (1)
64-66
: Doc‑string grammar & clarity
“An array of permission string.” → “An array of permission strings.”app/controllers/shared/api.php (1)
556-558
: Token overrides bucket‐level ACL – re‑confirm security intentThe added
&& !$isToken
clause means:
• A valid token bypasses bucket read‑permission checks whenfileSecurity
is disabled.
Just verify this behaviour matches the RFC: tokens should only relax ACLs when they belong to the same bucket (which you already check) and are not expired/revoked (handled in the provider).If that’s the intended policy, consider a short inline comment here to make the reasoning explicit for future readers.
app/config/specs/open-api3-latest-client.json (7)
7490-7491
: Minor documentation inconsistency.The edit URL appears to have an incomplete description text appended to it instead of a proper URL path.
- "edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterList all the tokens created for a specific file or bucket. You can use the query params to filter your re 23DA sults.", + "edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/tokens\/list.md",
7571-7572
: Documentation inconsistency in edit URL.Similar to the previous issue, this edit URL appears to have description text appended to it instead of a proper URL path.
- "edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterCreate a new token. A token is linked to a file or a bucket and manages permissions for those file(s). Token can be passed as a header or request get parameter.", + "edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/tokens\/create-file-token.md",
7669-7670
: Documentation inconsistency in edit URL.Another instance of description text being appended to the edit URL instead of a proper URL path.
- "edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterGet a token by its unique ID.", + "edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/tokens\/get.md",
7730-7731
: Documentation inconsistency in edit URL.Similar edit URL issue with description text appended.
- "edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterUpdate a token by its unique ID. Use this endpoint to update a token's expiry date or permissions.", + "edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/tokens\/update.md",
7808-7809
: Documentation inconsistency in edit URL.Similar edit URL issue with description text appended.
- "edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterDelete a token by its unique ID.", + "edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/tokens\/delete.md",
7872-7873
: Documentation inconsistency in edit URL.Final instance of the description text being appended to edit URL issue.
- "edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterGet a JWT based token by its unique ID. You can use the JWT to authenticate on behalf of the user.", + "edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/tokens\/get-jwt.md",
7471-7552
: Token listing endpoint description is empty.The description field for the token listing endpoint is empty, which could impair API documentation clarity.
- "description": "", + "description": "List all the tokens created for a specific file or bucket. You can use the query params to filter your results.",app/config/specs/swagger2-latest-server.json (1)
23234-23258
: Improve thex-example
for thetokens
array.An empty string isn’t representative of the response payload. Consider using a realistic sample, for example:
"x-example": [ { "$id": "bb8ea5c16897e", "$createdAt": "2020-10-15T06:38:00.000+00:00", "resourceId": "5e5ea5c168bb8:5e5ea5c168bb8", "resourceInternalId": "1:1", "resourceType": "file", "expire": "2020-10-15T06:38:00.000+00:00" } ]app/config/specs/open-api3-latest-console.json (3)
11083-11088
: Marksecret
property as write-only and specify a defaultTo enforce the intended behavior (“Secret variables can only be updated or deleted, they cannot be read”), please:
- Add
"writeOnly": true
to eachsecret
schema entry.- Consider adding
"default": false
to explicitly default the field."secret": { + "writeOnly": true, + "default": false, "type": "boolean", "description": "Is secret? Secret variables can only be updated or deleted, they cannot be read.", "x-example": false }Also applies to: 18798-18803, 35958-35962
17747-17824
: RequirerequestBody
for/migrations/csv
By default OpenAPI treats
requestBody
as optional. Since the CSV import endpoint expects a JSON payload, add"required": true"
:"requestBody": { + "required": true, "content": { "application/json": { "schema": { ... }
31343-31366
: ImproveresourceTokenList
example fortokens
arrayThe
x-example
for thetokens
array is currently an empty string. A more representative example would be an array ofresourceToken
objects:"x-example": "" + "x-example": [ + { + "$id": "bb8ea5c16897e", + "resourceId": "db:col", + "resourceInternalId": "1:1", + "resourceType": "file", + "expire": "2025-01-01T00:00:00.000+00:00" + } + ]app/config/specs/swagger2-latest-console.json (3)
11261-11267
: Consider markingsecret
as readOnly and hiding it in responses
Thesecret
boolean flag should not be exposed on GET responses and should be marked with"readOnly": true
in the schema to prevent clients from reading it.
27139-27383
: StandardizecreateFileToken
metadata and platforms
ThecreateFileToken
endpoint inx-appwrite
also lists"server"
twice underplatforms
and itsedit
URL lacks a file path. Consider:- "platforms": ["client","server","server"], + "platforms": ["client","server"], - "edit": "https://github.com/appwrite/appwrite/edit/masterCreate a new token. A token is linked to a file or a bucket and manages permissions for those file(s). Token can be passed as a header or request get parameter.", + "edit": "https://github.com/appwrite/appwrite/edit/master/docs/references/tokens/create-file-token.md"Also, verify that JWT, Key, and Project authentication modes are correctly specified across all token endpoints.
31838-31862
: Enhance thetokens
array example inresourceTokenList
Thex-example
for thetokens
property is an empty string. It would be clearer to provide an array example, e.g.:"x-example": [ { "$id": "bb8ea5c16897e", "resourceId": "5e5ea5c168bb8:5e5ea5c168bb8", "expire": "2025-01-01T00:00:00.000+00:00" } ]app/config/specs/open-api3-latest-server.json (2)
19111-19175
: Tighten Get Token as JWT metadata
- Remove duplicate
"server"
inplatforms
.- Correct the
x-appwrite.edit
URL todocs/references/tokens/get-jwt.md
.
22750-22773
: Improve example in Resource Token List schema
Thex-example
for thetokens
array is an empty string. Consider providing a realistic array example, e.g.:"x-example": [ { "$ref": "#/components/schemas/resourceToken" } ]
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (38)
.github/workflows/tests.yml
(1 hunks)app/config/collections/projects.php
(1 hunks)app/config/roles.php
(1 hunks)app/config/scopes.php
(1 hunks)app/config/specs/open-api3-latest-client.json
(5 hunks)app/config/specs/open-api3-latest-console.json
(65 hunks)app/config/specs/open-api3-latest-server.json
(53 hunks)app/config/specs/swagger2-latest-client.json
(5 hunks)app/config/specs/swagger2-latest-console.json
(66 hunks)app/config/specs/swagger2-latest-server.json
(53 hunks)app/controllers/api/storage.php
(3 hunks)app/controllers/general.php
(3 hunks)app/controllers/shared/api.php
(2 hunks)app/init/resources.php
(1 hunks)src/Appwrite/Extend/Exception.php
(1 hunks)src/Appwrite/Platform/Appwrite.php
(1 hunks)src/Appwrite/Platform/Modules/Storage/Http/Tokens/Buckets/Files/Action.php
(1 hunks)src/Appwrite/Platform/Modules/Storage/Http/Tokens/Buckets/Files/Create.php
(1 hunks)src/Appwrite/Platform/Modules/Storage/Http/Tokens/Buckets/Files/XList.php
(1 hunks)src/Appwrite/Platform/Modules/Storage/Http/Tokens/Delete.php
(1 hunks)src/Appwrite/Platform/Modules/Storage/Http/Tokens/Get.php
(1 hunks)src/Appwrite/Platform/Modules/Storage/Http/Tokens/JWT/Get.php
(1 hunks)src/Appwrite/Platform/Modules/Storage/Http/Tokens/Update.php
(1 hunks)src/Appwrite/Platform/Modules/Storage/Module.php
(1 hunks)src/Appwrite/Platform/Modules/Storage/Services/Http.php
(1 hunks)src/Appwrite/Platform/Workers/Migrations.php
(1 hunks)src/Appwrite/SDK/Method.php
(1 hunks)src/Appwrite/Specification/Format/OpenAPI3.php
(1 hunks)src/Appwrite/Specification/Format/Swagger2.php
(1 hunks)src/Appwrite/Utopia/Database/Validator/Queries/FileTokens.php
(1 hunks)src/Appwrite/Utopia/Response.php
(4 hunks)src/Appwrite/Utopia/Response/Model/ResourceToken.php
(1 hunks)tests/e2e/Scopes/ProjectCustom.php
(1 hunks)tests/e2e/Services/Storage/StorageBase.php
(1 hunks)tests/e2e/Services/Tokens/TokensBase.php
(1 hunks)tests/e2e/Services/Tokens/TokensConsoleClientTest.php
(1 hunks)tests/e2e/Services/Tokens/TokensCustomClientTest.php
(1 hunks)tests/e2e/Services/Tokens/TokensCustomServerTest.php
(1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (5)
src/Appwrite/Platform/Appwrite.php (2)
src/Appwrite/Platform/Modules/Storage/Module.php (2)
__construct
(10-13)Module
(8-14)src/Appwrite/Platform/Modules/Storage/Services/Http.php (1)
__construct
(15-27)
src/Appwrite/Specification/Format/OpenAPI3.php (1)
src/Appwrite/GraphQL/Types/Mapper.php (1)
route
(79-160)
src/Appwrite/Specification/Format/Swagger2.php (1)
src/Appwrite/GraphQL/Types/Mapper.php (1)
route
(79-160)
app/init/resources.php (1)
src/Appwrite/Event/Event.php (1)
getParam
(310-313)
app/config/collections/projects.php (1)
src/Appwrite/Event/Database.php (1)
Database
(9-132)
⏰ Context from checks skipped due to timeout of 90000ms (17)
- GitHub Check: E2E Service Test (Health)
- GitHub Check: E2E Service Test (Messaging)
- GitHub Check: E2E Service Test (Projects)
- GitHub Check: E2E Service Test (Realtime)
- GitHub Check: E2E Service Test (Teams)
- GitHub Check: E2E Service Test (Locale)
- GitHub Check: E2E Service Test (GraphQL)
- GitHub Check: E2E Service Test (Migrations)
- GitHub Check: E2E Service Test (Databases)
- GitHub Check: E2E Service Test (FunctionsSchedule)
- GitHub Check: E2E Service Test (Console)
- GitHub Check: E2E Service Test (Functions)
- GitHub Check: E2E Service Test (Account)
- GitHub Check: E2E Service Test (Avatars)
- GitHub Check: Benchmark
- GitHub Check: E2E General Test
- GitHub Check: Unit Test
🔇 Additional comments (65)
src/Appwrite/Extend/Exception.php (1)
306-307
: New error constant for token management added appropriately.The new error constant
TOKEN_NOT_FOUND
is properly placed under a dedicatedTokens
section, consistent with the existing code organization pattern. This constant will be used by the new token-related endpoints to provide consistent error handling when a requested token cannot be found.src/Appwrite/Utopia/Database/Validator/Queries/FileTokens.php (1)
1-19
:❓ Verification inconclusive
Validator class properly implements query filtering for file tokens.
The FileTokens validator class correctly extends the Base class and allows filtering tokens by the 'expire' attribute, aligning with the new token management functionality being introduced.
However, I notice that only the 'expire' attribute is whitelisted for queries. Will there be other attributes users might need to filter tokens by, such as creation date or token permissions?
🏁 Script executed:
#!/bin/bash # Check the resourceTokens collection schema to see if there are other filterable attributes fd resourceTokens.*php --exec grep -A 30 "Schema" {} \;Length of output: 60
🏁 Script executed:
#!/bin/bash # Locate and display the Files collection schema to identify available fields schema_files=$(fd Files.php src/Appwrite/Utopia/Database/Schema/Collections) for file in $schema_files; do echo "=== Schema file: $file ===" sed -n '1,200p' "$file" doneLength of output: 214
Confirm Additional Filterable Attributes for FileTokens
I wasn’t able to locate the schema definition for thefile_tokens
collection—aside fromexpire
, are there any other fields (e.g.createdAt
, permission flags) that clients should be able to filter by?
• Please review the file‑tokens schema/model to see if extra attributes exist.
• If so, add them to ALLOWED_ATTRIBUTES insrc/Appwrite/Utopia/Database/Validator/Queries/FileTokens.php
.tests/e2e/Scopes/ProjectCustom.php (1)
99-101
: Token permission scopes added correctly to the project key.The new 'tokens.read' and 'tokens.write' scopes are properly added to the list of scopes for the project key, enabling the test suite to interact with the token management endpoints.
app/config/roles.php (1)
79-80
: Proper addition of token permission scopes.These new permission scopes (
tokens.read
andtokens.write
) align perfectly with the PR's objective of introducing file tokens for resource access without requiring user sessions or public access. The addition to the admin role ensures proper administrative control over this new feature.tests/e2e/Services/Storage/StorageBase.php (1)
16-18
: Good addition of test categorization.The
@group fileTokens
annotation properly organizes the test into a relevant category, making it easier to run specific tests related to the new file tokens feature..github/workflows/tests.yml (1)
208-209
: Appropriate addition of Tokens service to test matrix.Adding the Tokens service to the shared mode test matrix ensures the new token functionality is properly tested in all database modes, which is critical for ensuring compatibility.
src/Appwrite/Platform/Modules/Storage/Module.php (1)
1-14
: Clean implementation of Storage Module.The implementation follows the platform's module pattern correctly by extending the base Module class and registering the necessary HTTP service. This module provides the glue needed to integrate the new token functionality into the storage platform.
app/controllers/general.php (3)
13-13
: Added import for Appwrite platform.This import is needed to support the platform initialization at the end of the file, which enables the new token management functionality.
46-46
: Added import for Platform Service.This import is necessary for the platform initialization that uses the Service::TYPE_HTTP constant.
1214-1215
: Platform initialization for token management.The code initializes the Appwrite platform with HTTP service type, enabling the new Storage module that provides token management capabilities for storage resources.
src/Appwrite/Platform/Workers/Migrations.php (1)
219-222
:✅ Verification successful
Added token management scopes to migration API key.
The API key generation method now includes additional scopes (
documents.write
,tokens.read
, andtokens.write
) to ensure migration workers have the necessary permissions to handle the new token resources.
🏁 Script executed:
#!/bin/bash # Check if these scopes are being used elsewhere in the codebase # to ensure consistency with other components echo "Checking for use of token scopes in the codebase..." rg "tokens\.read|tokens\.write" --type phpLength of output: 1253
Approve addition of token management scopes
Verified that
tokens.read
andtokens.write
are already defined inapp/config/scopes.php
andapp/config/roles.php
, and are used across storage modules and E2E tests. The new scopes insrc/Appwrite/Platform/Workers/Migrations.php
align with existing permissions and ensure migration workers can handle token resources.src/Appwrite/Platform/Appwrite.php (2)
6-6
: Added import for Storage module.This import is necessary to use the Storage module that contains the token management functionality.
14-14
: Registered Storage module to enable token management.This line registers the Storage module with the Appwrite platform, which adds the HTTP service containing token-related actions (create, get, list, update, delete).
app/config/scopes.php (1)
133-138
: Added new permission scopes for token management.Two new permission scopes are added:
tokens.read
: For reading project tokenstokens.write
: For creating, updating, and deleting project tokensThese scopes follow the established pattern for resource permissions and support the new token management feature.
tests/e2e/Services/Tokens/TokensCustomClientTest.php (1)
1-15
: Test class structure looks good.The TokensCustomClientTest class correctly extends Scope and uses the appropriate traits for testing token functionality in a custom client context.
tests/e2e/Services/Tokens/TokensConsoleClientTest.php (1)
1-14
: Test class structure follows project conventions.The TokensConsoleClientTest class properly extends Scope and uses the appropriate traits for testing token functionality in a console context.
src/Appwrite/SDK/Method.php (1)
90-97
: Optimization for file path validation.Good improvement that conditionally checks for file existence only when the description is a markdown file. This prevents unnecessary file path retrieval and validation operations.
src/Appwrite/Specification/Format/Swagger2.php (2)
176-178
: Enhanced description handling.This change properly handles both direct string descriptions and file-based descriptions, with sensible fallbacks. The empty string default for null descriptions and conditional file loading align well with the changes in Method.php.
185-185
: Description properly utilized.The description content is correctly assigned to the 'description' field in the specification.
src/Appwrite/Specification/Format/OpenAPI3.php (1)
180-182
: Code improvement for better readabilityThe refactoring improves code clarity by explicitly separating the description handling logic. Instead of embedding the file reading logic directly in the assignment statement, it now uses a separate variable
$descContents
with a clear conditional check for.md
file extensions.src/Appwrite/Platform/Modules/Storage/Services/Http.php (1)
1-28
: Well-structured HTTP service for token managementThe implementation follows a clean service-oriented architecture pattern, properly registering all necessary token-related actions in the constructor. This provides a clean API for file access tokens as described in the PR objectives.
src/Appwrite/Utopia/Response.php (4)
84-84
: Proper import for the new ResourceToken modelThe import statement is correctly placed in alphabetical order within the existing imports, maintaining code organization.
203-204
: Added constants for resource token modelsThese constants follow the naming convention used throughout the file and are properly placed in the Storage section of constants.
355-355
: Registered resource token list modelThe BaseList registration properly includes all required parameters for the collection, including an appropriate human-readable name.
427-427
: Added the ResourceToken model to the model registryThe model is added in the appropriate location among similar entity types, maintaining the organization of the code.
app/config/collections/projects.php (1)
1925-1996
: Well-defined schema for resource tokens collectionThe new collection schema for resource tokens follows best practices:
- Proper attribute definitions with appropriate data types and constraints
- The
secret
field uses the 'encrypt' filter for security- An index on the
expire
attribute will allow efficient querying and cleanup of expired tokensThis implementation aligns with the PR objective of enabling file access via tokens without requiring user sessions.
src/Appwrite/Utopia/Response/Model/ResourceToken.php (1)
1-71
: Well-designed model for resource tokensThe ResourceToken model is well-structured with appropriate field definitions, types, and documentation. The model supports the token authentication feature for accessing files.
src/Appwrite/Platform/Modules/Storage/Http/Tokens/Get.php (1)
1-65
: Clean implementation of token retrieval endpointThe Get token endpoint is well-implemented with proper parameter validation, error handling, and response formatting. The code follows the project's patterns for HTTP actions.
app/controllers/api/storage.php (6)
939-940
: Resource token dependency properly injectedThe resourceToken dependency is correctly injected into the file preview endpoint.
942-942
: Function signature updated to include resourceToken parameterThe action function signature is properly updated to include the resourceToken parameter.
957-958
: Token-based authorization check for bucket accessGood implementation of the token validation for bucket access, checking if the token matches the bucket's internal ID.
961-962
: Permission check updated to include token-based authorizationThe permission check is properly updated to allow access if a valid token is provided, maintaining backward compatibility with existing permission checks.
965-969
: File security check updated to include token-based authorizationThe file security check is properly updated to integrate token-based authorization alongside existing permission checks.
971-973
: File-specific token validationGood security practice to verify that the token specifically matches the requested file's internal ID, throwing an appropriate exception if not.
src/Appwrite/Platform/Modules/Storage/Http/Tokens/Delete.php (1)
72-75
: LGTM: Event queueing is properly implemented.The event queueing logic correctly captures the token information before deletion and prepares it for downstream processing.
src/Appwrite/Platform/Modules/Storage/Http/Tokens/Buckets/Files/Action.php (1)
31-35
: LGTM: Conditional retrieval logic is well implemented.The method correctly handles different file retrieval scenarios based on security settings and user permissions.
src/Appwrite/Platform/Modules/Storage/Http/Tokens/Buckets/Files/Create.php (1)
82-92
: Authorization guard ignores “update” permission on the token itself
You correctly check bucket/file permissions, but a user lackingupdate
on the token collection could still call this endpoint through the bucket/file route.
Consider adding:if (!Authorization::isRole(Role::any()) /* or specific check */) { throw new Exception(Exception::USER_UNAUTHORIZED); }app/config/specs/swagger2-latest-client.json (7)
5773-5774
: Minor weight update for messaging subscriber creation endpoint.The operation weight for the
messagingCreateSubscriber
function has been increased from 376 to 377. This is a simple configuration adjustment that likely reflects recalibration of API operation complexity.
5857-5858
: Minor weight update for messaging subscriber deletion endpoint.The operation weight for the
messagingDeleteSubscriber
function has been increased from 380 to 381. This is a simple configuration adjustment that likely reflects recalibration of API operation complexity.
7843-8047
: New API endpoints for token management (get, update, delete tokens).This introduces CRUD operations for individual tokens:
GET /tokens/{tokenId}
- fetch token detailsPATCH /tokens/{tokenId}
- update token properties (expiry, permissions)DELETE /tokens/{tokenId}
- delete a tokenThese endpoints follow RESTful design principles and are consistent with other API operations in the Appwrite ecosystem. The update endpoint allows for changing token expiration and permissions.
8048-8110
: New API endpoint for obtaining JWT representation of tokens.This endpoint (
GET /tokens/{tokenId}/jwt
) allows converting a resource token to a JWT format, which can be used for authentication purposes when accessing protected files. This is an important part of the token-based file access feature.
8327-8351
: New schema definition for resourceTokenList.This schema defines the structure for returning lists of resource tokens, following the same pattern as other list responses in the API. It includes
total
(count of tokens) andtokens
(array of token objects).
9559-9602
: New schema definition for resourceToken.This schema defines the structure of individual resource token objects with properties:
$id
: Token ID$createdAt
: Creation timestampresourceId
: Resource identifierresourceInternalId
: Internal ID of the resourceresourceType
: Type of resource (e.g., "file")expire
: Expiration date in ISO formatThe schema is well-structured and includes all necessary fields for token management.
7665-7842
:✅ Verification successful
New API endpoints for token management (list and create file tokens).
This introduces two new API endpoints for resource token management:
GET /tokens/buckets/{bucketId}/files/{fileId}
- for listing tokens for a specific filePOST /tokens/buckets/{bucketId}/files/{fileId}
- for creating a new file tokenThese endpoints allow developers to create and manage access tokens for files, enabling access to files without requiring a user session or making the file public.
Confirming that the query parameters for filtering tokens are properly aligned with the database schema:
🏁 Script executed:
#!/bin/bash # Check for other token-related schemas to ensure property naming consistency grep -r "resourceToken" ./app/config/specs/ --include="*.json" | grep propertiesLength of output: 80
🏁 Script executed:
#!/bin/bash # Locate the Swagger spec file SPEC_FILE=$(fd -t f swagger2-latest-client.json | head -n1) # Extract and display the properties of resourceToken and resourceTokenList definitions jq ' { resourceToken: .definitions.resourceToken.properties, resourceTokenList: .definitions.resourceTokenList.properties } ' "$SPEC_FILE"Length of output: 1545
Filtering parameter consistency verified
The GET
/tokens/buckets/{bucketId}/files/{fileId}
endpoint’squeries
parameter allows filtering on theexpire
attribute, which matches theexpire
property in theresourceToken
schema (type: string). No discrepancies found—filtering parameters align correctly with the API definitions.app/controllers/shared/api.php (2)
390-396
: InjectingresourceToken
– double‑check provider registration & nullable handling👍 The new dependency is injected correctly, but please confirm:
resourceToken
is registered inapp/init/resources.php
before this controller is built; otherwise the injection container will fail at runtime.- The provider must always return a
Document
instance (possibly empty) – nevernull* – because the action’s signature expects a non‑nullable
Document. If
nullis still a possible outcome, change the type to
?Document` both here and in the provider to avoid fatal errors.
569-571
: Early exit on mismatched token—good, but add strict checkGreat catch preventing cross‑file access!
Maintain consistency with the earlier bucket check and switch to===
for strict type matching.- if (!$resourceToken->isEmpty() && $resourceToken->getAttribute('fileInternalId') !== $file->getInternalId()) { + if (!$resourceToken->isEmpty() + && $resourceToken->getAttribute('fileInternalId') !== $file->getInternalId()) { // strict check already in use 👍 throw new Exception(Exception::USER_UNAUTHORIZED); }(No functional change needed; just pointing out the good strict comparison.)
app/config/specs/open-api3-latest-client.json (9)
5547-5548
: Change in weight parameter noted.The weight of the
messagingCreateSubscriber
endpoint has been increased by 1.
5629-5630
: Change in weight parameter noted.The weight of the
messagingDeleteSubscriber
endpoint has been increased by 1.
7462-7640
: New token listing and creation endpoints well-structured for file access.This introduces endpoints for listing and creating tokens for specific files. The implementation follows RESTful practices with appropriate parameters, request bodies, and response structures. The list method allows for filtering with queries, and the create method accepts expiry and permissions parameters.
7642-7843
: CRUD operations for tokens properly implemented.This section adds endpoints for getting, updating, and deleting tokens by their ID. The operations follow standard RESTful patterns and include appropriate documentation, parameters, and security requirements.
7845-7907
: JWT token retrieval endpoint appropriately designed.This endpoint for retrieving a token in JWT format follows best practices and includes proper documentation. The response returns the JWT in a standardized format that can be used for authentication.
8152-8174
: Resource token list schema properly defined.The schema for resource token lists properly defines the structure with total count and an array of tokens, consistent with other list object types in the API.
8372-8414
: Resource token schema correctly structured.The resource token schema includes all necessary fields: ID, timestamps, resource identifiers, type, and expiration. This structure aligns with other object schemas in the API and provides sufficient information for token management.
8395-8405
: Resource token schema properly defined with appropriate fields.The resource token schema includes all necessary information to properly identify and manage tokens. It follows the pattern of other Appwrite resources with standardized ID and timestamp fields.
7631-7711
:❓ Verification inconclusive
Verify the token update endpoint's functionality.
The token update endpoint allows updating expiry and permissions. Make sure these updates are properly validated, especially when changing expiry dates on already-issued tokens.
It's important to verify that:
- Tokens can't be updated to have invalid expiry dates
- Permissions can't be escalated beyond what the requesting user has
- Updates to tokens don't invalidate existing usages of those tokens unexpectedly
Run the following script to see if there's any validation logic for these operations:
🏁 Script executed:
#!/bin/bash # Search for token update validation logic rg -A 10 "function updateToken|class Token.*update" --type phpLength of output: 64
Verify token update endpoint validation
I wasn’t able to find any code handling validation for the
tokensUpdate
(PATCH) operation. Please ensure the following safeguards are in place in your token‑update logic:
- Tokens cannot be assigned invalid or past expiry dates.
- Permissions can’t be escalated beyond the requesting user’s existing scope.
- Applying updates doesn’t unintentionally invalidate tokens that should remain usable.
If the validation lives in a different module or middleware, double‑check it enforces these rules.
app/config/specs/swagger2-latest-server.json (2)
12353-16865
: Skip mechanical weight adjustments.These changes uniformly bump the
weight
values of existing API methods to account for the newly inserted token endpoints. They’re consistent and purely mechanical, so no further review is needed here.
26615-26617
: Correctly addedsecret
to the required properties.Including
secret
in therequired
array ensures this flag is always returned, which aligns with the new schema additions.app/config/specs/open-api3-latest-console.json (2)
19147-19148
: Enum update forproject region
Adding
"default"
to the region enum aligns with current platform defaults.
13188-18567
:✅ Verification successful
Verify
x-appwrite.weight
values for all endpointsMultiple endpoint weight values have been incremented to accommodate new routes. Please ensure all
x-appwrite.weight
fields remain unique and maintain the correct ordering. You can run:Expect no output—any duplicates must be resolved.
🏁 Script executed:
#!/usr/bin/env bash # Check for duplicate weight values jq -r '.. | .x-appwrite? | select(.weight) | .weight' app/config/specs/open-api3-latest-console.json \ | sort | uniq -c | awk '$1 > 1'Length of output: 269
Let’s correct the jq syntax to properly handle the
x-appwrite
key (you need to quote it, since hyphens aren’t valid in unquoted identifiers) and re‑check for duplicates:
🏁 Script executed:
#!/usr/bin/env bash # Check for duplicate x-appwrite.weight values jq -r ' .. | .["x-appwrite"]? | select(type=="object" and has("weight")) | .weight ' app/config/specs/open-api3-latest-console.json \ | sort \ | uniq -c \ | awk '$1 > 1'Length of output: 176
All
x-appwrite.weight
values are unique
Ran the duplicate‑check script againstapp/config/specs/open-api3-latest-console.json
and found no repeated weights—no further action needed.app/config/specs/swagger2-latest-console.json (2)
13438-19035
: Verify uniqueness of adjustedweight
attributes
The bulk updates to theweight
field across many endpoints appear consistent for ordering, but please ensure there are no duplicateweight
values and that the relative ordering reflects the intended placement in the console UI.
18204-18289
: Review new/migrations/csv
endpoint definition
The new CSV migration endpoint is well-defined with parameters, rate limits, and metadata. Please confirm alignment with server and client SDK documentation and add a link to the corresponding examples/docs.app/config/specs/open-api3-latest-server.json (4)
9949-9954
: Addsecret
flag for variable definitions
The newsecret
boolean property correctly indicates which variables are write‑only. Consider explicitly marking its nullability if needed (e.g.,"x-nullable": false
).
12099-12105
: Consistent weight metadata updates
All existing endpoints’weight
fields have been incremented by one to accommodate the insertion of the new tokens paths. The relative ordering appears correct and consistent across services.Also applies to: 12175-12181, 12319-12325, 12465-12471, 12639-12645, 12817-12823, 12926-12932, 13038-13044, 13091-13097, 13153-13159, 13228-13234, 13303-13309, 13379-13385, 13484-13490, 13592-13598, 13677-13683, 13765-13771, 13880-13886, 13998-14004, 14093-14099, 14191-14197, 14296-14302, 14404-14410, 14547-14553, 14692-14698, 14787-14793, 14885-14891, 14980-14986, 15078-15084, 15173-15179, 15271-15277, 15366-15372, 15464-15470, 15517-15523, 15579-15585, 15654-15660
26082-26086
: Approve addition ofsecret
in variable metadata
Thesecret
boolean is correctly added to indicate unreadable variables.
26101-26107
: Approve inclusion ofsecret
in required fields
Markingsecret
as required ensures consistency when creating/updating variables.
src/Appwrite/Platform/Modules/Storage/Http/Tokens/Buckets/Files/Action.php
Outdated
Show resolved
Hide resolved
src/Appwrite/Platform/Modules/Storage/Http/Tokens/Buckets/Files/Create.php
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 7
🔭 Outside diff range comments (4)
app/config/specs/open-api3-1.7.x-client.json (3)
4771-4772
:⚠️ Potential issueFix malformed URL in documentation reference.
There's an issue with the edit URL for this endpoint documentation. The URL is truncated and incorrectly includes the description text, which will lead to a broken link in the documentation.
Apply this fix:
- "edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterGet a list of all the current user function execution logs. You can use the query params to filter your results.", + "edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/list-executions.md",
4845-4846
:⚠️ Potential issueFix malformed URL in documentation reference.
Similar to the previous issue, the edit URL for this endpoint's documentation contains a truncated URL that incorrectly includes the description text.
Apply this fix:
- "edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterTrigger a function execution. The returned object will return you the current execution status. You can ping the `Get Execution` endpoint to get updates on the current execution status. Once this endpoint is called, your function execution process will start asynchronously.", + "edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/create-execution.md",
4959-4960
:⚠️ Potential issueFix malformed URL in documentation reference.
The edit URL for this endpoint documentation also has the same issue with truncation and incorrect inclusion of the description text.
Apply this fix:
- "edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/masterGet a function execution log by its unique ID.", + "edit": "https:\/\/github.com\/appwrite\/appwrite\/edit\/master\/docs\/references\/functions\/get-execution.md",app/config/specs/swagger2-1.7.x-server.json (1)
21631-21714
:⚠️ Potential issueFix malformed
edit
link and duplicated platforms for List Tokens
- The
edit
URL currently concatenatesmaster
directly with the description text. It should point to the spec file path and line range, for example:
https://github.com/appwrite/appwrite/edit/master/app/config/specs/swagger2-1.7.x-server.json#L21631-L21714
.- The
platforms
array lists"server"
twice—remove the duplicate.Proposed diff:
- "edit": "https://github.com/appwrite/appwrite/edit/masterList all the tokens created for a specific file or bucket. You can use the query params to filter your results.", + "edit": "https://github.com/appwrite/appwrite/edit/master/app/config/specs/swagger2-1.7.x-server.json#L21631-L21714", - "platforms": [ - "client", - "server", - "server" - ], + "platforms": [ + "client", + "server" + ],
♻️ Duplicate comments (11)
app/config/specs/open-api3-latest-console.json (2)
29594-29611
: Fix malformededit
URL and remove duplicateserver
platform entries
Thex-appwrite.edit
link is missing a slash and path segment (.../masterList...
), and theplatforms
array erroneously contains"server"
twice. Update to a correct edit URL and de-duplicate the platforms list so it reads:"edit": "https://github.com/appwrite/appwrite/edit/master/app/config/specs/open-api3-latest-console.json", "platforms": ["client", "server"]
37274-37317
:⚠️ Potential issueInclude
secret
andpermissions
inresourceToken
schema
TheresourceToken
schema currently lacks thesecret
(token value) andpermissions
fields, though the POST/PATCH endpoints accept and return them. Please add:"properties": { ... + "secret": { + "type": "string", + "description": "The secret token value used for authentication.", + "x-example": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." + }, + "permissions": { + "type": "array", + "description": "List of granted permission strings.", + "items": { "type": "string" }, + "x-example": ["read(\"any\")"] + } } "required": [ ... + "secret", + "permissions" ]This aligns the schema with the endpoint contracts and previous feedback.
app/config/specs/swagger2-latest-server.json (6)
21660-21660
: Fix malformedx-appwrite.edit
URL
Thex-appwrite.edit
value at line 21660 is missing a slash and the file path. It should point to the exact spec file and context (for example:https://github.com/appwrite/appwrite/edit/master/app/config/specs/swagger2-latest-server.json#L21631
).
21666-21669
: Remove duplicate platforms entries
Both thetokensList
andtokensCreateFileToken
operations list"server"
twice in their"platforms"
arrays. Please dedupe so each platform appears only once, and verify no other endpoints under/tokens
have the same issue.Also applies to: 21748-21752
21743-21743
: Fix malformedx-appwrite.edit
URL (POST)
Thex-appwrite.edit
for thetokensCreateFileToken
endpoint at line 21743 suffers from the same URL formatting issue. Update it to the correct GitHub edit link with the file path and line number.
21798-21801
: Escape JSON inx-example
for permissions
The example"[\"read(\"any\")\"]"
at lines 21798–21801 breaks JSON escaping due to unescaped inner quotes. Either escape the inner quotes ("[\"read(\\\"any\\\")\"]"
) or switch to single quotes inside ("['read(\"any\")']"
).
21949-21955
: Escape JSON inx-example
for permissions (PATCH)
ThetokensUpdate
endpoint’s payload example at lines 21949–21955 has the same unescaped-quote issue. Please apply the same fix.
28336-28340
: Addx-nullable: true
toexpire
Since a token may be created without an expiry date, theexpire
field in theresourceToken
schema must allownull
. Please add"x-nullable": true
under theexpire
property.app/config/specs/swagger2-latest-console.json (1)
37858-37901
: Includepermissions
andsecret
in theresourceToken
schema
TheresourceToken
model currently lacks the fields returned by the create/update endpoints. Per the API contract, add:"permissions": { "type": "array", "items": { "type": "string" }, "description": "Permissions granted by this token." }, "secret": { "type": "boolean", "description": "Indicates if this token is secret." }Additionally, if
expire
can be null (as the create payload allowsnull
), annotate it with"x-nullable": true
.app/config/specs/open-api3-latest-server.json (2)
21156-21165
: Fix edit URL and duplicate platforms in List Tokens endpoint
Thex-appwrite.edit
property for theGET /tokens/buckets/{bucketId}/files/{fileId}
operation is concatenating the description instead of pointing to the Markdown file (docs/references/tokens/list.md
), and theplatforms
array contains"server"
twice. Please update the edit URL to the correct docs path and remove the redundant"server"
entry.
27757-27791
: Add missingpermissions
field and markexpire
as nullable in ResourceToken schema
TheresourceToken
schema omits thepermissions
property (used by create/update endpoints), and theexpire
field lacks"x-nullable": true
to allow null expiry. These should be added to align the schema with the request/response models.
🧹 Nitpick comments (11)
app/config/specs/open-api3-1.7.x-server.json (1)
25166-25189
: EnhanceresourceTokenList
schema example & field formats
- The
x-example
for"tokens"
is empty—either supply a realistic array example of token objects or remove the placeholder.- Add
"format": "date-time"
to the"expire"
property for consistency with other date fields.app/config/specs/swagger2-1.7.x-client.json (2)
7657-7832
: New API endpoints for file token managementThis adds new endpoints for listing and creating tokens associated with specific files or buckets in storage, enabling fine-grained access control outside of user sessions.
The implementation properly includes:
- Query parameter filtering on token expiration
- Optional token expiration date that can be null
- Permission management through the permissions array
This token-based access mechanism is a significant architectural improvement as it enables secure, time-limited file sharing without requiring user authentication or making files completely public.
8039-8100
: JWT-based token retrieval mechanismThis endpoint allows converting a resource token to a JWT format, which is useful for authentication and verification.
Using JWT as a representation format provides significant benefits:
- Cryptographically signed for verification
- Can contain encoded permissions and metadata
- Compatible with standard authentication flows
- May be verified without database lookups (if implemented as stateless tokens)
app/config/specs/open-api3-latest-console.json (1)
34381-34388
: Provide a realisticx-example
fortokens
array
Thetokens
property’sx-example
is an empty string. Supplying an example array ofresourceToken
objects will improve documentation clarity:"x-example": [ { "$id": "bb8ea5c16897e", "$createdAt": "2020-10-15T06:38:00.000+00:00", "resourceId": "5e5ea5c168bb8:5e5ea5c168bb8", "resourceInternalId": "1:1", "resourceType": "file", "expire": "2020-10-15T06:38:00.000+00:00" } ]app/config/specs/swagger2-latest-server.json (1)
25691-25715
: Provide a realisticx-example
for the tokens array
TheresourceTokenList.tokens
property defines"x-example": ""
, which should represent an array. Consider changing this to an empty array ([]
) or a sample array of token objects (e.g.,[{ "$id": "abc", ... }]
) so consumers see the expected structure.app/config/specs/swagger2-latest-console.json (1)
34917-34941
: Provide a valid example for thetokens
array inresourceTokenList
schema
The current"x-example": ""
is not a meaningful example for an array type. Consider replacing it with a sample array of token objects, for example:"x-example": [ { "$id": "bb8ea5c16897e", "$createdAt": "2024-04-01T12:00:00.000+00:00", "resourceId": "5e5ea5c168bb8:5e5ea5c168bb8", "resourceInternalId": "1:1", "resourceType": "file", "expire": "2024-05-01T12:00:00.000+00:00", "permissions": ["read(any)"], "secret": false } ]app/config/specs/swagger2-latest-client.json (1)
7809-7828
: Consider adding validation description for the expire parameterWhile the implementation allows for nullable expiry dates, it would be helpful to include specific format requirements in the description. For example, mentioning that the date should be in ISO 8601 format and must be in the future.
- "expire": { - "type": "string", - "description": "Token expiry date", - "default": null, - "x-example": null, - "x-nullable": true - }, + "expire": { + "type": "string", + "description": "Token expiry date in ISO 8601 format. When set, the token will expire at the specified date. If not provided, the token will never expire.", + "default": null, + "x-example": "2025-10-15T06:38:00.000+00:00", + "x-nullable": true + },app/config/specs/open-api3-latest-server.json (1)
25176-25183
: Use a realistic example for thetokens
array
Thex-example
value for thetokens
property in theresourceTokenList
schema is currently an empty string. It would be more illustrative to provide an example array (e.g.,[]
or a sampleresourceToken
object) to demonstrate the expected structure.app/config/specs/swagger2-1.7.x-server.json (2)
25691-25715
: EnrichresourceTokenList
with a realistic example
Adding a concretex-example
for thetokens
array will make the schema more instructive. For instance:"tokens": { "type": "array", "description": "List of tokens.", - "items": { - "type": "object", - "$ref": "#/definitions/resourceToken" - }, - "x-example": "" + "items": { + "$ref": "#/definitions/resourceToken" + }, + "x-example": [ + { + "$id": "bb8ea5c16897e", + "$createdAt": "2025-04-01T12:00:00.000Z", + "resourceId": "bucket123:file456", + "resourceInternalId": "1:1", + "resourceType": "file", + "expire": "2025-05-01T12:00:00.000Z" + } + ] }
28307-28350
: ClarifyresourceInternalId
and improveexpire
example
- Rename the description of
resourceInternalId
from “File ID.” to “Resource internal ID.” for precision.- Update the
expire
field’sx-example
to a modern ISO 8601 timestamp:"resourceInternalId": { "type": "string", - "description": "File ID.", + "description": "Resource internal ID.", "x-example": "1:1" }, "expire": { "type": "string", "description": "Token expiration date in ISO 8601 format.", - "x-example": "2020-10-15T06:38:00.000+00:00" + "x-example": "2025-05-01T12:00:00.000Z" }.coderabbit.yaml (1)
6-6
: Add a newline at end of file.YAML parsers and linters generally expect a trailing newline. Please append a blank line after the last entry to satisfy the
new-line-at-end-of-file
rule.🧰 Tools
🪛 YAMLlint (1.35.1)
[error] 6-6: no new line character at the end of file
(new-line-at-end-of-file)
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (30)
.coderabbit.yaml
(1 hunks).github/workflows/tests.yml
(1 hunks)app/config/collections/projects.php
(1 hunks)app/config/errors.php
(1 hunks)app/config/roles.php
(1 hunks)app/config/scopes.php
(1 hunks)app/config/specs/open-api3-1.7.x-client.json
(11 hunks)app/config/specs/open-api3-1.7.x-server.json
(141 hunks)app/config/specs/open-api3-latest-client.json
(3 hunks)app/config/specs/open-api3-latest-console.json
(3 hunks)app/config/specs/open-api3-latest-server.json
(3 hunks)app/config/specs/swagger2-1.7.x-client.json
(11 hunks)app/config/specs/swagger2-1.7.x-server.json
(147 hunks)app/config/specs/swagger2-latest-client.json
(3 hunks)app/config/specs/swagger2-latest-console.json
(3 hunks)app/config/specs/swagger2-latest-server.json
(3 hunks)app/controllers/api/storage.php
(3 hunks)app/controllers/general.php
(1 hunks)app/controllers/shared/api.php
(2 hunks)app/init/resources.php
(1 hunks)src/Appwrite/Extend/Exception.php
(1 hunks)src/Appwrite/Platform/Appwrite.php
(2 hunks)src/Appwrite/Platform/Modules/Storage/Http/Tokens/Buckets/Files/Create.php
(1 hunks)src/Appwrite/Platform/Modules/Storage/Http/Tokens/Buckets/Files/XList.php
(1 hunks)src/Appwrite/Platform/Modules/Storage/Http/Tokens/Delete.php
(1 hunks)src/Appwrite/Platform/Modules/Storage/Http/Tokens/Get.php
(1 hunks)src/Appwrite/Platform/Modules/Storage/Http/Tokens/JWT/Get.php
(1 hunks)src/Appwrite/Platform/Modules/Storage/Http/Tokens/Update.php
(1 hunks)src/Appwrite/Platform/Workers/Migrations.php
(1 hunks)src/Appwrite/Utopia/Response.php
(4 hunks)
✅ Files skipped from review due to trivial changes (3)
- src/Appwrite/Extend/Exception.php
- app/controllers/general.php
- app/config/collections/projects.php
🚧 Files skipped from review as they are similar to previous changes (16)
- app/config/roles.php
- .github/workflows/tests.yml
- app/config/scopes.php
- src/Appwrite/Platform/Appwrite.php
- src/Appwrite/Platform/Workers/Migrations.php
- app/init/resources.php
- src/Appwrite/Platform/Modules/Storage/Http/Tokens/Delete.php
- src/Appwrite/Utopia/Response.php
- src/Appwrite/Platform/Modules/Storage/Http/Tokens/Get.php
- src/Appwrite/Platform/Modules/Storage/Http/Tokens/Buckets/Files/Create.php
- src/Appwrite/Platform/Modules/Storage/Http/Tokens/JWT/Get.php
- app/controllers/api/storage.php
- src/Appwrite/Platform/Modules/Storage/Http/Tokens/Update.php
- src/Appwrite/Platform/Modules/Storage/Http/Tokens/Buckets/Files/XList.php
- app/controllers/shared/api.php
- app/config/specs/open-api3-latest-client.json
🧰 Additional context used
🧬 Code Graph Analysis (1)
app/config/errors.php (1)
src/Appwrite/Extend/Exception.php (1)
Exception
(7-405)
🪛 YAMLlint (1.35.1)
.coderabbit.yaml
[error] 6-6: no new line character at the end of file
(new-line-at-end-of-file)
🔇 Additional comments (22)
app/config/errors.php (1)
491-502
: LGTM! Well-structured error definitions for the new token feature.The error definitions for TOKEN_NOT_FOUND and TOKEN_EXPIRED are properly structured and follow the existing patterns. The HTTP status codes (404 for not found and 401 for expired) are appropriate for these error conditions and align well with the token-based file access feature described in the PR objectives.
app/config/specs/open-api3-1.7.x-server.json (1)
8124-18427
: Descriptive & weight adjustments look consistent
The newly addeddescription
fields and updatedweight
values across the existing functions and sites endpoints follow the established patterns—descriptions are clear, weights are unique per tag group, and ordering is preserved.app/config/specs/swagger2-1.7.x-client.json (2)
7834-8100
: Token lifecycle management endpointsThese endpoints provide the core CRUD operations for token management - getting, updating, and deleting tokens by ID.
The implementation correctly:
- Uses standard HTTP methods (GET, PATCH, DELETE) for respective operations
- Includes proper authentication checks (JWT, Session, Project)
- Allows updating token permissions and expiration dates
- Returns appropriate status codes for each operation
9555-9598
: ResourceToken schema definitionThis defines the data structure for file access tokens with appropriate fields for resource identification and access control.
The schema properly includes:
- Standard Appwrite fields ($id, $createdAt)
- Resource identification (resourceId, resourceInternalId, resourceType)
- Token expiration date
This structured approach ensures tokens can be properly validated against the resources they're meant to access.
app/config/specs/swagger2-latest-client.json (6)
7657-7834
: New API endpoints for file access tokens provide enhanced security flexibilityThe addition of token-based access for storage files represents a valuable security enhancement to the platform. This implementation allows for more granular access control beyond simple public/private permissions, enabling time-bound access to files through tokens.
7835-8038
: Comprehensive token management API with proper documentationThe token management endpoints (get, update, delete) are well-structured and follow consistent API patterns. The documentation clearly explains each endpoint's purpose and parameters, maintaining the same format as other Appwrite APIs.
8039-8101
: JWT token conversion endpoint enhances integration optionsThis endpoint allows converting resource tokens to JWT format, which is valuable for integrating with other systems that support JWT authentication. The implementation follows security best practices by requiring proper authentication to generate the JWT.
8323-8347
: Well-structured resource token list definitionThe
resourceTokenList
definition follows the established pattern for list objects in Appwrite, making it consistent with other list responses in the API.
9555-9598
: Comprehensive resource token model with all necessary fieldsThe
resourceToken
definition includes all necessary fields for token management:
- Unique identifier
- Creation date
- Resource identifiers (both public and internal)
- Resource type specification
- Expiration date
This provides a complete representation of token objects for client interactions.
7765-7771
: Appropriate rate limiting for token creation operationsThe rate limit of 60 requests per minute provides a good balance between allowing legitimate usage while protecting against abuse. This is important for security-sensitive operations like token creation.
app/config/specs/open-api3-1.7.x-client.json (10)
4752-4752
: Good description of the function execution listing API.The updated description clearly explains the purpose of the endpoint to get a list of all current user function execution logs, and notes that query parameters can be used for filtering results.
4766-4767
: Weight value updated for function listing endpoint.The weight value is now set to 384 for the function listing endpoint. This weight value is used internally to manage API rate limiting and prioritization.
4825-4826
: Improved function execution description.The description clearly explains the purpose of the endpoint for triggering a function execution and provides good context about the returned execution status and asynchronous processing.
4840-4841
: Weight value updated for function execution creation.The weight value for the function execution creation endpoint has been updated to 382. This is used for internal rate limiting and API prioritization.
4939-4940
: Clear description for the function execution endpoint.The description clearly explains that this endpoint retrieves a function execution log by its unique ID.
4954-4955
: Weight value updated for function execution retrieval.The weight value for retrieving a function execution has been updated to 383, maintaining consistent weighting patterns with the other function endpoints.
5537-5538
: Weight value updated for subscriber creation.The weight value for the messaging subscriber creation endpoint has been updated to 349, which helps manage API prioritization and rate limiting.
5619-5620
: Weight value updated for subscriber deletion.The weight value for the messaging subscriber deletion endpoint has been updated to 353, maintaining consistency with other messaging endpoints.
7452-7896
: Added new token management endpoints for file access.This is a substantial addition that implements a complete set of endpoints for token-based file access, including:
- List tokens for a specific file or bucket
- Create file tokens with customizable expiry and permissions
- Retrieve, update, and delete tokens
- Generate JWT representations of tokens
This implementation matches the PR objective of enabling access to files via tokens without requiring files to be public or a user session with appropriate permissions.
The endpoints are well-designed with appropriate security controls, rate limiting, and follow RESTful patterns. The permissions are correctly scoped using
tokens.read
andtokens.write
which will need to be registered in the roles and scopes configuration.
8146-8409
: Added schema definitions for resource tokens.These schema definitions properly describe the structure of resource tokens and token lists, including all necessary properties:
resourceToken
: Defines a token with ID, creation date, resource identifiers, type, and expiry dateresourceTokenList
: Defines a paginated list of tokens with total countThe schemas are well-structured and include all necessary fields to support the token management API endpoints.
app/config/specs/swagger2-1.7.x-server.json (1)
8271-19325
: Skip repeated description and weight updates
These hunks uniformly adjust descriptions andx-appwrite.weight
metadata across existingfunctions
,sites
, and related endpoints. They are non‑functional, stylistic tweaks that follow the same pattern and don’t introduce behavior changes..coderabbit.yaml (1)
4-6
: Confirm the addition of the1.7.x
base branch.You’ve correctly inserted
1.7.x
after1.6.x
to target the upcoming release line. Please verify that the1.7.x
branch exists and that the order here aligns with any CI/CD workflows that rely on branch declaration order.🧰 Tools
🪛 YAMLlint (1.35.1)
[error] 6-6: no new line character at the end of file
(new-line-at-end-of-file)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
.coderabbit.yaml (1)
11-11
: Add trailing newline at end‑of‑file
YAML files should end with a newline character to satisfy linting rules (new-line-at-end-of-file
) and prevent subtle parsing issues.🧰 Tools
🪛 YAMLlint (1.35.1)
[error] 11-11: no new line character at the end of file
(new-line-at-end-of-file)
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (6)
app/config/specs/open-api3-latest-client.json
is excluded by!app/config/specs/**
app/config/specs/open-api3-latest-console.json
is excluded by!app/config/specs/**
app/config/specs/open-api3-latest-server.json
is excluded by!app/config/specs/**
app/config/specs/swagger2-latest-client.json
is excluded by!app/config/specs/**
app/config/specs/swagger2-latest-console.json
is excluded by!app/config/specs/**
app/config/specs/swagger2-latest-server.json
is excluded by!app/config/specs/**
📒 Files selected for processing (8)
.coderabbit.yaml
(1 hunks).github/workflows/tests.yml
(1 hunks)app/controllers/general.php
(1 hunks)app/controllers/shared/api.php
(2 hunks)app/init/resources.php
(1 hunks)src/Appwrite/Platform/Appwrite.php
(2 hunks)src/Appwrite/Utopia/Response.php
(4 hunks)tests/e2e/Scopes/ProjectCustom.php
(1 hunks)
✅ Files skipped from review due to trivial changes (1)
- app/controllers/general.php
🚧 Files skipped from review as they are similar to previous changes (6)
- tests/e2e/Scopes/ProjectCustom.php
- src/Appwrite/Platform/Appwrite.php
- .github/workflows/tests.yml
- src/Appwrite/Utopia/Response.php
- app/init/resources.php
- app/controllers/shared/api.php
🧰 Additional context used
🪛 YAMLlint (1.35.1)
.coderabbit.yaml
[error] 11-11: no new line character at the end of file
(new-line-at-end-of-file)
⏰ Context from checks skipped due to timeout of 90000ms (3)
- GitHub Check: Setup & Build Appwrite Image
- GitHub Check: Setup & Build Console SDK
- GitHub Check: scan
🔇 Additional comments (1)
.coderabbit.yaml (1)
11-11
: Approve addition of1.7.x
toauto_review.base_branches
The updated branch ordering (main
,1.6.x
,1.7.x
) correctly reflects the project’s versioning progression and ensures that automatic reviews will include the new release line.🧰 Tools
🪛 YAMLlint (1.35.1)
[error] 11-11: no new line character at the end of file
(new-line-at-end-of-file)
What does this PR do?
Accessing files currently requires either files to be public or need user session with user that have access permission. It's mainly painful for image previews that we want to show publicly. For this reason, we want to introduce file tokens. The tokens will be linked to specific file and will be passed in URL for previews and downloads to provide access.
Test Plan
Added required tests.
Related PRs and Issues
Checklist
Summary by CodeRabbit
New Features
tokens.read
,tokens.write
) and updated roles to manage tokens.Bug Fixes
Tests
Documentation
Chores