Skip to content
Merged
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
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
# Change Log

## 28.0.0

* Breaking: removed `Account.listLogs` and the `Log`, `LogList` models
* Breaking: removed `Client.setDevKey`
* Breaking: SDK now targets Appwrite 2.3 (`x-appwrite-response-format: 2.3.0`)
* Added: `Account.createIdTokenSession` for native Apple and Google sign-in with `IdTokenProvider` enum
* Added: `Account.createRecoveryOTP` and `Account.updateRecoveryOTP` for code-based password recovery
* Added: `Account.createEmailVerificationOTP` and `Account.updateEmailVerificationOTP`
* Added: `KAKAO` and `TIKTOK` values to `OAuthProvider`
* Added: `passwordPwned` field on `User` and `providerIdToken` field on `Identity`
* Fixed: empty-string required path parameters are rejected instead of sent to the API

## 27.2.0

* Added: `DocumentsDB` and `VectorsDB` services for document and vector database access
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@

![Maven Central](https://img.shields.io/maven-central/v/io.appwrite/sdk-for-android.svg?color=green&style=flat-square)
![License](https://img.shields.io/github/license/appwrite/sdk-for-android.svg?style=flat-square)
![Version](https://img.shields.io/badge/api%20version-2.0.0-blue.svg?style=flat-square)
![Version](https://img.shields.io/badge/api%20version-2.3.0-blue.svg?style=flat-square)
[![Build Status](https://img.shields.io/travis/com/appwrite/sdk-generator?style=flat-square)](https://travis-ci.com/appwrite/sdk-generator)
[![Twitter Account](https://img.shields.io/twitter/follow/appwrite?color=00acee&label=twitter&style=flat-square)](https://twitter.com/appwrite)
[![Discord](https://img.shields.io/discord/564160730845151244?label=discord&style=flat-square)](https://appwrite.io/discord)

**This SDK targets Appwrite server version 2.0.x as shipped on Appwrite Cloud.** Self-hosted releases can lag behind Cloud — if you run an older self-hosted build, use a matching older SDK from [previous releases](https://github.com/appwrite/sdk-for-android/releases) when APIs differ.
**This SDK targets Appwrite server version 2.3.x as shipped on Appwrite Cloud.** Self-hosted releases can lag behind Cloud — if you run an older self-hosted build, use a matching older SDK from [previous releases](https://github.com/appwrite/sdk-for-android/releases) when APIs differ.

Appwrite is an open-source backend as a service server that abstracts and simplifies complex and repetitive development tasks behind a very simple to use REST API. Appwrite aims to help you develop your apps faster and in a more secure way. Use the Android SDK to integrate your app with the Appwrite server to easily start interacting with all of Appwrite backend APIs and tools. For full API documentation and tutorials go to [https://appwrite.io/docs](https://appwrite.io/docs)

Expand Down Expand Up @@ -38,7 +38,7 @@ repositories {
Next, add the dependency to your project's `build.gradle(.kts)` file:

```groovy
implementation("io.appwrite:sdk-for-android:27.2.0")
implementation("io.appwrite:sdk-for-android:28.0.0")
```

### Maven
Expand All @@ -49,7 +49,7 @@ Add this to your project's `pom.xml` file:
<dependency>
<groupId>io.appwrite</groupId>
<artifactId>sdk-for-android</artifactId>
<version>27.2.0</version>
<version>28.0.0</version>
</dependency>
</dependencies>
```
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,8 @@ Client client = new Client(context)

Account account = new Account(client);

account.listLogs(
List.of(), // queries (optional)
false, // total (optional)
account.createEmailVerificationOTP(
false, // phrase (optional)
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
Expand Down
32 changes: 32 additions & 0 deletions docs/examples/java/account/create-id-token-session.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
```java
import android.util.Log;

import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;
import io.appwrite.enums.IdTokenProvider;

Client client = new Client(context)
.setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint
.setProject("<YOUR_PROJECT_ID>"); // Your project ID

Account account = new Account(client);

account.createIdTokenSession(
IdTokenProvider.APPLE, // provider
"<ID_TOKEN>", // idToken
"<NONCE>", // nonce (optional)
"<ACCESS_TOKEN>", // accessToken (optional)
0, // accessTokenExpiry (optional)

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 Broken native sign-in example The Java sample passes 0 for accessTokenExpiry, but the method expects a boxed Long, so the sample does not compile. Changing it to 0L alone would make the example’s access token immediately expired; the Kotlin sample also supplies zero seconds. Omit the optional expiry or use the provider-reported lifetime.

Prompt To Fix With AI
This is a comment left during a code review.
Path: docs/examples/java/account/create-id-token-session.md
Line: 20

Comment:
**Broken native sign-in example** The Java sample passes `0` for `accessTokenExpiry`, but the method expects a boxed `Long`, so the sample does not compile. Changing it to `0L` alone would make the example’s access token immediately expired; the Kotlin sample also supplies zero seconds. Omit the optional expiry or use the provider-reported lifetime.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Claude Code Fix in Codex

"<NAME>", // name (optional)
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}

Log.d("Appwrite", result.toString());

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 security Session credentials logged If a developer supplies the access token shown in this example, logging the full returned Session can write that credential to Android logs. Log a non-sensitive field such as the session ID instead.

How this was verified: The method accepts an access token to store on the session, and Session.toString() includes its providerAccessToken field before this example passes it to Log.d.

Suggested change
Log.d("Appwrite", result.toString());
Log.d("Appwrite", result.getId());
Prompt To Fix With AI
This is a comment left during a code review.
Path: docs/examples/java/account/create-id-token-session.md
Line: 28

Comment:
**Session credentials logged** If a developer supplies the access token shown in this example, logging the full returned `Session` can write that credential to Android logs. Log a non-sensitive field such as the session ID instead.

**How this was verified:** The method accepts an access token to store on the session, and `Session.toString()` includes its `providerAccessToken` field before this example passes it to `Log.d`.

```suggestion
        Log.d("Appwrite", result.getId());
```

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Claude Code Fix in Codex

})
);

```
27 changes: 27 additions & 0 deletions docs/examples/java/account/create-recovery-otp.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
```java
import android.util.Log;

import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;

Client client = new Client(context)
.setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint
.setProject("<YOUR_PROJECT_ID>"); // Your project ID

Account account = new Account(client);

account.createRecoveryOTP(
"email@example.com", // email
false, // phrase (optional)
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}

Log.d("Appwrite", result.toString());
})
);

```
27 changes: 27 additions & 0 deletions docs/examples/java/account/update-email-verification-otp.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
```java
import android.util.Log;

import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;

Client client = new Client(context)
.setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint
.setProject("<YOUR_PROJECT_ID>"); // Your project ID

Account account = new Account(client);

account.updateEmailVerificationOTP(
"<USER_ID>", // userId
"<SECRET>", // secret
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}

Log.d("Appwrite", result.toString());
})
);

```
28 changes: 28 additions & 0 deletions docs/examples/java/account/update-recovery-otp.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
```java
import android.util.Log;

import io.appwrite.Client;
import io.appwrite.coroutines.CoroutineCallback;
import io.appwrite.services.Account;

Client client = new Client(context)
.setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint
.setProject("<YOUR_PROJECT_ID>"); // Your project ID

Account account = new Account(client);

account.updateRecoveryOTP(
"<USER_ID>", // userId
"<SECRET>", // secret
"password", // password
new CoroutineCallback<>((result, error) -> {
if (error != null) {
error.printStackTrace();
return;
}

Log.d("Appwrite", result.toString());
})
);

```
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ val client = Client(context)

val account = Account(client)

val result = account.listLogs(
queries = listOf(), // (optional)
total = false, // (optional)
val result = account.createEmailVerificationOTP(
phrase = false, // (optional)
)
```
21 changes: 21 additions & 0 deletions docs/examples/kotlin/account/create-id-token-session.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
```kotlin
import io.appwrite.Client
import io.appwrite.coroutines.CoroutineCallback
import io.appwrite.services.Account
import io.appwrite.enums.IdTokenProvider

val client = Client(context)
.setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint
.setProject("<YOUR_PROJECT_ID>") // Your project ID

val account = Account(client)

val result = account.createIdTokenSession(
provider = IdTokenProvider.APPLE,
idToken = "<ID_TOKEN>",
nonce = "<NONCE>", // (optional)
accessToken = "<ACCESS_TOKEN>", // (optional)
accessTokenExpiry = 0, // (optional)
name = "<NAME>", // (optional)
)
```
16 changes: 16 additions & 0 deletions docs/examples/kotlin/account/create-recovery-otp.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
```kotlin
import io.appwrite.Client
import io.appwrite.coroutines.CoroutineCallback
import io.appwrite.services.Account

val client = Client(context)
.setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint
.setProject("<YOUR_PROJECT_ID>") // Your project ID

val account = Account(client)

val result = account.createRecoveryOTP(
email = "email@example.com",
phrase = false, // (optional)
)
```
16 changes: 16 additions & 0 deletions docs/examples/kotlin/account/update-email-verification-otp.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
```kotlin
import io.appwrite.Client
import io.appwrite.coroutines.CoroutineCallback
import io.appwrite.services.Account

val client = Client(context)
.setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint
.setProject("<YOUR_PROJECT_ID>") // Your project ID

val account = Account(client)

val result = account.updateEmailVerificationOTP(
userId = "<USER_ID>",
secret = "<SECRET>",
)
```
17 changes: 17 additions & 0 deletions docs/examples/kotlin/account/update-recovery-otp.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
```kotlin
import io.appwrite.Client
import io.appwrite.coroutines.CoroutineCallback
import io.appwrite.services.Account

val client = Client(context)
.setEndpoint("https://<REGION>.cloud.appwrite.io/v1") // Your API Endpoint
.setProject("<YOUR_PROJECT_ID>") // Your project ID

val account = Account(client)

val result = account.updateRecoveryOTP(
userId = "<USER_ID>",
secret = "<SECRET>",
password = "password",
)
```
4 changes: 2 additions & 2 deletions example/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,9 @@ dependencies {
implementation("androidx.appcompat:appcompat:1.8.0")
implementation("com.google.android.material:material:1.14.0")
implementation("androidx.constraintlayout:constraintlayout:2.2.2")
implementation("androidx.navigation:navigation-fragment-ktx:2.10.0")
implementation("androidx.navigation:navigation-fragment-ktx:2.10.1")
implementation("androidx.fragment:fragment-ktx:1.9.0")
implementation("androidx.navigation:navigation-ui-ktx:2.10.0")
implementation("androidx.navigation:navigation-ui-ktx:2.10.1")
implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.11.0")
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.11.0")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.11.0")
Expand Down
2 changes: 1 addition & 1 deletion library/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ dependencies {
testImplementation("junit:junit:4.13.2")
testImplementation("androidx.test.ext:junit-ktx:1.3.0")
testImplementation("androidx.test:core-ktx:1.7.0")
testImplementation("org.robolectric:robolectric:4.16.1")
testImplementation("org.robolectric:robolectric:4.17")
testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.11.0")
}

Expand Down
19 changes: 2 additions & 17 deletions library/src/main/java/io/appwrite/Client.kt
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,8 @@ class Client @JvmOverloads constructor(
"x-sdk-name" to "Android",
"x-sdk-platform" to "client",
"x-sdk-language" to "android",
"x-sdk-version" to "27.2.0",
"x-appwrite-response-format" to "2.0.0"
"x-sdk-version" to "28.0.0",
"x-appwrite-response-format" to "2.3.0"
)
config = mutableMapOf()

Expand Down Expand Up @@ -176,21 +176,6 @@ class Client @JvmOverloads constructor(
return this
}

/**
* Set DevKey
*
* Your secret dev API key
*
* @param {string} devkey
*
* @return this
*/
fun setDevKey(value: String): Client {
config["devKey"] = value
addHeader("x-appwrite-dev-key", value)
return this
}

/**
* Set Cookie
*
Expand Down
12 changes: 12 additions & 0 deletions library/src/main/java/io/appwrite/enums/IdTokenProvider.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package io.appwrite.enums

import com.google.gson.annotations.SerializedName

enum class IdTokenProvider(val value: String) {
@SerializedName("apple")
APPLE("apple"),
@SerializedName("google")
GOOGLE("google");

override fun toString() = value
}
4 changes: 4 additions & 0 deletions library/src/main/java/io/appwrite/enums/OAuthProvider.kt
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ enum class OAuthProvider(val value: String) {
GOOGLE("google"),
@SerializedName("huggingface")
HUGGINGFACE("huggingface"),
@SerializedName("kakao")
KAKAO("kakao"),
@SerializedName("keycloak")
KEYCLOAK("keycloak"),
@SerializedName("kick")
Expand Down Expand Up @@ -77,6 +79,8 @@ enum class OAuthProvider(val value: String) {
SPOTIFY("spotify"),
@SerializedName("stripe")
STRIPE("stripe"),
@SerializedName("tiktok")
TIKTOK("tiktok"),
@SerializedName("tradeshift")
TRADESHIFT("tradeshift"),
@SerializedName("tradeshiftBox")
Expand Down
2 changes: 1 addition & 1 deletion library/src/main/java/io/appwrite/models/Execution.kt
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ data class Execution(
val errors: String,

/**
* Resource(function/site) execution duration in seconds.
* Total time the resource(function/site) took to respond, in seconds.
*/
@SerializedName("duration")
val duration: Double,
Expand Down
8 changes: 8 additions & 0 deletions library/src/main/java/io/appwrite/models/Identity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,12 @@ data class Identity(
@SerializedName("providerRefreshToken")
val providerRefreshToken: String,

/**
* Identity Provider ID token (JWT) from the most recent native sign-in. Empty for identities created through the browser OAuth2 flow.
*/
@SerializedName("providerIdToken")
val providerIdToken: String,

) {
fun toMap(): Map<String, Any?> = mapOf(
"\$id" to id as Any,
Expand All @@ -79,6 +85,7 @@ data class Identity(
"providerAccessToken" to providerAccessToken as Any,
"providerAccessTokenExpiry" to providerAccessTokenExpiry as Any,
"providerRefreshToken" to providerRefreshToken as Any,
"providerIdToken" to providerIdToken as Any,
)

companion object {
Expand All @@ -96,6 +103,7 @@ data class Identity(
providerAccessToken = map["providerAccessToken"] as String,
providerAccessTokenExpiry = map["providerAccessTokenExpiry"] as String,
providerRefreshToken = map["providerRefreshToken"] as String,
providerIdToken = map["providerIdToken"] as String,
)
}
}
Loading