Docs

Client to Server Auth

You can extend Appwrite's APIs by building backend apps using Server SDKs. To secure your backend app's APIs, client apps must prove their identity against your backend app before accessing sensitive information. You can secure these APIs and enforce access permissions in your backend app by using JWT authentication.

If you are already authenticated on your client-side app and need your backend app to act on behalf of the user, this guide will walk you through the process.

Proof of Identity

Before making requests to your backend APIs, your client application needs to first create a session directly with Appwrite using the account service. This session will act like an ID card for the user and can be used to access resources in Appwrite. The client will only receive information accessible to the user based on the resources's permissions.

When you build backend APIs to extend Appwrite's functionality, these APIs should still respect access permissions to keep user data secure. Appwrite's backend SDKs allows you to securely act on behalf of a user with the same permissions by using JWT authentication.

JWT Authentication

JSON Web Tokens (JWTs) are a secure means to transfer information or claims between two parties. JWT act like temporary copies of the user's ID card that allow Appwrite's Server SDKs to access information oh behalf of a user.

You need to create a session using the Client SDKs before generating a JWT. The JWT will be a stateless proof of claim for the identity of the authenticated user and expire after 15 minutes or when the session is deleted.

You can generate a JWT like this:

  • Web

    import { Client, Account } from "appwrite";
    
    const client = new Client()
        .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
        .setProject('[PROJECT_ID]');               // Your project ID
    
    const account = new Account(client);
    
    const promise = account.createJWT();
    
    promise.then(function (response) {
        console.log(response);
    }, function (error) {
        console.log(error);
    });
  • Flutter

    import 'package:appwrite/appwrite.dart';
    
    final client = Client()
        .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
        .setProject('[PROJECT_ID]');               // Your project ID
    
    final account = Account(client);
    
    final jwt = await account.createJWT();
    
     
  • Android

    import io.appwrite.Client
    import io.appwrite.services.Account
    
    val client = Client(context)
        .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
        .setProject("[PROJECT_ID]")                // Your project ID
    
    val account = Account(client)
    
    val jwt = account.createJWT()
  • Apple

    import Appwrite
    
    let client = Client()
        .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
        .setProject("[PROJECT_ID]")                // Your project ID
    
    let account = Account(client)
    
    let jwt = try await account.createJWT()
  • GraphQL

    mutation {
        accountCreateJWT {
            jwt
        }
    }

Your server application can use the JWT to act on behalf of the user by creating a Client instance with the JWT for each request it receives. To keep your API secure, discard the client object after each request.

  • Node.js

    const { Client } = require('node-appwrite');
    
    const client = new Client();
    
    client
        .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
        .setProject('[PROJECT_ID]')                // Your project ID
        .setJWT('eyJJ9.eyJ...886ca');               // Your secret JSON Web Token
  • PHP

    use Appwrite\Client;
    
    $client = new Client();
    
    $client
        ->setEndpoint('https://cloud.appwrite.io/v1')            // Your API Endpoint
        ->setProject('[PROJECT_ID]')                           // Your project ID
        ->setJWT('eyJJ9.eyJ...886ca');                          // Your secret JSON Web Token
  • Python

    from appwrite.client import Client
    
    client = Client()
    
    (client
      .set_endpoint('https://cloud.appwrite.io/v1')              # Your API Endpoint
      .set_project('[PROJECT_ID]')                             # Your project ID
      .set_jwt('eyJJ9.eyJ...886ca')                             # Your secret JSON Web Token
    )
  • Ruby

    require 'appwrite'
    
    include Appwrite
    
    client = Client.new
    
    client
        .set_endpoint('https://cloud.appwrite.io/v1')            # Your API Endpoint
        .set_project('[PROJECT_ID]')                           # Your project ID
        .set_jwt('eyJJ9.eyJ...886ca')                           # Your secret JSON Web Token
  • Deno

    import { Client } from "https://deno.land/x/appwrite/mod.ts";
    
    let client = new Client();
    
    client
        .setEndpoint('https://cloud.appwrite.io/v1')             // Your API Endpoint
        .setProject('[PROJECT_ID]')                            // Your project ID
        .setJWT('eyJJ9.eyJ...886ca');                           // Your secret JSON Web Token
  • Dart

    import 'package:dart_appwrite/dart_appwrite.dart';
    
    final client = Client();
    
    client
        .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
        .setProject('[PROJECT_ID]')                // Your project ID
        .setJWT('eyJJ9.eyJ...886ca');               // Your secret JSON Web Token
  • Kotlin

    import io.appwrite.Client
    
    val client = Client()
    
    client
        .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
        .setProject("[PROJECT_ID]")                // Your project ID
        .setJWT("eyJJ9.eyJ...886ca")                // Your secret JSON Web Token
  • Swift

    import Appwrite
    
    let client = Client()
    
    client
        .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
        .setProject("[PROJECT_ID]")                // Your project ID
        .setJWT("eyJJ9.eyJ...886ca")                // Your secret JSON Web Token

