Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ On the client side, you can now call the method by calling:
var result = await client.example.hello('World');
```

The client is initialized like this:
Initialize the generated client once and keep it somewhere that the rest of your app can reuse, such as a service locator:

```dart
// Sets up a singleton client object that can be used to talk to the server from
Expand All @@ -57,7 +57,7 @@ var client = Client('http://localhost:8080/')

If you run the app in an Android emulator, use `10.0.2.2` instead of `localhost`, since `10.0.2.2` is the IP address of the host machine from inside the emulator. To access the server from a different device on the same network (such as a physical phone), replace `localhost` with the local IP address of your machine. You can find the local IP by running `ifconfig` (Linux/macOS) or `ipconfig` (Windows).

Make sure to also update the `publicHost` in the development config to make sure the server always serves the client with the correct path to assets etc.
Make sure to also update the `publicHost` in the development config so the server always serves the client with the correct path to assets and other resources.

```yaml
# your_project_server/config/development.yaml
Expand All @@ -69,6 +69,8 @@ apiServer:
publicScheme: http
```

See [Configure HTTP calls](./working-with-endpoints/configure-http-calls) for transport-specific configuration such as browser credentials or platform-native HTTP clients.

## Passing parameters

There are some limitations to how endpoint methods can be implemented. Parameters and return types can be of type `bool`, `int`, `double`, `String`, `UuidValue`, `Duration`, `DateTime`, `ByteData`, `Uri`, `BigInt`, or generated serializable objects (see next section). A typed `Future` should always be returned. Null safety is supported. When passing a `DateTime` it is always converted to UTC.
Expand Down
114 changes: 114 additions & 0 deletions docs/06-concepts/01-working-with-endpoints/03-configure-http-calls.md
Comment thread
marcelomendoncasoares marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# Configure HTTP calls

The generated `Client` accepts an optional `httpClientOverride` parameter that controls the underlying HTTP transport used for API calls. Use it when you need to customize how requests are sent, such as enabling browser credentials or using platform-native HTTP stacks.

## Include CORS credentials on web

By default, browser requests do not include cookies or HTTP authentication credentials in cross-origin requests. If your app relies on cookie-based sessions or similar mechanisms, pass a `BrowserClient` with `withCredentials` enabled:

```dart
import 'package:http/browser_client.dart';

final client = Client(
serverUrl,
httpClientOverride: BrowserClient()..withCredentials = true,
);
```

On the server, Serverpod adds CORS headers to API responses by default through `httpResponseHeaders` and `httpOptionsResponseHeaders` on the `Serverpod` constructor. The defaults allow cross-origin `POST` requests from any origin (`Access-Control-Allow-Origin: *`) and permit common request headers such as `Authorization` on preflight `OPTIONS` requests.

Credential-aware requests require stricter headers: the browser rejects `Access-Control-Allow-Origin: *` when credentials are included, and the server must respond with `Access-Control-Allow-Credentials: true` and a specific origin. Override the defaults in your `lib/server.dart` (or wherever you construct `Serverpod`):

```dart
import 'package:serverpod/serverpod.dart';

import 'src/generated/protocol.dart';
import 'src/generated/endpoints.dart';

/// The starting point of the Serverpod server.
void run(List<String> args) async {
// Initialize Serverpod and connect it with your generated code.
final pod = Serverpod(
args,
Protocol(),
Endpoints(),
httpResponseHeaders: Headers.build((mh) {
mh.accessControlAllowOrigin = AccessControlAllowOriginHeader.origin(
origin: Uri.parse('http://localhost:49660'), // Your Flutter web app origin
);
mh.accessControlAllowCredentials = true;
mh.accessControlAllowMethods = AccessControlAllowMethodsHeader.methods(
[Method.post],
);
}),
httpOptionsResponseHeaders: Headers.build((mh) {
mh.accessControlAllowHeaders = AccessControlAllowHeadersHeader.headers([
'Content-Type',
'Authorization',
'Accept',
'User-Agent',
'X-Requested-With',
]);
}),
);

// Start the server
await pod.start();
}
```

