Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/format.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:

steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
persist-credentials: true
ref: ${{ github.event.pull_request.head.ref }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
id-token: write
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v6
- name: Install Flutter
uses: subosito/flutter-action@v2
with:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v6
- name: Install Flutter
uses: subosito/flutter-action@v2
with:
Expand Down
13 changes: 10 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
# Change Log

## 24.1.0

* Added: Added `setCookie()` method to `Client`, `ClientIO`, and `ClientBrowser` for forwarding incoming `Cookie` headers in server-side runtimes
* Added: Added `fusionauth`, `keycloak`, and `kick` OAuth providers to `OAuthProvider` enum
* Updated: Updated `X-Appwrite-Response-Format` header to `1.9.4`
* Updated: Reformatted generated code to use 4-space indentation

## 24.0.0

* Breaking: Added `unsubscribe()`, `update()`, and `close()` for Realtime subscription lifecycle.
* Added: Added `userPhone` to the `Membership` model.
* Updated: Updated `X-Appwrite-Response-Format` header to `1.9.2`.
* Breaking: Added `unsubscribe()`, `update()`, and `close()` to Realtime subscriptions
* Added: Added `userPhone` field to `Membership` model
* Updated: Updated `X-Appwrite-Response-Format` header to `1.9.2`

## 23.1.0

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Add this to your package's `pubspec.yaml` file:

```yml
dependencies:
appwrite: ^24.0.0
appwrite: ^24.1.0
```

You can install packages from the command line:
Expand Down
5 changes: 5 additions & 0 deletions lib/src/client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ abstract class Client {
/// Your secret dev API key.
Client setDevKey(String value);

/// Set Cookie.
///
/// The user cookie to authenticate with. Used by SDKs that forward an incoming Cookie header in server-side runtimes..
Client setCookie(String value);
Comment on lines +84 to +85
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 Double period at end of doc comment.

Suggested change
/// The user cookie to authenticate with. Used by SDKs that forward an incoming Cookie header in server-side runtimes..
Client setCookie(String value);
/// The user cookie to authenticate with. Used by SDKs that forward an incoming Cookie header in server-side runtimes.
Client setCookie(String value);


/// Set ImpersonateUserId.
///
/// Impersonate a user by ID on an already user-authenticated request. Requires the current request to be authenticated as a user with impersonator capability; X-Appwrite-Key alone is not sufficient. Impersonator users are intentionally granted users.read so they can discover a target before impersonation begins. Internal audit logs still attribute actions to the original impersonator and record the impersonated target only in internal audit payload data..
Expand Down
4 changes: 4 additions & 0 deletions lib/src/client_base.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ abstract class ClientBase implements Client {
@override
ClientBase setDevKey(value);

/// The user cookie to authenticate with. Used by SDKs that forward an incoming Cookie header in server-side runtimes.
@override
ClientBase setCookie(value);

/// Impersonate a user by ID on an already user-authenticated request. Requires the current request to be authenticated as a user with impersonator capability; X-Appwrite-Key alone is not sufficient. Impersonator users are intentionally granted users.read so they can discover a target before impersonation begins. Internal audit logs still attribute actions to the original impersonator and record the impersonated target only in internal audit payload data.
@override
ClientBase setImpersonateUserId(value);
Expand Down
12 changes: 10 additions & 2 deletions lib/src/client_browser.dart
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ class ClientBrowser extends ClientBase with ClientMixin {
'x-sdk-name': 'Flutter',
'x-sdk-platform': 'client',
'x-sdk-language': 'flutter',
'x-sdk-version': '24.0.0',
'X-Appwrite-Response-Format': '1.9.2',
'x-sdk-version': '24.1.0',
'X-Appwrite-Response-Format': '1.9.4',
};

config = {};
Expand Down Expand Up @@ -95,6 +95,14 @@ class ClientBrowser extends ClientBase with ClientMixin {
return this;
}

/// The user cookie to authenticate with. Used by SDKs that forward an incoming Cookie header in server-side runtimes.
@override
ClientBrowser setCookie(value) {
config['cookie'] = value;
addHeader('Cookie', value);
return this;
}
Comment on lines +98 to +104
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 Cookie is a forbidden header in browsers

Cookie is on the Fetch spec's forbidden header list, so browsers silently discard it when sent via fetch or XMLHttpRequest. Calling setCookie() on ClientBrowser will store the value in config but the header will never reach the server. This is likely acceptable since the method is documented as being for server-side runtimes, but a guard or debugPrint warning when this is called in a browser context would prevent silent mis-use.


/// Impersonate a user by ID on an already user-authenticated request. Requires the current request to be authenticated as a user with impersonator capability; X-Appwrite-Key alone is not sufficient. Impersonator users are intentionally granted users.read so they can discover a target before impersonation begins. Internal audit logs still attribute actions to the original impersonator and record the impersonated target only in internal audit payload data.
@override
ClientBrowser setImpersonateUserId(value) {
Expand Down
12 changes: 10 additions & 2 deletions lib/src/client_io.dart
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ class ClientIO extends ClientBase with ClientMixin {
'x-sdk-name': 'Flutter',
'x-sdk-platform': 'client',
'x-sdk-language': 'flutter',
'x-sdk-version': '24.0.0',
'X-Appwrite-Response-Format': '1.9.2',
'x-sdk-version': '24.1.0',
'X-Appwrite-Response-Format': '1.9.4',
};

config = {};
Expand Down Expand Up @@ -121,6 +121,14 @@ class ClientIO extends ClientBase with ClientMixin {
return this;
}

/// The user cookie to authenticate with. Used by SDKs that forward an incoming Cookie header in server-side runtimes.
@override
ClientIO setCookie(value) {
config['cookie'] = value;
addHeader('Cookie', value);
return this;
}
Comment on lines +124 to +130
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 setCookie conflicts with CookieManager interceptor

addHeader('Cookie', value) stores the manual cookie as the key 'Cookie' in _headers. During call(), the CookieManager interceptor then runs request.headers.addAll({HttpHeaders.cookieHeader: cookie}) (using the lowercase key 'cookie'). Because http.BaseRequest.headers is a case-sensitive Map<String, String>, both entries co-exist, but when IOClient forwards them to dart:io's HttpHeaders.set() — which is case-insensitive — the last write for the canonical cookie header wins. The outcome (which value is kept) depends on iteration order and is non-deterministic across Dart versions. In a non-empty cookie jar scenario the forwarded cookie may be silently dropped or partially overwritten by jar cookies.


/// Impersonate a user by ID on an already user-authenticated request. Requires the current request to be authenticated as a user with impersonator capability; X-Appwrite-Key alone is not sufficient. Impersonator users are intentionally granted users.read so they can discover a target before impersonation begins. Internal audit logs still attribute actions to the original impersonator and record the impersonated target only in internal audit payload data.
@override
ClientIO setImpersonateUserId(value) {
Expand Down
3 changes: 3 additions & 0 deletions lib/src/enums/o_auth_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,12 @@ enum OAuthProvider {
etsy(value: 'etsy'),
facebook(value: 'facebook'),
figma(value: 'figma'),
fusionauth(value: 'fusionauth'),
github(value: 'github'),
gitlab(value: 'gitlab'),
google(value: 'google'),
keycloak(value: 'keycloak'),
kick(value: 'kick'),
linkedin(value: 'linkedin'),
microsoft(value: 'microsoft'),
notion(value: 'notion'),
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: appwrite
version: 24.0.0
version: 24.1.0
description: Appwrite is an open-source self-hosted backend server that abstracts and simplifies complex and repetitive development tasks behind a very simple REST API
homepage: https://appwrite.io
repository: https://github.com/appwrite/sdk-for-flutter
Expand Down