When Should I Use JWT Auth?

JWT auth is useful when you need your backend app's Server SDK to be restricted by the same set of permissions.

If your backend app's Server SDK is using an API key, it will fetch all resources reguardless of permissions. This means the Server SDK might fetch files and documents your user should not be able to see, which is not helpful when you need to act on behalf of a user.

If your backend app's Server SDK is using a JWT, it will only fetch resources your user has permissions to access.

Example

Here's an example collection of birthdays with the following documents. Notice how they all have different permissions.

$id name birthday $permissions
ac5fc866ad1e Kevin 2012-02-03 "read(\"user:user-a\")"
bc7fc866ad1e Laura 1999-09-22 "read(\"user:user-b\")"
cc2fc886ad1e Bob 1982-05-11 "read(\"user:user-c\")"

If you're authenticated on the client-side as user-a and created a JWT 'eyJJ9.eyJ...886ca', you can pass this JWT to a Server SDK on the backend server to fetch only the birthdays user-a can read.

  • Node.js

    const { Client } = require('node-appwrite');
    
    const client = new Client();
    
    client
        .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
        .setProject('[PROJECT_ID]')                // Your project ID
        .setJWT('eyJJ9.eyJ...886ca');               // Your secret JSON Web Token
    
    const databases = new sdk.Databases(client);
    
    const birthday = await databases.listDocuments('642f358bf4084c662590', '642f3592aa5fc856ad1e');
    // ... More code to manipulate the results
  • PHP

    use Appwrite\Client;
    
    $client = new Client();
    
    $client
        ->setEndpoint('https://cloud.appwrite.io/v1')            // Your API Endpoint
        ->setProject('[PROJECT_ID]')                           // Your project ID
        ->setJWT('eyJJ9.eyJ...886ca');                          // Your secret JSON Web Tokens
    
    $databases = new Databases($client);
    
    $result = $databases->listDocuments('642f358bf4084c662590', '642f3592aa5fc856ad1e');
    // ... More code to manipulate the results
  • Python

    from appwrite.client import Client
    
    client = Client()
    
    (client
      .set_endpoint('https://cloud.appwrite.io/v1')              # Your API Endpoint
      .set_project('[PROJECT_ID]')                             # Your project ID
      .set_jwt('eyJJ9.eyJ...886ca')                             # Your secret JSON Web Token
    )
    
    databases = Databases(client)
    
    result = databases.list_documents('642f358bf4084c662590', '642f3592aa5fc856ad1e')
    # ... More code to manipulate the results
  • Ruby

    require 'appwrite'
    
    include Appwrite
    
    client = Client
    
    client.new
        .set_endpoint('https://cloud.appwrite.io/v1')            # Your API Endpoint
        .set_project('[PROJECT_ID]')                           # Your project ID
        .set_jwt('eyJJ9.eyJ...886ca')                           # Your secret JSON Web Token
    
    databases = Databases.new(client)
    
    response = databases.list_documents(database_id: '642f358bf4084c662590', '642f3592aa5fc856ad1e')
    # ... More code to manipulate the results
  • Deno

    import { Client } from "https://deno.land/x/appwrite/mod.ts";
    
    let client = new Client();
    
    client
        .setEndpoint('https://cloud.appwrite.io/v1')             // Your API Endpoint
        .setProject('[PROJECT_ID]')                            // Your project ID
        .setJWT('eyJJ9.eyJ...886ca');                           // Your secret JSON Web Token
    
    let databases = new sdk.Databases(client);
    
    let promise = databases.listDocuments('642f358bf4084c662590', '642f3592aa5fc856ad1e');
    // ... More code to manipulate the results
  • Dart

    import 'package:dart_appwrite/dart_appwrite.dart';
    
    final client = Client();
    
    client
        .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
        .setProject('[PROJECT_ID]')                // Your project ID
        .setJWT('eyJJ9.eyJ...886ca');               // Your secret JSON Web Token
    
    Databases databases = Databases(client);
    
    Future result = databases.listDocuments(
        databaseId: '642f358bf4084c662590',
        collectionId: '642f3592aa5fc856ad1e',
    );
    // ... More code to manipulate the results
  • Kotlin

    import io.appwrite.Client
    
    val client = Client()
    
    client
        .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
        .setProject("[PROJECT_ID]")                // Your project ID
        .setJWT("eyJJ9.eyJ...886ca")                // Your secret JSON Web Token
    
    val databases = Databases(client)
    
    val response = databases.listDocuments(
        databaseId = "642f358bf4084c662590",
        collectionId = "642f3592aa5fc856ad1e",
    )
    // ... More code to manipulate the results
  • Swift

    import Appwrite
    
    let client = Client()
    
    client
        .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
        .setProject("[PROJECT_ID]")                // Your project ID
        .setJWT("eyJJ9.eyJ...886ca")                // Your secret JSON Web Token
        
    let databases = Databases(client)
    
    let documentList = try await databases.listDocuments(
        databaseId: "642f358bf4084c662590",
        collectionId: "642f3592aa5fc856ad1e"
    )
    / ... More code to manipulate the results