Set `origin` to the exact origin of your Flutter web app (scheme, host, and port). In production, list each allowed origin explicitly.

## Use platform-native HTTP clients

You can also override the default HTTP client with a platform-native HTTP client. On iOS and macOS, you can use [cupertino_http](https://pub.dev/packages/cupertino_http) to route traffic through `NSURLSession`. On Android, you can use [cronet_http](https://pub.dev/packages/cronet_http) to use the Cronet network stack.

Below is an example of how to override the default HTTP client with platform-native HTTP clients.

```dart
import 'dart:io';

import 'package:cronet_http/cronet_http.dart';
import 'package:cupertino_http/cupertino_http.dart';
import 'package:http/http.dart' as http;

import 'package:my_project_client/my_project_client.dart';

void main() async {
http.Client? httpClient;

if (Platform.isAndroid) {
final engine = CronetEngine.build(
cacheMode: CacheMode.memory,
cacheMaxSize: 2 * 1024 * 1024,
userAgent: 'Book Agent');
httpClient = CronetClient.fromCronetEngine(engine, closeEngine: true);
} else if (Platform.isIOS || Platform.isMacOS) {
final config = URLSessionConfiguration.ephemeralSessionConfiguration()
..cache = URLCache.withCapacity(memoryCapacity: 2 * 1024 * 1024)
..httpAdditionalHeaders = {'User-Agent': 'Book Agent'};
httpClient = CupertinoClient.fromSessionConfiguration(config);
}

final client = Client(
serverUrl,
httpClientOverride: httpClient,
);
}
```

### Support web with conditional imports

The above example does not work if your app also targets web, since `dart:io` is not available there. Put the platform-specific `http.Client` creation logic behind a conditional import instead:

```dart
import 'src/http_client_stub.dart'
if (dart.library.io) 'src/http_client_io.dart';

final client = Client(
serverUrl,
httpClientOverride: createHttpClient(),
);
```

Add the corresponding package to your Flutter app's `pubspec.yaml` before using these clients.
27 changes: 24 additions & 3 deletions docs/06-concepts/21-security-configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@

:::info

In a **production environment**, TLS termination is **normally handled by a load balancer** or **reverse proxy** (e.g., Nginx, AWS ALB, or Cloudflare).
In a **production environment**, TLS termination is **normally handled by a load balancer** or **reverse proxy** (e.g., Nginx, AWS ALB, or Cloudflare).
However, Serverpod also supports setting up **TLS/SSL directly on the server**, allowing you to provide your own certificates if needed.

:::

Serverpod supports **TLS/SSL security configurations** through the **Dart configuration object**.
Serverpod supports **TLS/SSL security configurations** through the **Dart configuration object**.
To enable SSL/TLS, you must pass a **`SecurityContextConfig`** to the `Serverpod` constructor.

## Server Security Configuration
Expand Down Expand Up @@ -45,10 +45,31 @@ To enable SSL/TLS when using the Serverpod client, pass a **`SecurityContext`**
final securityContext = SecurityContext()
..setTrustedCertificates('path/to/server_cert.pem');


final client = Client(
'https://yourserver.com',
securityContext: securityContext,
...
);
```

#### Using `SecurityContext` with `httpClientOverride`

If you use the [`httpClientOverride` parameter](./working-with-endpoints/configure-http-calls), provide the security context through the HTTP client you pass in. You cannot set `securityContext` and `httpClientOverride` on the same `Client` instance.

For example, on `dart:io` platforms you can create an `HttpClient` with your trusted certificates and wrap it in an `IOClient`:

```dart
import 'dart:io';

import 'package:http/io_client.dart';

final securityContext = SecurityContext()
..setTrustedCertificates('path/to/server_cert.pem');

final client = Client(
'https://yourserver.com',
httpClientOverride: IOClient(
HttpClient(context: securityContext),
),
);
```
Loading