Only the birthday of Kevin is returned and documents where user-A has no permissions to access are not returned.

{
  "total": 1,
  "documents": [
    {
      "name": "Kevin",
      "birthday": "2012-02-03T00:00:00.000+00:00",
      "$id": "ac5fc866ad1e",
      "$permissions": [
        "read(\"user:user-a\")"
      ],
      "$collectionId": "642f3592aa5fc856ad1e",
      "$databaseId": "642f358bf4084c662590",
      ...
    }
  ]
}

If the same request is made where the Server SDK's client is authenticate with an API key instead of a JWT, the results returned will be different.

  • Node.js

    const { Client } = require('node-appwrite');
    
    const client = new Client();
    
    client
        .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
        .setProject('[PROJECT_ID]')                // Your project ID
        .setKey('919c2d18fb5d4...a2ae413da83346ad2')// Your secret API key
    
    const databases = new sdk.Databases(client);
    
    const birthday = await databases.listDocuments('642f358bf4084c662590', '642f3592aa5fc856ad1e');
    // ... More code to manipulate the results
  • PHP

    use Appwrite\Client;
    
    $client = new Client();
    
    $client
        ->setEndpoint('https://cloud.appwrite.io/v1')            // Your API Endpoint
        ->setProject('[PROJECT_ID]')                           // Your project ID
        ->setKey('919c2d18fb5d4...a2ae413da83346ad2')           // Your secret API key
    
    $databases = new Databases($client);
    
    $result = $databases->listDocuments('642f358bf4084c662590', '642f3592aa5fc856ad1e');
    // ... More code to manipulate the results
  • Python

    from appwrite.client import Client
    
    client = Client()
    
    (client
      .set_endpoint('https://cloud.appwrite.io/v1')              # Your API Endpoint
      .set_project('[PROJECT_ID]')                             # Your project ID
      .setKey('919c2d18fb5d4...a2ae413da83346ad2')              # Your secret API key
    ) databases = Databases(client) result = databases.list_documents('642f358bf4084c662590', '642f3592aa5fc856ad1e') # ... More code to manipulate the results
  • Ruby

    require 'appwrite'
    
    include Appwrite
    
    client = Client
    
    client.new
        .set_endpoint('https://cloud.appwrite.io/v1')            # Your API Endpoint
        .set_project('[PROJECT_ID]')                           # Your project ID
        .setKey('919c2d18fb5d4...a2ae413da83346ad2')            # Your secret API key
    
    databases = Databases.new(client)
    
    response = databases.list_documents(database_id: '642f358bf4084c662590', '642f3592aa5fc856ad1e')
    # ... More code to manipulate the results
  • Deno

    import { Client } from "https://deno.land/x/appwrite/mod.ts";
    
    let client = new Client();
    
    client
        .setEndpoint('https://cloud.appwrite.io/v1')             // Your API Endpoint
        .setProject('[PROJECT_ID]')                            // Your project ID
        .setKey('919c2d18fb5d4...a2ae413da83346ad2')            // Your secret API key
    
    let databases = new sdk.Databases(client);
    
    let promise = databases.listDocuments('642f358bf4084c662590', '642f3592aa5fc856ad1e');
    // ... More code to manipulate the results
  • Dart

    import 'package:dart_appwrite/dart_appwrite.dart';
    
    final client = Client();
    
    client
        .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
        .setProject('[PROJECT_ID]')                // Your project ID
        .setKey('919c2d18fb5d4...a2ae413da83346ad2')// Your secret API key
    
    Databases databases = Databases(client);
    
    Future result = databases.listDocuments(
        databaseId: '642f358bf4084c662590',
        collectionId: '642f3592aa5fc856ad1e',
    );
    // ... More code to manipulate the results
  • Kotlin

    import io.appwrite.Client
    
    val client = Client()
    
    client
        .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
        .setProject("[PROJECT_ID]")                // Your project ID
        .setKey("919c2d18fb5d4...a2ae413da83346ad2")// Your secret API key
    
    val databases = Databases(client)
    
    val response = databases.listDocuments(
        databaseId = "642f358bf4084c662590",
        collectionId = "642f3592aa5fc856ad1e",
    )
    // ... More code to manipulate the results
  • Swift

    import Appwrite
    
    let client = Client()
    
    client
        .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
        .setProject("[PROJECT_ID]")                // Your project ID
        .setKey("919c2d18fb5d4...a2ae413da83346ad2")// Your secret API key
        
        let databases = Databases(client)
        
        let documentList = try await databases.listDocuments(
            databaseId: "642f358bf4084c662590",
            collectionId: "642f3592aa5fc856ad1e"
        )
        / ... More code to manipulate the results

This will return every document reguardless of permissions, which could lead to privacy and security problems.

{
  "total": 3,
  "documents": [
    {
      "name": "Kevin",
      "birthday": "2012-02-03T00:00:00.000+00:00",
      "$id": "ac5fc866ad1e",
      "$permissions": [
        "read(\"user:user-a\")"
      ],
      "$collectionId": "642f3592aa5fc856ad1e",
      "$databaseId": "642f358bf4084c662590",
      ...
    },
    {
      "name": "Laura",
      "birthday": "1999-09-22T11:21:23.334+00:00",
      "$id": "bc7fc866ad1e",
      "$permissions": [
        "read(\"user:user-b\")"
      ],
      "$collectionId": "642f3592aa5fc856ad1e",
      "$databaseId": "642f358bf4084c662590",
      ...
    },
    {
      "name": "Bob",
      "birthday": "1982-05-11T12:31:39.381+00:00",
      "$id": "cc2fc886ad1e",
      "$permissions": [
        "read(\"user:user-c\")"
      ],
      "$collectionId": "642f3592aa5fc856ad1e",
      "$databaseId": "642f358bf4084c662590",
      ...
    }
  ]
}

If you're integrating existing backend services with Appwrite or adding backend endpoints to perform more complex logic, JWT authentication helps them behave similarly to actual Appwrite endpoints.