From 459a5e2b517f056b9f25301a2ff23f2571d61ed1 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Fri, 11 Aug 2023 01:32:42 +0000 Subject: [PATCH 01/21] Add some new pages for different auth methods. --- app/views/docs/authentication-anonymous.phtml | 1268 +++++++++++++++++ .../docs/authentication-email-pass.phtml | 262 ++++ app/views/docs/authentication-magic.phtml | 198 +++ app/views/docs/authentication-sms.phtml | 211 +++ 4 files changed, 1939 insertions(+) create mode 100644 app/views/docs/authentication-anonymous.phtml create mode 100644 app/views/docs/authentication-email-pass.phtml create mode 100644 app/views/docs/authentication-magic.phtml create mode 100644 app/views/docs/authentication-sms.phtml diff --git a/app/views/docs/authentication-anonymous.phtml b/app/views/docs/authentication-anonymous.phtml new file mode 100644 index 000000000..9910bc286 --- /dev/null +++ b/app/views/docs/authentication-anonymous.phtml @@ -0,0 +1,1268 @@ +

+ Appwrite provides authentication for many different use cases to fit the needs of developers. + Appwrite manages authentication with a combination of accounts and sessions. + Accounts can be created in many different ways, such as through an anonymous session, email and password, OAuth authentication, magic URLs, and more. +

+ +

Account vs Users API

+ +

+ The Account API operates in the scope of the currently logged-in account and is usually used in a frontend or mobile app. The Users API is used in backend integrations and uses an API key with access to all your project users. +

+ +

+ Some of the Account API methods are available from Server SDKs when you authenticate with a JWT. This allows your Server SDK to perform actions on behalf of a user. +

+ +

Create An Account

+ +

+ A user account in Appwrite is the primary way to access information for a given project. Accounts can be created in many different ways, including email & password, anonymous sessions, OAuth2, phone authentication, and more. Applications can create and manage sessions through the REST API or Client SDKs. +

+ +

Email

+ +

+ Creating an account via email and password is one of the most common ways to sign up for an application. Appwrite provides email and password authentication out of the box. Using one of Appwrite's Client SDKs, or the REST APIs directly, you can create an account using an email address and password in your application. +

+ +

+ Passwords are hashed with Argon2, a resilient and secure password hashing algorithm. +

+ +

+ The example below shows you how to create an account: +

+ + + +

+ After an account is created, it can be verified through the account verification route provided by the Appwrite Accounts API. The user doesn't need to be verified to log in, but you can restrict resource access to verified users only using permissions. +

+ +

Anonymous User

+ +

+Anonymous authentication allows users of your application to create a temporary valid session without creating an account. The session has an expiration time of one year. If an account is created while an anonymous session is active, it will be attached to the existing anonymous session. +

+ + + +

OAuth

+ +

+ OAuth is another way to authenticate a user using a multistep process. When using OAuth to authenticate, the authentication request is initiated from the client application. The user is then redirected to an OAuth2 provider to complete the authentication step, and finally, the user is redirected back to the client application. This provides integration with many third-party services that provide their own OAuth integration as a more secure approach than providing a username/password directly. +

+ +

+ In applications with first-party redirects, using OAuth2 for authentication is preferred. +

+ +

+ The example below shows you how to authenticate with OAuth2 using Amazon's OAuth system. +

+ + + +

+ If there is already an active anonymous session, the new session will be attached to it. If there are no active sessions, the server will attempt to look for an account with the same email address as the email received from the OAuth2 provider and attach the new session to the existing account. If no matching account is found - the server will create a new account. +

+ +

Phone

+ +

+ Phone authentication is done using a two-step authentication process. When using phone authentication, the authentication request is initiated from the client application and an SMS is sent to the user with a secret key for creating a session. +

+ +

+ The example below shows you how to initiate a phone authentication request. +

+ + + +

+ After initiation, the returned user ID and secret are used to confirm the user. The secret will be a 6-digit number in the SMS message sent to the user. +

+ + + +

+ After the secret is verified, a session will be created. +

+ + +

Magic URL

+

+ Magic URL authentication allows a user to sign in without a password. Magic URL authentication sends the user an email with a secret key for creating a new session. If the provided email does not belong to an existing user, the provided user ID is used to create a new user. If the account already exists, the provided user ID is ignored +

+ +

+ Only redirect URLs to domains added as a platform on your Appwrite console will be accepted. URLs not added as a platform are rejected to protect against redirect attacks. +

+ + +

+ Magic URL authentication can be initiated like this: +

+ + + + +

+ After receiving your secret from an email, you can create a new Magic URL session like this: +

+ + + + +

Login

+ +

+ Logging in with an email and password is one of the most common ways to login into an application. +

+ +

+ The example below shows you how to create a session: +

+ + + +

+ When a user tries to access restricted resources, you can check if they have a valid, active session. The Account Service provides a get() method that checks whether the current user session is active and returns the account information if successful. +

+ +

+ The example below shows you how to check whether there is an active session: +

+ + + +

+ An authenticated session in Appwrite lasts for 1 year and is then automatically expired. +

+ + +

Password Recovery

+

+ If a user forgets their password, they can initiate a password recovery flow to recover their password. The Create Password Recovery endpoint sends the user an email with a temporary secret key for password reset. When the user clicks the confirmation link, they are redirected back to the password reset URL with the secret key and email address values attached to the URL as query strings. +

+ +

+ Only redirect URLs to domains added as a platform on your Appwrite console will be accepted. URLs not added as a platform are rejected to protect against redirect attacks. +

+ + + +

+After receiving a email with the secret attached to the redirect link, submit a request to the Create Password Recovery (confirmation) endpoint to complete the recovery flow. The verification link sent to the user's email address is valid for 1 hour. +

+ + + + +

User Preferences

+

You can store user preferences on a user's account using Appwrite's Update Preferences endpoint. You can store user preferences such as theme, notification settings, or preferred language so they can be synced across multiple devices.

+

Preferences are stored as a key-value JSON object. The maximum allowed prefs size is 64kB and throws an error if exceeded.

+ + +

After a user's preferences are updated, they can be retrieved using the Get Preferences endpoint.

+ + diff --git a/app/views/docs/authentication-email-pass.phtml b/app/views/docs/authentication-email-pass.phtml new file mode 100644 index 000000000..f81623927 --- /dev/null +++ b/app/views/docs/authentication-email-pass.phtml @@ -0,0 +1,262 @@ +

+ Email and password login is the most commonly used authentication method. + Appwrite Authentication promotes a safer internet by providing secure APIs and promoting better password choices to end users. + Appwrite supports added security features like blocking personal info in passwords, password dictionary, and password history to help users choose good passwords. +

+ +

Sign Up

+ +

+ You can use the Appwrite Client SDKs to create an account using email and password. +

+ + + +

+ Passwords are hashed with Argon2, a resilient and secure password hashing algorithm. +

+ +

Verification

+ +

+ After an account is created, it can be verified through the account create verification route. + The user doesn't need to be verified to log in, but you can restrict resource access to verified users only using permissions through the user([USER_ID], "verified") role. +

+ +

+ First, send a verification email. + Specify a redirect URL which users will be redirected to. + The verification secrets will be appended as query parameters to the redirect URL. + In this example, the redirect URL is https://example.com/verify. +

+ + +

+ Next, implement the verification page in your app. + This page will parse the secrets passed in through the userId and secret query parameters. + In this example, the code below will be found in the page served at https://example.com/verify. +

+ +[TODO: Who ever: examples to parse query params from page and complete verification] + + +

Log In

+ +

+ After you've created your account, users can be logged in using the Create Email Session route. +

+ + + + +

Security

+[TODO: Talk about the password security features] \ No newline at end of file diff --git a/app/views/docs/authentication-magic.phtml b/app/views/docs/authentication-magic.phtml new file mode 100644 index 000000000..760de3e8d --- /dev/null +++ b/app/views/docs/authentication-magic.phtml @@ -0,0 +1,198 @@ +

+ Magic URL is a password-less way to authenticate users. + When a user logs in, they will receive an email with a magic url that contains a secret used to log in the user. +

+ +

Send Email

+ +

+ Initialize the log in process with the Create MAgic URL Session route. + We recommend you use the user's email as their user ID instead of a random ID. + This way, you will only need an email, and not an ID to log in the user. +

+ + + +

Log In

+ +

+ After receiving your secret from an email, you can create a session. +

+ +[TODO: Engineers, please update the examples below with how to get the secret from the magic URL] + + \ No newline at end of file diff --git a/app/views/docs/authentication-sms.phtml b/app/views/docs/authentication-sms.phtml new file mode 100644 index 000000000..b02f581b9 --- /dev/null +++ b/app/views/docs/authentication-sms.phtml @@ -0,0 +1,211 @@ +

+ Phone authentication lets users create accounts using their phone numbers and log in through SMS messages. +

+ + +

Send SMS Message

+ +

+ Phone authentication is done using a two-step authentication process. + When using phone authentication, the authentication request is initiated from the client application and an SMS message is sent to the user's phone. + The SMS message will contain a secret the user can use to log in. +

+ +

+ Send an SMS message to initiate the authentication process. + A new account will be created for this phone number if it has never been used before. +

+ +[TODO: to engineer: update these examples to show where the userID comes from (continuity from first request to next)] + + + + +

Log In

+

+ After initiation, the returned user ID and secret are used to confirm the user. + The secret will usually be a 6-digit number in the SMS message sent to the user. +

+ + + +

+ After the secret is verified, a session will be created. +

\ No newline at end of file From fce9b607a1792aabc8a0fb72066d43dbdf424f8b Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Fri, 11 Aug 2023 20:45:42 +0000 Subject: [PATCH 02/21] Add auth method pages. --- app/views/docs/authentication-anonymous.phtml | 1191 +--------------- .../docs/authentication-email-pass.phtml | 198 +++ app/views/docs/authentication-magic.phtml | 8 +- .../docs/authentication-management.phtml | 178 +++ app/views/docs/authentication-oauth.phtml | 189 +++ app/views/docs/authentication.phtml | 1253 ----------------- 6 files changed, 588 insertions(+), 2429 deletions(-) create mode 100644 app/views/docs/authentication-management.phtml create mode 100644 app/views/docs/authentication-oauth.phtml diff --git a/app/views/docs/authentication-anonymous.phtml b/app/views/docs/authentication-anonymous.phtml index 9910bc286..93d6dbc64 100644 --- a/app/views/docs/authentication-anonymous.phtml +++ b/app/views/docs/authentication-anonymous.phtml @@ -1,143 +1,18 @@

- Appwrite provides authentication for many different use cases to fit the needs of developers. - Appwrite manages authentication with a combination of accounts and sessions. - Accounts can be created in many different ways, such as through an anonymous session, email and password, OAuth authentication, magic URLs, and more. -

- -

Account vs Users API

- -

- The Account API operates in the scope of the currently logged-in account and is usually used in a frontend or mobile app. The Users API is used in backend integrations and uses an API key with access to all your project users. -

- -

- Some of the Account API methods are available from Server SDKs when you authenticate with a JWT. This allows your Server SDK to perform actions on behalf of a user. -

- -

Create An Account

- -

- A user account in Appwrite is the primary way to access information for a given project. Accounts can be created in many different ways, including email & password, anonymous sessions, OAuth2, phone authentication, and more. Applications can create and manage sessions through the REST API or Client SDKs. -

- -

Email

- -

- Creating an account via email and password is one of the most common ways to sign up for an application. Appwrite provides email and password authentication out of the box. Using one of Appwrite's Client SDKs, or the REST APIs directly, you can create an account using an email address and password in your application. -

- -

- Passwords are hashed with Argon2, a resilient and secure password hashing algorithm. + Anonymous sessions allow you to implement guest users. + Guest users let you store user information like items in their cart or theme preferences before they create an account. + This reduces the friction for your users to get started with your app.

- The example below shows you how to create an account: + If a user later creates an account, their information will be inhereted by the newly created account.

- - +

Create Anonymous Session

- After an account is created, it can be verified through the account verification route provided by the Appwrite Accounts API. The user doesn't need to be verified to log in, but you can restrict resource access to verified users only using permissions. + Create an anonymous session with Create Anonymous Session route.

-

Anonymous User

- -

-Anonymous authentication allows users of your application to create a temporary valid session without creating an account. The session has an expiration time of one year. If an account is created while an anonymous session is active, it will be attached to the existing anonymous session. -

-

OAuth

- -

- OAuth is another way to authenticate a user using a multistep process. When using OAuth to authenticate, the authentication request is initiated from the client application. The user is then redirected to an OAuth2 provider to complete the authentication step, and finally, the user is redirected back to the client application. This provides integration with many third-party services that provide their own OAuth integration as a more secure approach than providing a username/password directly. -

- -

- In applications with first-party redirects, using OAuth2 for authentication is preferred. -

- -

- The example below shows you how to authenticate with OAuth2 using Amazon's OAuth system. -

- - - -

- If there is already an active anonymous session, the new session will be attached to it. If there are no active sessions, the server will attempt to look for an account with the same email address as the email received from the OAuth2 provider and attach the new session to the existing account. If no matching account is found - the server will create a new account. -

- -

Phone

- -

- Phone authentication is done using a two-step authentication process. When using phone authentication, the authentication request is initiated from the client application and an SMS is sent to the user with a secret key for creating a session. -

- +

Attaching an Account

- The example below shows you how to initiate a phone authentication request. + Anonymous users cannot sign back in. + If they close their browser, or go to another computer, they won't be able to log in again. + Remeber to prompt the user to create an account to no lose their data.

- -

- After initiation, the returned user ID and secret are used to confirm the user. The secret will be a 6-digit number in the SMS message sent to the user. + Create an account with any of these methods to transition from an anonymous session to a user account session.

- - -

- After the secret is verified, a session will be created. -

- - -

Magic URL

-

- Magic URL authentication allows a user to sign in without a password. Magic URL authentication sends the user an email with a secret key for creating a new session. If the provided email does not belong to an existing user, the provided user ID is used to create a new user. If the account already exists, the provided user ID is ignored -

- -

- Only redirect URLs to domains added as a platform on your Appwrite console will be accepted. URLs not added as a platform are rejected to protect against redirect attacks. -

- - -

- Magic URL authentication can be initiated like this: -

- - - - -

- After receiving your secret from an email, you can create a new Magic URL session like this: -

- - - - -

Login

- -

- Logging in with an email and password is one of the most common ways to login into an application. -

- -

- The example below shows you how to create a session: -

- - - -

- When a user tries to access restricted resources, you can check if they have a valid, active session. The Account Service provides a get() method that checks whether the current user session is active and returns the account information if successful. -

- -

- The example below shows you how to check whether there is an active session: -

- - - -

- An authenticated session in Appwrite lasts for 1 year and is then automatically expired. -

- - -

Password Recovery

-

- If a user forgets their password, they can initiate a password recovery flow to recover their password. The Create Password Recovery endpoint sends the user an email with a temporary secret key for password reset. When the user clicks the confirmation link, they are redirected back to the password reset URL with the secret key and email address values attached to the URL as query strings. -

- -

- Only redirect URLs to domains added as a platform on your Appwrite console will be accepted. URLs not added as a platform are rejected to protect against redirect attacks. -

- - - -

-After receiving a email with the secret attached to the redirect link, submit a request to the Create Password Recovery (confirmation) endpoint to complete the recovery flow. The verification link sent to the user's email address is valid for 1 hour. -

- - - - -

User Preferences

-

You can store user preferences on a user's account using Appwrite's Update Preferences endpoint. You can store user preferences such as theme, notification settings, or preferred language so they can be synced across multiple devices.

-

Preferences are stored as a key-value JSON object. The maximum allowed prefs size is 64kB and throws an error if exceeded.

- - -

After a user's preferences are updated, they can be retrieved using the Get Preferences endpoint.

- - +
    +
  1. + Email and password + Phone + Magic URL + OAuth2 +
  2. +
\ No newline at end of file diff --git a/app/views/docs/authentication-email-pass.phtml b/app/views/docs/authentication-email-pass.phtml index f81623927..c9cee86f7 100644 --- a/app/views/docs/authentication-email-pass.phtml +++ b/app/views/docs/authentication-email-pass.phtml @@ -257,6 +257,204 @@ let session = try await account.createEmailSession( +

Password Recovery

+

+ If a user forgets their password, they can initiate a password recovery flow to recover their password. The Create Password Recovery endpoint sends the user an email with a temporary secret key for password reset. When the user clicks the confirmation link, they are redirected back to the password reset URL with the secret key and email address values attached to the URL as query strings. +

+ +

+ Only redirect URLs to domains added as a platform on your Appwrite console will be accepted. URLs not added as a platform are rejected to protect against redirect attacks. +

+ + + +

+After receiving a email with the secret attached to the redirect link, submit a request to the Create Password Recovery (confirmation) endpoint to complete the recovery flow. The verification link sent to the user's email address is valid for 1 hour. +

+ +

Security

[TODO: Talk about the password security features] \ No newline at end of file diff --git a/app/views/docs/authentication-magic.phtml b/app/views/docs/authentication-magic.phtml index 760de3e8d..1f89e0346 100644 --- a/app/views/docs/authentication-magic.phtml +++ b/app/views/docs/authentication-magic.phtml @@ -6,7 +6,7 @@

Send Email

- Initialize the log in process with the Create MAgic URL Session route. + Initialize the log in process with the Create Magic URL Session route. We recommend you use the user's email as their user ID instead of a random ID. This way, you will only need an email, and not an ID to log in the user.

@@ -120,7 +120,7 @@ const client = new Client() const account = new Account(client); -const promise = account.updateMagicURLSession(''email@example.com'', '[SECRET]'); +const promise = account.updateMagicURLSession('email@example.com', '[SECRET]'); promise.then(function (response) { console.log(response); @@ -141,7 +141,7 @@ final client = Client() final account = Account(client); final user = await account.updateMagicURLSession( - userId: ''email@example.com'', + userId: 'email@example.com', secret: '[SECRET]', ); @@ -158,7 +158,7 @@ val client = Client(context) val account = Account(client) val user = account.updateMagicURLSession( - userId = ''email@example.com'', + userId = 'email@example.com', secret = '[SECRET]' ) diff --git a/app/views/docs/authentication-management.phtml b/app/views/docs/authentication-management.phtml new file mode 100644 index 000000000..a6c8a7591 --- /dev/null +++ b/app/views/docs/authentication-management.phtml @@ -0,0 +1,178 @@ +

+ [TODO] +

+ +

User Preferences

+

You can store user preferences on a user's account using Appwrite's Update Preferences endpoint. You can store user preferences such as theme, notification settings, or preferred language so they can be synced across multiple devices.

+

Preferences are stored as a key-value JSON object. The maximum allowed prefs size is 64kB and throws an error if exceeded.

+ + +

After a user's preferences are updated, they can be retrieved using the Get Preferences endpoint.

+ + diff --git a/app/views/docs/authentication-oauth.phtml b/app/views/docs/authentication-oauth.phtml new file mode 100644 index 000000000..5fcbb32ee --- /dev/null +++ b/app/views/docs/authentication-oauth.phtml @@ -0,0 +1,189 @@ +

+ OAuth authentication allows users to log in using accounts from other popular services. + This can be convenient for users because they can start using your app without creating a new account. + It can also be more secure, because the user has one less password that could become vulnerable. +

+ +

+ When using OAuth to authenticate, the authentication request is initiated from the client application. + The user is then redirected to an OAuth2 provider to complete the authentication step, and finally, the user is redirected back to the client application. +

+ +

Configure OAuth2 Login

+

+ Before using OAuth2 login, you need to enable and configure a OAuth2 login provider. +

+ +[TODO] +1. Navigate to your Appwrite project +2. Navigate to **Auth** > **Settings** +3. Find and open the OAuth provider +4. In the **Zoom OAuth2 Settings** modal, use the toggle to enable the provider + +

Initialize OAuth2 Login

+ +

+ To initialize the OAuth2 login process, use the Create OAuth2 Session route. +

+ + + +

+ You'll be redirected to the OAuth 2 provider's login page to log in. + Once complete, you'll be redirected to the redirect URL configured in your OAuth 2 provider. +

+ +

OAuth 2 Profile

+

+ +

+ + +

Refresh Tokens

+

+ OAuth2 sessions expire to protect from security risks. + This means, OAuth2 sessions should be refreshed to keep the user authenticated. + You can do this by calling the Update OAuth Session endpoint when ever your user visits your app. +

+ + \ No newline at end of file diff --git a/app/views/docs/authentication.phtml b/app/views/docs/authentication.phtml index 9910bc286..e9391674d 100644 --- a/app/views/docs/authentication.phtml +++ b/app/views/docs/authentication.phtml @@ -13,1256 +13,3 @@

Some of the Account API methods are available from Server SDKs when you authenticate with a JWT. This allows your Server SDK to perform actions on behalf of a user.

- -

Create An Account

- -

- A user account in Appwrite is the primary way to access information for a given project. Accounts can be created in many different ways, including email & password, anonymous sessions, OAuth2, phone authentication, and more. Applications can create and manage sessions through the REST API or Client SDKs. -

- -

Email

- -

- Creating an account via email and password is one of the most common ways to sign up for an application. Appwrite provides email and password authentication out of the box. Using one of Appwrite's Client SDKs, or the REST APIs directly, you can create an account using an email address and password in your application. -

- -

- Passwords are hashed with Argon2, a resilient and secure password hashing algorithm. -

- -

- The example below shows you how to create an account: -

- - - -

- After an account is created, it can be verified through the account verification route provided by the Appwrite Accounts API. The user doesn't need to be verified to log in, but you can restrict resource access to verified users only using permissions. -

- -

Anonymous User

- -

-Anonymous authentication allows users of your application to create a temporary valid session without creating an account. The session has an expiration time of one year. If an account is created while an anonymous session is active, it will be attached to the existing anonymous session. -

- - - -

OAuth

- -

- OAuth is another way to authenticate a user using a multistep process. When using OAuth to authenticate, the authentication request is initiated from the client application. The user is then redirected to an OAuth2 provider to complete the authentication step, and finally, the user is redirected back to the client application. This provides integration with many third-party services that provide their own OAuth integration as a more secure approach than providing a username/password directly. -

- -

- In applications with first-party redirects, using OAuth2 for authentication is preferred. -

- -

- The example below shows you how to authenticate with OAuth2 using Amazon's OAuth system. -

- - - -

- If there is already an active anonymous session, the new session will be attached to it. If there are no active sessions, the server will attempt to look for an account with the same email address as the email received from the OAuth2 provider and attach the new session to the existing account. If no matching account is found - the server will create a new account. -

- -

Phone

- -

- Phone authentication is done using a two-step authentication process. When using phone authentication, the authentication request is initiated from the client application and an SMS is sent to the user with a secret key for creating a session. -

- -

- The example below shows you how to initiate a phone authentication request. -

- - - -

- After initiation, the returned user ID and secret are used to confirm the user. The secret will be a 6-digit number in the SMS message sent to the user. -

- - - -

- After the secret is verified, a session will be created. -

- - -

Magic URL

-

- Magic URL authentication allows a user to sign in without a password. Magic URL authentication sends the user an email with a secret key for creating a new session. If the provided email does not belong to an existing user, the provided user ID is used to create a new user. If the account already exists, the provided user ID is ignored -

- -

- Only redirect URLs to domains added as a platform on your Appwrite console will be accepted. URLs not added as a platform are rejected to protect against redirect attacks. -

- - -

- Magic URL authentication can be initiated like this: -

- - - - -

- After receiving your secret from an email, you can create a new Magic URL session like this: -

- - - - -

Login

- -

- Logging in with an email and password is one of the most common ways to login into an application. -

- -

- The example below shows you how to create a session: -

- - - -

- When a user tries to access restricted resources, you can check if they have a valid, active session. The Account Service provides a get() method that checks whether the current user session is active and returns the account information if successful. -

- -

- The example below shows you how to check whether there is an active session: -

- - - -

- An authenticated session in Appwrite lasts for 1 year and is then automatically expired. -

- - -

Password Recovery

-

- If a user forgets their password, they can initiate a password recovery flow to recover their password. The Create Password Recovery endpoint sends the user an email with a temporary secret key for password reset. When the user clicks the confirmation link, they are redirected back to the password reset URL with the secret key and email address values attached to the URL as query strings. -

- -

- Only redirect URLs to domains added as a platform on your Appwrite console will be accepted. URLs not added as a platform are rejected to protect against redirect attacks. -

- - - -

-After receiving a email with the secret attached to the redirect link, submit a request to the Create Password Recovery (confirmation) endpoint to complete the recovery flow. The verification link sent to the user's email address is valid for 1 hour. -

- - - - -

User Preferences

-

You can store user preferences on a user's account using Appwrite's Update Preferences endpoint. You can store user preferences such as theme, notification settings, or preferred language so they can be synced across multiple devices.

-

Preferences are stored as a key-value JSON object. The maximum allowed prefs size is 64kB and throws an error if exceeded.

- - -

After a user's preferences are updated, they can be retrieved using the Get Preferences endpoint.

- - From 286867e4b402173535f87e30d452283f0f5080b4 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Mon, 14 Aug 2023 02:18:21 +0000 Subject: [PATCH 03/21] Add homepage list of auth methods --- .../docs/authentication-management.phtml | 9 ++- app/views/docs/authentication-security.phtml | 8 ++- app/views/docs/authentication.phtml | 72 +++++++++++++++++-- 3 files changed, 78 insertions(+), 11 deletions(-) diff --git a/app/views/docs/authentication-management.phtml b/app/views/docs/authentication-management.phtml index a6c8a7591..69db8cb05 100644 --- a/app/views/docs/authentication-management.phtml +++ b/app/views/docs/authentication-management.phtml @@ -1,7 +1,14 @@

- [TODO] + Appwrite has build in features to help manage user accounts. + Users can be organized into teams and be given labels, so they can be given different permissions and access different resources. + Each user can also have their own preference object, which you can use to save preferences such as theme, language, and notification settings.

+[TODO @STEVEN: TEAMS examples] + +[TODO @STEVEN: Labels] + +

User Preferences

You can store user preferences on a user's account using Appwrite's Update Preferences endpoint. You can store user preferences such as theme, notification settings, or preferred language so they can be synced across multiple devices.

Preferences are stored as a key-value JSON object. The maximum allowed prefs size is 64kB and throws an error if exceeded.

diff --git a/app/views/docs/authentication-security.phtml b/app/views/docs/authentication-security.phtml index 241e6893e..28a1a475b 100644 --- a/app/views/docs/authentication-security.phtml +++ b/app/views/docs/authentication-security.phtml @@ -84,13 +84,15 @@ Security is very important to protect users' data and privacy. Appwrite uses a permissions model coupled with user sessions to ensure users need correct permissions to access resources. With all Appwrite services, including databases and storage, access is granted at the collection, bucket, document, or file level. These permissions are enforced for client SDKs and server SDKs when using JWT, but are ignored when using a server SDK with an API key.

-

Password History

+

Password History

Password history prevents users from reusing recent passwords. This protects user accounts from security risks by enforcing a new password everytime it's changed.

Password history can be enabled in the Auth service's Security tab on the Appwrite console. You can choose how many previous passwords to remember up to a maximum of 20 and block users from reusing them.

-

Password Dictionary

+

Password Dictionary

Password dictionary protects users from using bad passwords. It compares the user's password to the 10,000 most common passwords and throws an error if there's a match. Together with rate limits, password dictionary will significantly reduce the chance of a malicious actor from guessing user passwords.

-

Password dictionary can be enabled in the Auth service's Security tab on the Appwrite console.

\ No newline at end of file +

Password dictionary can be enabled in the Auth service's Security tab on the Appwrite console.

+ +

Personal Information

diff --git a/app/views/docs/authentication.phtml b/app/views/docs/authentication.phtml index e9391674d..7f8755d59 100644 --- a/app/views/docs/authentication.phtml +++ b/app/views/docs/authentication.phtml @@ -1,15 +1,73 @@

- Appwrite provides authentication for many different use cases to fit the needs of developers. - Appwrite manages authentication with a combination of accounts and sessions. - Accounts can be created in many different ways, such as through an anonymous session, email and password, OAuth authentication, magic URLs, and more. + Appwrite Authentication delivers more than just user sign up and log in. + Authentication makes it easy to build secure and robust authentication with support for many differnt authentication methods. + You can manage user accounts with user preferences, user labeling, or organizing users into teams. + Combined with a robust permissions system, Appwrite Authentication provides everything you need to authenticate and manager users.

-

Account vs Users API

+

Account vs Users API

- The Account API operates in the scope of the currently logged-in account and is usually used in a frontend or mobile app. The Users API is used in backend integrations and uses an API key with access to all your project users. + Appwrite has two auth APIs for different purposes, which are Account and Users. + Here's how you choose between the two, depending on your needs.

-

- Some of the Account API methods are available from Server SDKs when you authenticate with a JWT. This allows your Server SDK to perform actions on behalf of a user. +

Account API

+

+ Use the Account API when acting on behalf of individual users when building client applications, like websites or mobile apps. + The Account API is authenticated through secure cookies that store session information, so Appwrite knows which authenticated user is accessing data. + The Account API is safe to expose to end users, because their access to data and resources is limited by Appwrite's permission system. +

+ +

Users API

+

+ Use the Users API when acting as an administrator in use cases like building admin consoles or server integrations. + The Users API uses API keys to authenticate, which means Appwrite only knows which API key is accessing data. + API keys don't respect permissions, which means they can access all data, and should never be shared with end users in client applications. + The Users API also has batch operations, letting your query and manage users from an admin's perspective. +

+ +

Explore

+

Explore Appwrite Authentication's features.

+ +

+ + Log in with email and password + +

+ +

+ + Log in with SMS messages + +

+ +

+ + Log in with magic URL + +

+ +

+ + Log in with OAuth 2 + +

+ +

+ + Log in as a guest (anonymous) + +

+ +

+ + Server integrations + +

+ +

+ + Security +

From c4e6f150924a9991886ebe03faf0c7689a1f9bf8 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Mon, 14 Aug 2023 18:07:32 +0000 Subject: [PATCH 04/21] Add tags for engineers to add examples --- app/views/docs/authentication-anonymous.phtml | 8 ++++++- .../docs/authentication-email-pass.phtml | 5 ++-- app/views/docs/authentication-magic.phtml | 2 +- .../docs/authentication-management.phtml | 4 ++-- app/views/docs/authentication-oauth.phtml | 23 ++++++++++--------- app/views/docs/authentication-security.phtml | 3 ++- app/views/docs/authentication-sms.phtml | 2 +- app/views/docs/getting-started-for-web.phtml | 2 +- 8 files changed, 29 insertions(+), 20 deletions(-) diff --git a/app/views/docs/authentication-anonymous.phtml b/app/views/docs/authentication-anonymous.phtml index 93d6dbc64..f0c9b236f 100644 --- a/app/views/docs/authentication-anonymous.phtml +++ b/app/views/docs/authentication-anonymous.phtml @@ -108,8 +108,14 @@ mutation {
  1. Email and password +
  2. +
  3. Phone - Magic URL +
  4. +
  5. + Magic URL +
  6. +
  7. OAuth2
\ No newline at end of file diff --git a/app/views/docs/authentication-email-pass.phtml b/app/views/docs/authentication-email-pass.phtml index c9cee86f7..8e8b5dd39 100644 --- a/app/views/docs/authentication-email-pass.phtml +++ b/app/views/docs/authentication-email-pass.phtml @@ -160,7 +160,7 @@ mutation { In this example, the code below will be found in the page served at https://example.com/verify.

-[TODO: Who ever: examples to parse query params from page and complete verification] +[TODO: @bradley examples to parse query params from page and complete verification]

Log In

@@ -457,4 +457,5 @@ let token = try await account.updateRecovery(

Security

-[TODO: Talk about the password security features] \ No newline at end of file +[TODO: @steven Talk about the password security features like password dictionary, passowrd history, and prevent personal information.] +[Be brief, link to security page for details] \ No newline at end of file diff --git a/app/views/docs/authentication-magic.phtml b/app/views/docs/authentication-magic.phtml index 1f89e0346..d863b7611 100644 --- a/app/views/docs/authentication-magic.phtml +++ b/app/views/docs/authentication-magic.phtml @@ -106,7 +106,7 @@ let user = try await account.createMagicURLSession( After receiving your secret from an email, you can create a session.

-[TODO: Engineers, please update the examples below with how to get the secret from the magic URL] +[TODO: @bradley, please update the examples below with how to get the secret from the magic URL]
  • diff --git a/app/views/docs/authentication-management.phtml b/app/views/docs/authentication-management.phtml index 69db8cb05..8f636fcfc 100644 --- a/app/views/docs/authentication-management.phtml +++ b/app/views/docs/authentication-management.phtml @@ -4,9 +4,9 @@ Each user can also have their own preference object, which you can use to save preferences such as theme, language, and notification settings.

    -[TODO @STEVEN: TEAMS examples] +[TODO @steven: TEAMS docs] -[TODO @STEVEN: Labels] +[TODO @steven: Labels docs]

    User Preferences

    diff --git a/app/views/docs/authentication-oauth.phtml b/app/views/docs/authentication-oauth.phtml index 5fcbb32ee..18f8b69d1 100644 --- a/app/views/docs/authentication-oauth.phtml +++ b/app/views/docs/authentication-oauth.phtml @@ -14,11 +14,13 @@ Before using OAuth2 login, you need to enable and configure a OAuth2 login provider.

    -[TODO] -1. Navigate to your Appwrite project -2. Navigate to **Auth** > **Settings** -3. Find and open the OAuth provider -4. In the **Zoom OAuth2 Settings** modal, use the toggle to enable the provider +
      +
    1. Navigate to your Appwrite project
    2. +
    3. Navigate to Auth > Settings
    4. +
    5. Find and open the OAuth provider.
    6. +
    7. In the OAuth2 settings modal, use the toggle to enable the provider
    8. +
    +

    Initialize OAuth2 Login

    @@ -103,10 +105,9 @@ try await account.createOAuth2Session(provider: "amazon")

    OAuth 2 Profile

    - + [TODO: @steven fill the docs to access profile information]

    -

    Refresh Tokens

    OAuth2 sessions expire to protect from security risks. @@ -129,8 +130,8 @@ client .setProject('[PROJECT_ID]') // Your Project ID ; -// Go to Zoom OAuth login page -account.createOAuth2Session('zoom', '[LINK_ON_SUCCESS]', '[LINK_ON_FAILURE]'); +// Go to Amazon OAuth login page +account.createOAuth2Session('amazon', '[LINK_ON_SUCCESS]', '[LINK_ON_FAILURE]');

  • @@ -148,7 +149,7 @@ void main() async { // OAuth Login, for simplest implementation you can leave both success and // failure link empty so that Appwrite handles everything. - await account.createOAuth2Session(provider: 'zoom'); + await account.createOAuth2Session(provider: 'amazon'); } @@ -165,7 +166,7 @@ val client = Client(context) val account = Account(client) -account.createOAuth2Session(provider = "zoom") +account.createOAuth2Session(provider = "amazon")
  • diff --git a/app/views/docs/authentication-security.phtml b/app/views/docs/authentication-security.phtml index 28a1a475b..8e98a7b90 100644 --- a/app/views/docs/authentication-security.phtml +++ b/app/views/docs/authentication-security.phtml @@ -92,7 +92,8 @@

    Password Dictionary

    Password dictionary protects users from using bad passwords. It compares the user's password to the 10,000 most common passwords and throws an error if there's a match. Together with rate limits, password dictionary will significantly reduce the chance of a malicious actor from guessing user passwords.

    -

    Password dictionary can be enabled in the Auth service's Security tab on the Appwrite console.

    Personal Information

    + +[TODO: @steven Talk about new personal information thing.] \ No newline at end of file diff --git a/app/views/docs/authentication-sms.phtml b/app/views/docs/authentication-sms.phtml index b02f581b9..49c7c6483 100644 --- a/app/views/docs/authentication-sms.phtml +++ b/app/views/docs/authentication-sms.phtml @@ -16,7 +16,7 @@ A new account will be created for this phone number if it has never been used before.

    -[TODO: to engineer: update these examples to show where the userID comes from (continuity from first request to next)] +[TODO: @bradley update these examples to show where the userID comes from (continuity from first request to next)]
    • diff --git a/app/views/docs/getting-started-for-web.phtml b/app/views/docs/getting-started-for-web.phtml index d7ec5bc2a..51d3428df 100644 --- a/app/views/docs/getting-started-for-web.phtml +++ b/app/views/docs/getting-started-for-web.phtml @@ -27,7 +27,7 @@ $demos = $platform['demos'] ?? [];

      Web platforms allow wildcard hostnames through a * character. The wildcard character can be applied anywhere in a hostname, both *.example.com and prod.*.example.com are valid examples. Avoid using wildcards unless necessary to keep your Appwrite project secure.

      - +

      Get Appwrite Web SDK

      From ff3c2b495d35ca89fc2677c9af189421c50897f4 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Thu, 17 Aug 2023 17:29:28 +0000 Subject: [PATCH 05/21] Fix web example format, add quickstart to auth --- app/views/docs/authentication-anonymous.phtml | 8 +- .../docs/authentication-email-pass.phtml | 36 +----- app/views/docs/authentication-magic.phtml | 16 +-- .../docs/authentication-management.phtml | 16 +-- app/views/docs/authentication-server.phtml | 8 +- app/views/docs/authentication-sms.phtml | 18 +-- app/views/docs/authentication.phtml | 105 +++++++++++++++++- 7 files changed, 118 insertions(+), 89 deletions(-) diff --git a/app/views/docs/authentication-anonymous.phtml b/app/views/docs/authentication-anonymous.phtml index f0c9b236f..8c6f53929 100644 --- a/app/views/docs/authentication-anonymous.phtml +++ b/app/views/docs/authentication-anonymous.phtml @@ -26,13 +26,7 @@ const client = new Client() const account = new Account(client); -const promise = account.createAnonymousSession(); - -promise.then(function (response) { - console.log(response); -}, function (error) { - console.log(error); -}); +const user = await account.createAnonymousSession();
    • diff --git a/app/views/docs/authentication-email-pass.phtml b/app/views/docs/authentication-email-pass.phtml index 8e8b5dd39..9ad52be88 100644 --- a/app/views/docs/authentication-email-pass.phtml +++ b/app/views/docs/authentication-email-pass.phtml @@ -22,17 +22,11 @@ const client = new Client() const account = new Account(client); -const promise = account.create( +const user = await account.create( ID.unique(), 'email@example.com', 'password' -); - -promise.then(function (response) { - console.log(response); -}, function (error) { - console.log(error); -}); +);
    • @@ -181,16 +175,10 @@ const client = new Client() const account = new Account(client); -const promise = account.createEmailSession( +const user = await account.createEmailSession( 'email@example.com', 'password' -); - -promise.then(function (response) { - console.log(response); -}, function (error) { - console.log(error); -}); +);
    • @@ -278,13 +266,7 @@ const client = new Client() const account = new Account(client); -const promise = account.createPasswordRecovery('email@example.com', 'https://example.com'); - -promise.then(function (response) { - console.log(response); -}, function (error) { - console.log(error); -}); +const user = await account.createPasswordRecovery('email@example.com', 'https://example.com');
    • @@ -371,13 +353,7 @@ const client = new Client() const account = new Account(client); -const promise = account.updateRecovery('[USER_ID]', '[SECRET]', 'password', 'password'); - -promise.then(function (response) { - console.log(response); -}, function (error) { - console.log(error); -}); +const user = await account.updateRecovery('[USER_ID]', '[SECRET]', 'password', 'password');
    • diff --git a/app/views/docs/authentication-magic.phtml b/app/views/docs/authentication-magic.phtml index d863b7611..f06095ab5 100644 --- a/app/views/docs/authentication-magic.phtml +++ b/app/views/docs/authentication-magic.phtml @@ -23,13 +23,7 @@ const client = new Client() const account = new Account(client); -const promise = account.createMagicURLSession('email@example.com', 'email@example.com'); - -promise.then(function (response) { - console.log(response); -}, function (error) { - console.log(error); -}); +const user = await account.createMagicURLSession('email@example.com', 'email@example.com');
    • @@ -120,13 +114,7 @@ const client = new Client() const account = new Account(client); -const promise = account.updateMagicURLSession('email@example.com', '[SECRET]'); - -promise.then(function (response) { - console.log(response); -}, function (error) { - console.log(error); -}); +const user = await account.updateMagicURLSession('email@example.com', '[SECRET]');
    • diff --git a/app/views/docs/authentication-management.phtml b/app/views/docs/authentication-management.phtml index 8f636fcfc..f0c89799e 100644 --- a/app/views/docs/authentication-management.phtml +++ b/app/views/docs/authentication-management.phtml @@ -24,13 +24,7 @@ const client = new Client() const account = new Account(client); -const promise = account.updatePrefs({darkTheme: true, language: 'en'}); - -promise.then(function (response) { - console.log(response); -}, function (error) { - console.log(error); -}); +const user = await account.updatePrefs({darkTheme: true, language: 'en'});
    • @@ -123,13 +117,7 @@ const client = new Client() const account = new Account(client); -const promise = account.getPrefs(); - -promise.then(function (prefs) { - console.log(prefs); -}, function (error) { - console.log(error); -}); +const user = await account.getPrefs();
    • diff --git a/app/views/docs/authentication-server.phtml b/app/views/docs/authentication-server.phtml index 186b5eb5b..0313c8a11 100644 --- a/app/views/docs/authentication-server.phtml +++ b/app/views/docs/authentication-server.phtml @@ -30,13 +30,7 @@ const client = new Client() const account = new Account(client); -const promise = account.createJWT(); - -promise.then(function (response) { - console.log(response); -}, function (error) { - console.log(error); -}); +const user = await account.createJWT();
    • diff --git a/app/views/docs/authentication-sms.phtml b/app/views/docs/authentication-sms.phtml index 49c7c6483..2660ccc4f 100644 --- a/app/views/docs/authentication-sms.phtml +++ b/app/views/docs/authentication-sms.phtml @@ -30,17 +30,11 @@ const client = new Client() const account = new Account(client); -const promise = account.createPhoneSession( +const user = await account.createPhoneSession( ID.unique(), '+14255550123' ); -promise.then(function (response) { - console.log(response); -}, function (error) { - console.log(error); -}); -
    • @@ -128,16 +122,10 @@ const client = new Client() const account = new Account(client); -const promise = account.updatePhoneSession( +const user = await account.updatePhoneSession( '[USER_ID]', '[SECRET]' -); - -promise.then(function (response) { - console.log(response); -}, function (error) { - console.log(error); -}); +);
    • diff --git a/app/views/docs/authentication.phtml b/app/views/docs/authentication.phtml index 7f8755d59..62fcdce3e 100644 --- a/app/views/docs/authentication.phtml +++ b/app/views/docs/authentication.phtml @@ -1,8 +1,109 @@

      Appwrite Authentication delivers more than just user sign up and log in. - Authentication makes it easy to build secure and robust authentication with support for many differnt authentication methods. + Authentication makes it easy to build secure and robust authentication with support for many different authentication methods. +

      + +

      You can manage user accounts with user preferences, user labeling, or organizing users into teams. - Combined with a robust permissions system, Appwrite Authentication provides everything you need to authenticate and manager users. + Combined with a robust permissions system, Appwrite Authentication provides everything you need to authenticate and manage users. +

      + +

      Getting Started

      +

      + Adding Appwrite Authentication to your apps can be as easy as these lines of code. +

      + +
        +
      • +

        Web

        +
        +
        import { Client, Account, ID } 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 user = await account.create(
        +    ID.unique(),
        +    'email@example.com',
        +    'password'
        +);
        +
        +
      • +
      • +

        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 user = await account.create(
        +    userId: ID.unique(),
        +    email: 'email@example.com',
        +    password: 'password',
        +);
        +
      • +
      • +

        Android

        +
        +
        import io.appwrite.Client
        +import io.appwrite.services.Account
        +import io.appwrite.ID
        +
        +val client = Client()
        +    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
        +    .setProject("[PROJECT_ID]")                // Your project ID
        +
        +val account = Account(client)
        +
        +val user = account.create(
        +    userId = ID.unique(),
        +    email = "email@example.com",
        +    password = "password"
        +)
        +
        +
      • +
      • +

        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 user = try await account.create(
        +    userId: ID.unique(),
        +    email: "email@example.com",
        +    password: "password"
        +)
        +
        +
      • +
      • +

        GraphQL

        +
        +
        
        +mutation {
        +    accountCreate(userId: "unique()", email: "email@example.com", password: "password") {
        +        _id
        +        email
        +        name
        +    }
        +}
        +
        +
      • +
      + +

      + Use email and password authentication as a starting point and explore the many powerful features of Appwrite authentication.

      Account vs Users API

      From 21431cc4c3d045fa560f2a07e70d3e6b92e29a13 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Thu, 17 Aug 2023 19:30:43 +0000 Subject: [PATCH 06/21] Fix auth index, add users api docs --- .../docs/authentication-management.phtml | 21 ++++++++++++++++++- app/views/docs/authentication.phtml | 6 ++++++ app/views/docs/index.phtml | 6 ++++++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/app/views/docs/authentication-management.phtml b/app/views/docs/authentication-management.phtml index f0c89799e..269233007 100644 --- a/app/views/docs/authentication-management.phtml +++ b/app/views/docs/authentication-management.phtml @@ -9,7 +9,7 @@ [TODO @steven: Labels docs] -

      User Preferences

      +

      User Preferences

      You can store user preferences on a user's account using Appwrite's Update Preferences endpoint. You can store user preferences such as theme, notification settings, or preferred language so they can be synced across multiple devices.

      Preferences are stored as a key-value JSON object. The maximum allowed prefs size is 64kB and throws an error if exceeded.

        @@ -171,3 +171,22 @@ let prefs = try await account.getPrefs()
      + +

      Users API

      +

      + The Users API is a dedicated API for managing users from an admin's perspective. + You'll notice that the Account API doesn't allow you to view or make changes to other users. + This is by design and for security reasons. +

      + +

      + You can use the Users API with an API key authenticated Server SDK to manage users. + If you must expose parts of the Users API to normal users, we suggest doing so through an Appwrite Function. + Exposing API keys to users is dangerous and a security risk, by using an Appwrite Function, you can add your own validation to prevent malicious behavior. +

      + +

      + + Learn more about the Users API + +

      \ No newline at end of file diff --git a/app/views/docs/authentication.phtml b/app/views/docs/authentication.phtml index 62fcdce3e..c2691e24b 100644 --- a/app/views/docs/authentication.phtml +++ b/app/views/docs/authentication.phtml @@ -161,6 +161,12 @@ mutation {

      +

      + + Manage users + +

      +

      Server integrations diff --git a/app/views/docs/index.phtml b/app/views/docs/index.phtml index 3554cba88..4643d1aca 100644 --- a/app/views/docs/index.phtml +++ b/app/views/docs/index.phtml @@ -88,6 +88,12 @@ $cols = [

    • Authentication From 672a6df5bce31bcbba0040384f8103eb0bd0ecc0 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Thu, 17 Aug 2023 19:34:06 +0000 Subject: [PATCH 07/21] Fix auth index display names --- app/views/docs/index.phtml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/app/views/docs/index.phtml b/app/views/docs/index.phtml index 4643d1aca..48a97c0ff 100644 --- a/app/views/docs/index.phtml +++ b/app/views/docs/index.phtml @@ -88,13 +88,13 @@ $cols = [
    • Authentication
    • From 8050091707bd0cc36a250c1264e7f1164b29e23b Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Thu, 17 Aug 2023 19:41:57 +0000 Subject: [PATCH 08/21] Maybe it should be user management vs just management --- app/views/docs/index.phtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/docs/index.phtml b/app/views/docs/index.phtml index 48a97c0ff..e4f21b661 100644 --- a/app/views/docs/index.phtml +++ b/app/views/docs/index.phtml @@ -93,7 +93,7 @@ $cols = [
    •   Magic URL
    •   OAuth 2
    •   Anonymous
    • -
    •   Management
    • +
    •   User Management
    •   Server Integrations
    •   Security
    From e2f493ec3fde149be307a97249b10fd007a6af54 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Thu, 17 Aug 2023 19:59:12 +0000 Subject: [PATCH 09/21] grammar check by GPT --- app/views/docs/authentication-anonymous.phtml | 4 ++-- app/views/docs/authentication-email-pass.phtml | 2 +- app/views/docs/authentication-management.phtml | 2 +- app/views/docs/authentication-security.phtml | 6 +++--- app/views/docs/authentication-server.phtml | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/app/views/docs/authentication-anonymous.phtml b/app/views/docs/authentication-anonymous.phtml index 8c6f53929..9848c8097 100644 --- a/app/views/docs/authentication-anonymous.phtml +++ b/app/views/docs/authentication-anonymous.phtml @@ -92,7 +92,7 @@ mutation {

    Anonymous users cannot sign back in. If they close their browser, or go to another computer, they won't be able to log in again. - Remeber to prompt the user to create an account to no lose their data. + Remeber to prompt the user to create an account to not lose their data.

    @@ -104,7 +104,7 @@ mutation { Email and password

  • - Phone + Phone (SMS)
  • Magic URL diff --git a/app/views/docs/authentication-email-pass.phtml b/app/views/docs/authentication-email-pass.phtml index 9ad52be88..4cbb7d731 100644 --- a/app/views/docs/authentication-email-pass.phtml +++ b/app/views/docs/authentication-email-pass.phtml @@ -433,5 +433,5 @@ let token = try await account.updateRecovery(

Security

-[TODO: @steven Talk about the password security features like password dictionary, passowrd history, and prevent personal information.] +[TODO: @steven Talk about the password security features like password dictionary, password history, and prevent personal information.] [Be brief, link to security page for details] \ No newline at end of file diff --git a/app/views/docs/authentication-management.phtml b/app/views/docs/authentication-management.phtml index 269233007..d140e01fd 100644 --- a/app/views/docs/authentication-management.phtml +++ b/app/views/docs/authentication-management.phtml @@ -1,5 +1,5 @@

- Appwrite has build in features to help manage user accounts. + Appwrite has built-in features to help manage user accounts. Users can be organized into teams and be given labels, so they can be given different permissions and access different resources. Each user can also have their own preference object, which you can use to save preferences such as theme, language, and notification settings.

diff --git a/app/views/docs/authentication-security.phtml b/app/views/docs/authentication-security.phtml index 8e98a7b90..153581615 100644 --- a/app/views/docs/authentication-security.phtml +++ b/app/views/docs/authentication-security.phtml @@ -10,7 +10,7 @@

Best Practice

-

Only keep user sessions active as long as needed and only maintain one instance of the Client SDK in your app to avoid conflicting session data.

+

Only keep user sessions active as long as needed and maintain exactly one instance of the Client SDK in your app to avoid conflicting session data.

@@ -74,7 +74,7 @@

Session Limits

-

In Appwrite versions 1.2 and above, you can limit the number of active sessions created per user to prevent the accumulation of unused but active sessions. New sessions created by the same user past the session limit deletes the oldest session.

+

In Appwrite versions 1.2 and above, you can limit the number of active sessions created per user to prevent the accumulation of unused but active sessions. New sessions created by the same user past the session limit delete the oldest session.

You can change the session limit in the Security tab of the Auth Service in your Appwrite Console. The default session limit is 10 with a maximum configurable limit of 100.

@@ -85,7 +85,7 @@

Password History

-

Password history prevents users from reusing recent passwords. This protects user accounts from security risks by enforcing a new password everytime it's changed.

+

Password history prevents users from reusing recent passwords. This protects user accounts from security risks by enforcing a new password every time it's changed.

Password history can be enabled in the Auth service's Security tab on the Appwrite console. You can choose how many previous passwords to remember up to a maximum of 20 and block users from reusing them.

diff --git a/app/views/docs/authentication-server.phtml b/app/views/docs/authentication-server.phtml index 0313c8a11..7e54f1d2e 100644 --- a/app/views/docs/authentication-server.phtml +++ b/app/views/docs/authentication-server.phtml @@ -12,7 +12,7 @@

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.

+

JSON Web Tokens (JWTs) are a secure means to transfer information or claims between two parties. JWTs act like temporary copies of the user's ID card that allow Appwrite's Server SDKs to access information on 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.

@@ -441,7 +441,7 @@ var documentList = await databases.ListDocuments( -

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

+

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

{
   "total": 1,

From f1a41d254d810ea2cc192971377ed0b3edc86279 Mon Sep 17 00:00:00 2001
From: "Vincent (Wen Yu) Ge" 
Date: Thu, 17 Aug 2023 20:33:20 +0000
Subject: [PATCH 10/21] Add info about personal information in auth docs

---
 app/views/docs/authentication-security.phtml | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/app/views/docs/authentication-security.phtml b/app/views/docs/authentication-security.phtml
index 153581615..99fd79a21 100644
--- a/app/views/docs/authentication-security.phtml
+++ b/app/views/docs/authentication-security.phtml
@@ -95,5 +95,8 @@
 

Password dictionary can be enabled in the Auth service's Security tab on the Appwrite console.

Personal Information

- -[TODO: @steven Talk about new personal information thing.] \ No newline at end of file +

+ Encourage passwords that are hard to guess by disallowing users to pick passwords that contain personal information. + Personal information includes the user's name, email, and phone number. +

+

Disallowing personal information can be enabled in the Auth service's Security tab on the Appwrite console.

From 61be417bb523fd7babbac1042a766f531174173f Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Thu, 17 Aug 2023 20:34:35 +0000 Subject: [PATCH 11/21] Add more information about password security in Appwrite --- app/views/docs/authentication-email-pass.phtml | 12 ++++++++++-- app/views/docs/authentication-oauth.phtml | 2 +- app/views/docs/authentication-security.phtml | 7 +++++-- app/views/docs/authentication.phtml | 4 ++-- 4 files changed, 18 insertions(+), 7 deletions(-) diff --git a/app/views/docs/authentication-email-pass.phtml b/app/views/docs/authentication-email-pass.phtml index 4cbb7d731..119dd9fa0 100644 --- a/app/views/docs/authentication-email-pass.phtml +++ b/app/views/docs/authentication-email-pass.phtml @@ -433,5 +433,13 @@ let token = try await account.updateRecovery(

Security

-[TODO: @steven Talk about the password security features like password dictionary, password history, and prevent personal information.] -[Be brief, link to security page for details] \ No newline at end of file +

+ Appwrite does more than use secure implementation of email and password authentication on the server-side to ensure security. + You can enable features like password dictionary, password history, and disallow personal information to encourage users to pick better passwords. + By enabling these features, you protect user data and teach better password choices, which helps make the internet a safer place. +

+

+ + Learn more about security features + +

\ No newline at end of file diff --git a/app/views/docs/authentication-oauth.phtml b/app/views/docs/authentication-oauth.phtml index 18f8b69d1..35a6a9305 100644 --- a/app/views/docs/authentication-oauth.phtml +++ b/app/views/docs/authentication-oauth.phtml @@ -105,7 +105,7 @@ try await account.createOAuth2Session(provider: "amazon")

OAuth 2 Profile

- [TODO: @steven fill the docs to access profile information] + [TODO: @steven fill the docs to access oauth account profile information]

Refresh Tokens

diff --git a/app/views/docs/authentication-security.phtml b/app/views/docs/authentication-security.phtml index 99fd79a21..776c320d8 100644 --- a/app/views/docs/authentication-security.phtml +++ b/app/views/docs/authentication-security.phtml @@ -78,10 +78,13 @@

You can change the session limit in the Security tab of the Auth Service in your Appwrite Console. The default session limit is 10 with a maximum configurable limit of 100.

-

Security

+

Permissions

- Security is very important to protect users' data and privacy. Appwrite uses a permissions model coupled with user sessions to ensure users need correct permissions to access resources. With all Appwrite services, including databases and storage, access is granted at the collection, bucket, document, or file level. These permissions are enforced for client SDKs and server SDKs when using JWT, but are ignored when using a server SDK with an API key. + Security is very important to protect users' data and privacy. + Appwrite uses a permissions model coupled with user sessions to ensure users need correct permissions to access resources. + With all Appwrite services, including databases and storage, access is granted at the collection, bucket, document, or file level. + These permissions are enforced for client SDKs and server SDKs when using JWT, but are ignored when using a server SDK with an API key.

Password History

diff --git a/app/views/docs/authentication.phtml b/app/views/docs/authentication.phtml index c2691e24b..917c20852 100644 --- a/app/views/docs/authentication.phtml +++ b/app/views/docs/authentication.phtml @@ -162,7 +162,7 @@ mutation {

- + Manage users

@@ -174,7 +174,7 @@ mutation {

- + Security

From e58af232b8febdaac87b57a52d864294149ba093 Mon Sep 17 00:00:00 2001 From: Bradley Schofield Date: Fri, 18 Aug 2023 15:40:40 +0100 Subject: [PATCH 12/21] Improve Examples --- .../docs/authentication-email-pass.phtml | 27 ++++++++++- app/views/docs/authentication-magic.phtml | 8 ++-- app/views/docs/authentication-sms.phtml | 45 ++++++++++--------- 3 files changed, 56 insertions(+), 24 deletions(-) diff --git a/app/views/docs/authentication-email-pass.phtml b/app/views/docs/authentication-email-pass.phtml index 119dd9fa0..1f8b44012 100644 --- a/app/views/docs/authentication-email-pass.phtml +++ b/app/views/docs/authentication-email-pass.phtml @@ -154,7 +154,32 @@ mutation { In this example, the code below will be found in the page served at https://example.com/verify.

-[TODO: @bradley examples to parse query params from page and complete verification] +
    +
  • +

    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 urlParams = new URLSearchParams(window.location.search);
    +const secret = urlParams.get('secret');
    +const userId = urlParams.get('userId');
    +
    +const promise = account.updateVerification(userId, secret);
    +
    +promise.then(function (response) {
    +    console.log(response);
    +}, function (error) {
    +    console.log(error);
    +});
    +
    +
  • +

Log In

diff --git a/app/views/docs/authentication-magic.phtml b/app/views/docs/authentication-magic.phtml index f06095ab5..29fc0fda9 100644 --- a/app/views/docs/authentication-magic.phtml +++ b/app/views/docs/authentication-magic.phtml @@ -100,8 +100,6 @@ let user = try await account.createMagicURLSession( After receiving your secret from an email, you can create a session.

-[TODO: @bradley, please update the examples below with how to get the secret from the magic URL] -
  • Web

    @@ -114,7 +112,11 @@ const client = new Client() const account = new Account(client); -const user = await account.updateMagicURLSession('email@example.com', '[SECRET]'); +const urlParams = new URLSearchParams(window.location.search); +const secret = urlParams.get('secret'); +const userId = urlParams.get('userId'); + +const user = await account.updateMagicURLSession(userId, secret);
  • diff --git a/app/views/docs/authentication-sms.phtml b/app/views/docs/authentication-sms.phtml index 2660ccc4f..54aea908e 100644 --- a/app/views/docs/authentication-sms.phtml +++ b/app/views/docs/authentication-sms.phtml @@ -16,8 +16,6 @@ A new account will be created for this phone number if it has never been used before.

    -[TODO: @bradley update these examples to show where the userID comes from (continuity from first request to next)] -
    • Web

      @@ -30,12 +28,12 @@ const client = new Client() const account = new Account(client); -const user = await account.createPhoneSession( +const sessionToken = await account.createPhoneSession( ID.unique(), '+14255550123' ); - +var userId = sessionToken.userId // Store this somewhere to use later when logging in
    • @@ -49,10 +47,12 @@ final client = Client() final account = Account(client); -final session = await account.createPhoneSession( +final sessionToken = await account.createPhoneSession( userId: ID.unique(), phone: '+14255550123' -); +); + +final userId = sessionToken.userId // Store this somewhere to use later when logging in
    • Android

      @@ -67,10 +67,12 @@ val client = Client() val account = Account(client) -val session = account.createPhoneSession( +val sessionToken = account.createPhoneSession( userId = ID.unique(), phone = "+14255550123" -) +) + +val userId = sessionToken.userId // Store this somewhere to use later when logging in
    • Apple

      @@ -83,10 +85,12 @@ let client = Client() let account = Account(client) -let session = try await account.createPhoneSession( +let sessionToken = try await account.createPhoneSession( userId: ID.unique(), phone: "+14255550123" -) +) + +let userId = sessionToken.userId // Store this somewhere to use later when logging in
    • GraphQL

      @@ -122,10 +126,11 @@ const client = new Client() const account = new Account(client); -const user = await account.updatePhoneSession( - '[USER_ID]', - '[SECRET]' -); +const session = await account.updatePhoneSession( + userId, // From when you called createPhoneSession + '[SECRET]' // The 6-digit code from the SMS message +); +
    • @@ -140,8 +145,8 @@ final client = Client() final account = Account(client); final session = await account.updatePhoneSession( - userId: '[USER_ID]', - secret: '[SECRET]' + userId: userId, // From when you called createPhoneSession + secret: '[SECRET]' // The 6-digit code from the SMS message );
    • @@ -158,8 +163,8 @@ val client = Client() val account = Account(client) val session = account.updatePhoneSession( - userId = "[USER_ID]", - secret = "[SECRET]" + userId = userId, // From when you called createPhoneSession + secret = "[SECRET]" // The 6-digit code from the SMS message )
    • @@ -174,8 +179,8 @@ let client = Client() let account = Account(client) let session = try await account.updatePhoneSession( - userId: "[USER_ID]", - secret: "[SECRET]" + userId: userId, // From when you called createPhoneSession + secret: "[SECRET]" // The 6-digit code from the SMS message )
    • From 9921120e973274909378003eeb465be62088de6d Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Fri, 18 Aug 2023 16:44:03 +0000 Subject: [PATCH 13/21] user management docs --- .../docs/authentication-management.phtml | 209 +++++++++++++++++- 1 file changed, 204 insertions(+), 5 deletions(-) diff --git a/app/views/docs/authentication-management.phtml b/app/views/docs/authentication-management.phtml index d140e01fd..83d284fc5 100644 --- a/app/views/docs/authentication-management.phtml +++ b/app/views/docs/authentication-management.phtml @@ -4,10 +4,6 @@ Each user can also have their own preference object, which you can use to save preferences such as theme, language, and notification settings.

      -[TODO @steven: TEAMS docs] - -[TODO @steven: Labels docs] -

      User Preferences

      You can store user preferences on a user's account using Appwrite's Update Preferences endpoint. You can store user preferences such as theme, notification settings, or preferred language so they can be synced across multiple devices.

      @@ -189,4 +185,207 @@ let prefs = try await account.getPrefs() Learn more about the Users API -

      \ No newline at end of file +

      + +

      Labels

      +

      + Labels are a good way to flag a user to grant them access to resources. + For example, a subscriber label can be added to a user once they've purchased a subscription. +

      + +
        +
      • +

        Node.js

        +
        +
        const sdk = require('node-appwrite');
        +
        +const client = new sdk.Client();
        +
        +const users = new sdk.Users(client);
        +
        +let res = await users.updateLabels('[USER_ID]', [ Role.label('subscriber') ]);
        +
        +
      • +
      • +

        PHP

        + +
        +
        use Appwrite\Client;
        +use Appwrite\Services\Users;
        +use Appwrite\Role;
        +
        +$client = new Client();
        +
        +$client
        +    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
        +    .setProject('5df5acd0d48c2') // Your project ID
        +    .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key
        +;
        +
        +$users = new Users($client);
        +
        +$result = $users->updateLabels(
        +    '[USER_ID]', 
        +    [
        +        Role.label('subscriber'),
        +    ]
        +);
        +
        +
      • +
      • +

        Python

        +
        +
        from appwrite.client import Client
        +from appwrite.services.users import Users
        +from appwrite.role import Role
        +
        +client = Client()
        +
        +(client
        +  .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint
        +  .set_project('5df5acd0d48c2') # Your project ID
        +  .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key
        +)
        + 
        +users = Users(client)
        +
        +result = users.update_labels('[USER_ID]', [ Role.label('subscriber') ])
        +
        +
      • +
      • +

        Ruby

        +
        +
        require 'Appwrite'
        +
        +include Appwrite
        +
        +client = Client.new
        +    .set_endpoint('https://cloud.appwrite.io/v1') # Your API Endpoint
        +    .set_project('5df5acd0d48c2') # Your project ID
        +    .set_key('919c2d18fb5d4...a2ae413da83346ad2') # Your secret API key
        +
        +users = Users.new(client)
        +
        +response = users.update_labels(user_id: '[USER_ID]', labels: [ Role.label('subscriber') ])
        +
        +puts response.inspect
        +
        +
      • +
      • +

        Deno

        +
        +
        import * as sdk from "https://deno.land/x/appwrite/mod.ts";
        +
        +// Init SDK
        +let client = new sdk.Client();
        +
        +let users = new sdk.Users(client);
        +
        +client
        +    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
        +    .setProject('5df5acd0d48c2') // Your project ID
        +    .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key
        +;
        +
        +
        +let res = await users.updateLabels('[USER_ID]', [ Role.label('subscriber') ]);
        +
        +
      • +
      • +

        Dart

        +
        +
        import 'package:dart_appwrite/dart_appwrite.dart';
        +
        +void main() { // Init SDK
        +  Client client = Client();
        +  Users users = Users(client);
        +
        +  client
        +    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
        +    .setProject('5df5acd0d48c2') // Your project ID
        +    .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key
        +  ;
        +
        +  Future result = users.updateLabels(
        +    userId: '[USER_ID]',
        +    labels: [ Role.label('subscriber') ],
        +  );
        +
        +  result
        +    .then((response) {
        +      print(response);
        +    }).catchError((error) {
        +      print(error.response);
        +  });
        +}
        +
        +
      • +
      • +

        Kotlin

        +
        +
        import io.appwrite.Client
        +import io.appwrite.services.Users
        +import io.appwrite.Role
        +
        +suspend fun main() {
        +    val client = Client(context)
        +      .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
        +      .setProject("5df5acd0d48c2") // Your project ID
        +      .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key
        +
        +    val users = Users(client)
        +    val response = users.updateLabels(
        +        userId = "[USER_ID]",
        +        labels = [ Role.label('subscriber') ]
        +    )
        +    val json = response.body?.string()
        +}
        +
        +
      • +
      • +

        Swift

        +
        +
        import Appwrite
        +
        +func main() async throws {
        +    let client = Client()
        +      .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
        +      .setProject("5df5acd0d48c2") // Your project ID
        +      .setKey("919c2d18fb5d4...a2ae413da83346ad2") // Your secret API key
        +    let users = Users(client)
        +    let response = try await users.updateLabels(
        +        userId: "[USER_ID]",
        +        labels: [ Role.label('subscriber') ]
        +    )
        +
        +    print(String(describing: response)
        +}
        +
        +
      • +
      • +

        .NET

        +
        +
        +
        +
      • +
      + +

      + This would correspond with the permissions Permissions.read(Role.label('subscriber')), Permissions.update(Role.label('subscriber')), Permissions.delete(Role.label('subscriber')), and Permissions.create(Role.label('subscriber')). +

      + + +

      +

    • Learn more about permissions
    • +

      + +

      Teams

      +

      + Teams are a good way to allow users to share access to resources. +

      + +

      + For example, in a todo app, a user can create a team for one of their todo lists and invite another user to the team to grant the other user access. + The invited user can accept the invitation to gain access. + If the user's ever removed from the team, they'll lose access again. +

      From 36a5b6b548062f44f24638d04fb269ff04017d06 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Fri, 18 Aug 2023 18:32:45 +0000 Subject: [PATCH 14/21] OAuth docs additions with steven's comments --- app/views/docs/authentication-oauth.phtml | 120 +++++++++++++++++++++- 1 file changed, 119 insertions(+), 1 deletion(-) diff --git a/app/views/docs/authentication-oauth.phtml b/app/views/docs/authentication-oauth.phtml index 35a6a9305..c75c2f9e8 100644 --- a/app/views/docs/authentication-oauth.phtml +++ b/app/views/docs/authentication-oauth.phtml @@ -105,7 +105,125 @@ try await account.createOAuth2Session(provider: "amazon")

      OAuth 2 Profile

      - [TODO: @steven fill the docs to access oauth account profile information] +After authenticating a user through their OAuth2 provider, you can fetch their profile information such as their avatar image or name. +To do this you can use the access token from the OAuth2 provider and make API calls to the provider. +

      + +

      +After creating an OAuth2 session, you can fetch the session to get information about the provider. +

      + +
        +
      • +

        Web

        +
        +
        import { Client, Account } from "appwrite";
        +
        +const client = new Client();
        +
        +const account = new Account(client);
        +
        +const session = account.getSession('current');
        +
        +// Provider information
        +console.log(session.provider);
        +console.log(session.providerUid);
        +console.log(session.provderAccessToken);
        +
        +
      • +
      • +

        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 session = await getSession(
        +    sessionId : "[SESSION_ID]"
        +);
        +
        +// Provider information
        +print(session.provider);
        +print(session.providerUid);
        +print(session.provderAccessToken);
        +
      • +
      • +

        Android

        +
        +
        import io.appwrite.Client
        +import io.appwrite.services.Account
        +
        +val client = Client(context)
        +    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
        +    .setProject("5df5acd0d48c2") // Your project ID
        +
        +val account = Account(client)
        +
        +val response = account.getSession(
        +    sessionId = "[SESSION_ID]"
        +)
        +
        +// Provider information
        +print(session.provider);
        +print(session.providerUid);
        +print(session.provderAccessToken);
        +
      • +
      • +

        Apple

        +
        +
        import Appwrite
        +
        +let client = Client()
        +    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
        +    .setProject("5df5acd0d48c2") // Your project ID
        +
        +let account = Account(client)
        +
        +let session = try await account.getSession(
        +    sessionId: "[SESSION_ID]"
        +)
        +
        +// Provider information
        +print(session.provider);
        +print(session.providerUid);
        +print(session.provderAccessToken);
        +
      • +
      + +

      + An OAuth2 session will have the following attributes. +

      + + + + + + + + + + + + + + + + + + + + + + +
      propertyDescription
      providerThe OAuth2 Provider.
      providerUid User ID from the OAuth2 Provider.
      provderAccessTokenAccess token from the OAuth2 provider. Use this to make requests to the OAuth2 provider to fetch personal information.
      + +

      + You can use the provderAccessToken to make requests to your OAuth2 provider. + Refer to the docs for the OAuth2 provider you're using to learn about making API calls with the access token.

      Refresh Tokens

      From a5b28d62648897542700a4abcec362d854c9f17f Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Fri, 18 Aug 2023 20:17:28 +0000 Subject: [PATCH 15/21] ChatGPT grammar check --- app/views/docs/authentication-anonymous.phtml | 31 ++-- .../docs/authentication-email-pass.phtml | 4 +- app/views/docs/authentication-magic.phtml | 20 ++- .../docs/authentication-management.phtml | 12 +- app/views/docs/authentication-oauth.phtml | 42 ++--- app/views/docs/authentication-server.phtml | 146 +++++++++--------- app/views/docs/authentication-sms.phtml | 6 +- app/views/docs/authentication.phtml | 4 +- 8 files changed, 137 insertions(+), 128 deletions(-) diff --git a/app/views/docs/authentication-anonymous.phtml b/app/views/docs/authentication-anonymous.phtml index 9848c8097..e9a73943a 100644 --- a/app/views/docs/authentication-anonymous.phtml +++ b/app/views/docs/authentication-anonymous.phtml @@ -5,7 +5,7 @@

      - If a user later creates an account, their information will be inhereted by the newly created account. + If a user later creates an account, their information will be inherited by the newly created account.

      Create Anonymous Session

      @@ -92,24 +92,23 @@ mutation {

      Anonymous users cannot sign back in. If they close their browser, or go to another computer, they won't be able to log in again. - Remeber to prompt the user to create an account to not lose their data. + Remember to prompt the user to create an account to not lose their data.

      Create an account with any of these methods to transition from an anonymous session to a user account session.

      -
        -
      1. - Email and password -
      2. -
      3. - Phone (SMS) -
      4. -
      5. - Magic URL -
      6. -
      7. - OAuth2 -
      8. -
      \ No newline at end of file + +

      +Email and password +

      +

      +Phone (SMS) +

      +

      +Magic URL +

      +

      +OAuth2 +

      diff --git a/app/views/docs/authentication-email-pass.phtml b/app/views/docs/authentication-email-pass.phtml index 1f8b44012..31a4b5580 100644 --- a/app/views/docs/authentication-email-pass.phtml +++ b/app/views/docs/authentication-email-pass.phtml @@ -363,7 +363,7 @@ let token = try await account.createRecovery(

    -After receiving a email with the secret attached to the redirect link, submit a request to the Create Password Recovery (confirmation) endpoint to complete the recovery flow. The verification link sent to the user's email address is valid for 1 hour. +After receiving an email with the secret attached to the redirect link, submit a request to the Create Password Recovery (confirmation) endpoint to complete the recovery flow. The verification link sent to the user's email address is valid for 1 hour.

      @@ -459,7 +459,7 @@ let token = try await account.updateRecovery(

      Security

      - Appwrite does more than use secure implementation of email and password authentication on the server-side to ensure security. + Appwrite's security first mindset goes beyond a securely implementated of authentication API. You can enable features like password dictionary, password history, and disallow personal information to encourage users to pick better passwords. By enabling these features, you protect user data and teach better password choices, which helps make the internet a safer place.

      diff --git a/app/views/docs/authentication-magic.phtml b/app/views/docs/authentication-magic.phtml index 29fc0fda9..d5aeb16f4 100644 --- a/app/views/docs/authentication-magic.phtml +++ b/app/views/docs/authentication-magic.phtml @@ -1,14 +1,15 @@

      Magic URL is a password-less way to authenticate users. - When a user logs in, they will receive an email with a magic url that contains a secret used to log in the user. + When a user logs in, they will receive an email with a "magic" link that contains a secret used to log in the user. + The user can simply click the link to be logged in.

      Send Email

      Initialize the log in process with the Create Magic URL Session route. - We recommend you use the user's email as their user ID instead of a random ID. - This way, you will only need an email, and not an ID to log in the user. + If the email has never been used, a new user ID is generated, then the user will receive an email. + If the email is already attached to an account, the user ID is ignored and the user will receive a link in their email.

        @@ -23,7 +24,10 @@ const client = new Client() const account = new Account(client); -const user = await account.createMagicURLSession('email@example.com', 'email@example.com'); +const user = await account.createMagicURLSession( + ID.unique(), + 'email@example.com' + );
      • @@ -33,12 +37,12 @@ const user = await account.createMagicURLSession('email@example.com', 'email@exa final client = Client() .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint - .setProject('[PROJECT_ID]'); // Your project ID + .setProject('[PROJECT_ID]'); // Your project ID final account = Account(client); final user = await account.createMagicURLSession( - userId: 'email@example.com', + userId: ID.unique(), email: 'email@example.com', );
      • @@ -55,7 +59,7 @@ val client = Client(context) val account = Account(client) val user = account.createMagicURLSession( - userId = 'email@example.com', + userId = ID.unique(), email = "email@example.com" ) @@ -71,7 +75,7 @@ let client = Client() let account = Account(client) let user = try await account.createMagicURLSession( - userId: 'email@example.com', + userId: ID.unique(), email: "email@example.com" ) diff --git a/app/views/docs/authentication-management.phtml b/app/views/docs/authentication-management.phtml index 83d284fc5..4e3514b27 100644 --- a/app/views/docs/authentication-management.phtml +++ b/app/views/docs/authentication-management.phtml @@ -6,8 +6,14 @@

        User Preferences

        -

        You can store user preferences on a user's account using Appwrite's Update Preferences endpoint. You can store user preferences such as theme, notification settings, or preferred language so they can be synced across multiple devices.

        -

        Preferences are stored as a key-value JSON object. The maximum allowed prefs size is 64kB and throws an error if exceeded.

        +

        + You can store user preferences on a user's account using Appwrite's Update Preferences endpoint. + You can store user preferences such as theme, notification settings, or preferred language so they can be synced across multiple devices. +

        +

        + Preferences are stored as a key-value JSON object. + The maximum allowed size for preferences is 64kB, and an error will be thrown if this limit is exceeded. +

        • Web

          @@ -376,7 +382,7 @@ func main() async throws {

          -

        • Learn more about permissions
        • + Learn more about permissions

          Teams

          diff --git a/app/views/docs/authentication-oauth.phtml b/app/views/docs/authentication-oauth.phtml index c75c2f9e8..dc99af316 100644 --- a/app/views/docs/authentication-oauth.phtml +++ b/app/views/docs/authentication-oauth.phtml @@ -6,26 +6,26 @@

          When using OAuth to authenticate, the authentication request is initiated from the client application. - The user is then redirected to an OAuth2 provider to complete the authentication step, and finally, the user is redirected back to the client application. + The user is then redirected to an OAuth 2 provider to complete the authentication step, and finally, the user is redirected back to the client application.

          -

          Configure OAuth2 Login

          +

          Configure OAuth 2 Login

          - Before using OAuth2 login, you need to enable and configure a OAuth2 login provider. + Before using OAuth 2 login, you need to enable and configure an OAuth 2 login provider.

          1. Navigate to your Appwrite project
          2. Navigate to Auth > Settings
          3. Find and open the OAuth provider.
          4. -
          5. In the OAuth2 settings modal, use the toggle to enable the provider
          6. +
          7. In the OAuth 2 settings modal, use the toggle to enable the provider
          -

          Initialize OAuth2 Login

          +

          Initialize OAuth 2 Login

          - To initialize the OAuth2 login process, use the Create OAuth2 Session route. + To initialize the OAuth 2 login process, use the Create OAuth 2 Session route.

            @@ -105,12 +105,12 @@ try await account.createOAuth2Session(provider: "amazon")

            OAuth 2 Profile

            -After authenticating a user through their OAuth2 provider, you can fetch their profile information such as their avatar image or name. -To do this you can use the access token from the OAuth2 provider and make API calls to the provider. +After authenticating a user through their OAuth 2 provider, you can fetch their profile information such as their avatar image or name. +To do this you can use the access token from the OAuth 2 provider and make API calls to the provider.

            -After creating an OAuth2 session, you can fetch the session to get information about the provider. +After creating an OAuth 2 session, you can fetch the session to get information about the provider.

              @@ -128,7 +128,7 @@ const session = account.getSession('current'); // Provider information console.log(session.provider); console.log(session.providerUid); -console.log(session.provderAccessToken); +console.log(session.providerAccessToken);
            • @@ -149,7 +149,7 @@ final session = await getSession( // Provider information print(session.provider); print(session.providerUid); -print(session.provderAccessToken); +print(session.providerAccessToken);
            • Android

              @@ -170,7 +170,7 @@ val response = account.getSession( // Provider information print(session.provider); print(session.providerUid); -print(session.provderAccessToken); +print(session.providerAccessToken);
            • Apple

              @@ -190,12 +190,12 @@ let session = try await account.getSession( // Provider information print(session.provider); print(session.providerUid); -print(session.provderAccessToken); +print(session.providerAccessToken);

            - An OAuth2 session will have the following attributes. + An OAuth 2 session will have the following attributes.

            @@ -212,24 +212,24 @@ print(session.provderAccessToken); - + - - + +
            providerUid User ID from the OAuth2 Provider. User ID from the OAuth 2 Provider.
            provderAccessTokenAccess token from the OAuth2 provider. Use this to make requests to the OAuth2 provider to fetch personal information.providerAccessTokenAccess token from the OAuth 2 provider. Use this to make requests to the OAuth 2 provider to fetch personal information.

            - You can use the provderAccessToken to make requests to your OAuth2 provider. - Refer to the docs for the OAuth2 provider you're using to learn about making API calls with the access token. + You can use the providerAccessToken to make requests to your OAuth 2 provider. + Refer to the docs for the OAuth 2 provider you're using to learn about making API calls with the access token.

            Refresh Tokens

            - OAuth2 sessions expire to protect from security risks. - This means, OAuth2 sessions should be refreshed to keep the user authenticated. + OAuth 2 sessions expire to protect from security risks. + OAuth 2 sessions should be periodically refreshed to keep the user authenticated. You can do this by calling the Update OAuth Session endpoint when ever your user visits your app.

            diff --git a/app/views/docs/authentication-server.phtml b/app/views/docs/authentication-server.phtml index 7e54f1d2e..de1c90211 100644 --- a/app/views/docs/authentication-server.phtml +++ b/app/views/docs/authentication-server.phtml @@ -7,7 +7,7 @@

            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.

            +

            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' 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.

            @@ -26,7 +26,7 @@ const client = new Client() .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint - .setProject('[PROJECT_ID]'); // Your project ID + .setProject('[PROJECT_ID]'); // Your project ID const account = new Account(client); @@ -40,7 +40,7 @@ const user = await account.createJWT(); final client = Client() .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint - .setProject('[PROJECT_ID]'); // Your project ID + .setProject('[PROJECT_ID]'); // Your project ID final account = Account(client); @@ -56,7 +56,7 @@ import io.appwrite.services.Account val client = Client(context) .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint - .setProject("[PROJECT_ID]") // Your project ID + .setProject("[PROJECT_ID]") // Your project ID val account = Account(client) @@ -69,7 +69,7 @@ val jwt = account.createJWT() let client = Client() .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint - .setProject("[PROJECT_ID]") // Your project ID + .setProject("[PROJECT_ID]") // Your project ID let account = Account(client) @@ -99,8 +99,8 @@ 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 + .setProject('[PROJECT_ID]') // Your project ID + .setJWT('eyJJ9.eyJ...886ca'); // Your secret JSON Web Token
          • @@ -113,8 +113,8 @@ $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 + ->setProject('[PROJECT_ID]') // Your project ID + ->setJWT('eyJJ9.eyJ...886ca'); // Your secret JSON Web Token
          • @@ -125,9 +125,9 @@ $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 + .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 )
          • @@ -141,9 +141,9 @@ 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 + .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
          • @@ -154,9 +154,9 @@ client 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 + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('[PROJECT_ID]') // Your project ID + .setJWT('eyJJ9.eyJ...886ca'); // Your secret JSON Web Token
          • @@ -167,9 +167,9 @@ client 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 + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('[PROJECT_ID]') // Your project ID + .setJWT('eyJJ9.eyJ...886ca'); // Your secret JSON Web Token
          • @@ -180,9 +180,9 @@ 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 + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("[PROJECT_ID]") // Your project ID + .setJWT("eyJJ9.eyJ...886ca") // Your secret JSON Web Token
          • @@ -193,9 +193,9 @@ client 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 + .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .setProject("[PROJECT_ID]") // Your project ID + .setJWT("eyJJ9.eyJ...886ca") // Your secret JSON Web Token
          • @@ -206,9 +206,9 @@ client var 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 + .SetEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("[PROJECT_ID]") // Your project ID + .SetJWT("eyJJ9.eyJ...886ca"); // Your secret JSON Web Token
          @@ -343,9 +343,9 @@ response = databases.list_documents(database_id: '642f358bf4084c662590', '642f35 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 + .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); @@ -361,9 +361,9 @@ let promise = databases.listDocuments('642f358bf4084c662590', '642f3592aa5fc856a 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 + .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); @@ -382,9 +382,9 @@ Future result = databases.listDocuments( 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 + .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) @@ -403,9 +403,9 @@ val response = databases.listDocuments( 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 + .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) @@ -426,9 +426,9 @@ using Appwrite.Models; var 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 + .SetEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("[PROJECT_ID]") // Your project ID + .SetJWT("eyJJ9.eyJ...886ca"); // Your secret JSON Web Token var databases = new Databases(client); @@ -461,7 +461,7 @@ var documentList = await databases.ListDocuments( } -

          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.

          +

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

          • Node.js

            @@ -471,9 +471,9 @@ var documentList = await databases.ListDocuments( 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 + .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); @@ -490,9 +490,9 @@ const birthday = await databases.listDocuments('642f358bf4084c662590', '642f3592 $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 + ->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); @@ -508,9 +508,9 @@ $result = $databases->listDocuments('642f358bf4084c662590', '642f3592aa5fc856ad1 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 + .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) @@ -529,9 +529,9 @@ 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 + .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) @@ -547,9 +547,9 @@ response = databases.list_documents(database_id: '642f358bf4084c662590', '642f35 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 + .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); @@ -565,9 +565,9 @@ let promise = databases.listDocuments('642f358bf4084c662590', '642f3592aa5fc856a 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 + .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); @@ -586,9 +586,9 @@ Future result = databases.listDocuments( 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 + .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) @@ -607,9 +607,9 @@ val response = databases.listDocuments( 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 + .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) @@ -630,9 +630,9 @@ using Appwrite.Models; var 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 + .SetEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint + .SetProject("[PROJECT_ID]") // Your project ID + .SetKey("919c2d18fb5d4...a2ae413da83346ad2"); // Your secret API key var databases = new Databases(client); diff --git a/app/views/docs/authentication-sms.phtml b/app/views/docs/authentication-sms.phtml index 54aea908e..8e03e7880 100644 --- a/app/views/docs/authentication-sms.phtml +++ b/app/views/docs/authentication-sms.phtml @@ -33,7 +33,7 @@ const sessionToken = await account.createPhoneSession( '+14255550123' ); -var userId = sessionToken.userId // Store this somewhere to use later when logging in +var userId = sessionToken.userId; // Store this somewhere to use later when logging in
          • @@ -52,7 +52,7 @@ final sessionToken = await account.createPhoneSession( phone: '+14255550123' ); -final userId = sessionToken.userId // Store this somewhere to use later when logging in +final userId = sessionToken.userId; // Store this somewhere to use later when logging in
          • Android

            @@ -110,7 +110,7 @@ let userId = sessionToken.userId // Store this somewhere to use later when loggi

            Log In

            - After initiation, the returned user ID and secret are used to confirm the user. + After initiating the phone authentication process, the returned user ID and secret are used to confirm the user. The secret will usually be a 6-digit number in the SMS message sent to the user.

            diff --git a/app/views/docs/authentication.phtml b/app/views/docs/authentication.phtml index 917c20852..bade8dfc9 100644 --- a/app/views/docs/authentication.phtml +++ b/app/views/docs/authentication.phtml @@ -125,7 +125,7 @@ mutation { Use the Users API when acting as an administrator in use cases like building admin consoles or server integrations. The Users API uses API keys to authenticate, which means Appwrite only knows which API key is accessing data. API keys don't respect permissions, which means they can access all data, and should never be shared with end users in client applications. - The Users API also has batch operations, letting your query and manage users from an admin's perspective. + The Users API also has batch operations, letting you query and manage users from an admin's perspective.

            Explore

            @@ -177,4 +177,4 @@ mutation { Security -

            +

            \ No newline at end of file From 47dd97178925e79f9f2c2a6a37d589fa3f40cf84 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Mon, 21 Aug 2023 21:19:22 +0000 Subject: [PATCH 16/21] Where applicable, prefer promises because it's copyable. --- app/views/docs/authentication-anonymous.phtml | 8 +- .../docs/authentication-email-pass.phtml | 215 ++++++++++++++++-- app/views/docs/authentication-magic.phtml | 12 +- app/views/docs/authentication-oauth.phtml | 76 ++++--- app/views/docs/authentication.phtml | 2 +- 5 files changed, 254 insertions(+), 59 deletions(-) diff --git a/app/views/docs/authentication-anonymous.phtml b/app/views/docs/authentication-anonymous.phtml index e9a73943a..4992ebe29 100644 --- a/app/views/docs/authentication-anonymous.phtml +++ b/app/views/docs/authentication-anonymous.phtml @@ -26,7 +26,13 @@ const client = new Client() const account = new Account(client); -const user = await account.createAnonymousSession(); +const promise = account.createAnonymousSession(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +});
          • diff --git a/app/views/docs/authentication-email-pass.phtml b/app/views/docs/authentication-email-pass.phtml index 31a4b5580..d5f77c4ed 100644 --- a/app/views/docs/authentication-email-pass.phtml +++ b/app/views/docs/authentication-email-pass.phtml @@ -22,11 +22,13 @@ const client = new Client() const account = new Account(client); -const user = await account.create( - ID.unique(), - 'email@example.com', - 'password' -); +const promise = account.create('[USER_ID]', 'email@example.com', ''); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +});
          • @@ -120,30 +122,114 @@ mutation {
          • Web

            -
            +
            import { Client, Account } from "appwrite";
            +
            +const client = new Client();
            +
            +const account = new Account(client);
            +
            +client
            +    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
            +    .setProject('5df5acd0d48c2') // Your project ID
            +;
            +
            +const promise = account.createVerification('https://example.com');
            +
            +promise.then(function (response) {
            +    console.log(response); // Success
            +}, function (error) {
            +    console.log(error); // Failure
            +});
          • Flutter

            -
            +
            import 'package:appwrite/appwrite.dart';
            +
            +void main() { // Init SDK
            +  Client client = Client();
            +  Account account = Account(client);
            +
            +  client
            +    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
            +    .setProject('5df5acd0d48c2') // Your project ID
            +  ;
            +  Future result = account.createVerification(
            +    url: 'https://example.com',
            +  );
            +
            +  result
            +    .then((response) {
            +      print(response);
            +    }).catchError((error) {
            +      print(error.response);
            +  });
            +}
          • Android

            -
            +
            import androidx.appcompat.app.AppCompatActivity
            +import android.os.Bundle
            +import kotlinx.coroutines.GlobalScope
            +import kotlinx.coroutines.launch
            +import io.appwrite.Client
            +import io.appwrite.services.Account
            +
            +class MainActivity : AppCompatActivity() {
            +    override fun onCreate(savedInstanceState: Bundle?) {
            +        super.onCreate(savedInstanceState)
            +        setContentView(R.layout.activity_main)
            +
            +        val client = Client(applicationContext)
            +            .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
            +            .setProject("5df5acd0d48c2") // Your project ID
            +
            +        val account = Account(client)
            +
            +        GlobalScope.launch {
            +            val response = account.createVerification(
            +                url = "https://example.com"
            +            )
            +            val json = response.body?.string()        
            +        }
            +    }
            +}
          • Apple

            -
            +
            import Appwrite
            +
            +func main() async throws {
            +    let client = Client()
            +      .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
            +      .setProject("5df5acd0d48c2") // Your project ID
            +    let account = Account(client)
            +    let token = try await account.createVerification(
            +        url: "https://example.com"
            +    )
            +
            +    print(String(describing: token)
            +}
          • GraphQL

            -
            +
            mutation {
            +    accountCreateVerification(
            +        url: "https://example.com"
            +    ) {
            +        _id
            +        _createdAt
            +        userId
            +        secret
            +        expire
            +    }
            +}
          @@ -154,6 +240,10 @@ mutation { In this example, the code below will be found in the page served at https://example.com/verify.

          +

          + Since the secrets are passed in through url params, it will be easiest to perform this step in the browser. +

          +
          • Web

            @@ -178,6 +268,84 @@ promise.then(function (response) { console.log(error); }); +
          • +
          • +

            Flutter

            +
            +
            import 'package:appwrite/appwrite.dart';
            +
            +void main() { // Init SDK
            +  Client client = Client();
            +  Account account = Account(client);
            +
            +  client
            +    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
            +    .setProject('5df5acd0d48c2') // Your project ID
            +  ;
            +  Future result = account.updateVerification(
            +    userId: '[USER_ID]',
            +    secret: '[SECRET]',
            +  );
            +
            +  result
            +    .then((response) {
            +      print(response);
            +    }).catchError((error) {
            +      print(error.response);
            +  });
            +}
            +
          • +
          • +

            Android

            +
            +
            import io.appwrite.Client
            +import io.appwrite.services.Account
            +
            +val client = Client(context)
            +    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
            +    .setProject("5df5acd0d48c2") // Your project ID
            +
            +val account = Account(client)
            +
            +val response = account.updateVerification(
            +    userId = "[USER_ID]",
            +    secret = "[SECRET]"
            +)
            +
            +
          • +
          • +

            Apple

            +
            +
            import Appwrite
            +
            +let client = Client()
            +    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
            +    .setProject("5df5acd0d48c2") // Your project ID
            +
            +let account = Account(client)
            +
            +let token = try await account.updateVerification(
            +    userId: "[USER_ID]",
            +    secret: "[SECRET]"
            +)
            +
            +
          • +
          • +

            GraphQL

            +
            +
            mutation {
            +    accountUpdateVerification(
            +        userId: "[USER_ID]",
            +        secret: "[SECRET]"
            +    ) {
            +        _id
            +        _createdAt
            +        userId
            +        secret
            +        expire
            +    }
            +}
            +
          @@ -200,10 +368,13 @@ const client = new Client() const account = new Account(client); -const user = await account.createEmailSession( - 'email@example.com', - 'password' -); +const promise = account.createEmailSession('email@example.com', 'password'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +});
        • @@ -289,9 +460,13 @@ 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.createRecovery('email@example.com', 'https://example.com'); -const user = await account.createPasswordRecovery('email@example.com', 'https://example.com'); +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +});
        • @@ -376,9 +551,13 @@ 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.updateRecovery('[USER_ID]', '[SECRET]', 'password', 'password'); -const user = await account.updateRecovery('[USER_ID]', '[SECRET]', 'password', 'password'); +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +});
        • diff --git a/app/views/docs/authentication-magic.phtml b/app/views/docs/authentication-magic.phtml index d5aeb16f4..e50694877 100644 --- a/app/views/docs/authentication-magic.phtml +++ b/app/views/docs/authentication-magic.phtml @@ -24,10 +24,14 @@ const client = new Client() const account = new Account(client); -const user = await account.createMagicURLSession( - ID.unique(), - 'email@example.com' - ); + +const promise = account.createMagicURLSession('[USER_ID]', 'email@example.com'); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +});
        • diff --git a/app/views/docs/authentication-oauth.phtml b/app/views/docs/authentication-oauth.phtml index dc99af316..e136c6af7 100644 --- a/app/views/docs/authentication-oauth.phtml +++ b/app/views/docs/authentication-oauth.phtml @@ -123,7 +123,7 @@ const client = new Client(); const account = new Account(client); -const session = account.getSession('current'); +const session = await account.getSession('current'); // Provider information console.log(session.provider); @@ -237,38 +237,38 @@ print(session.providerAccessToken);
        • Web

          -
          import { Client, Account } from "appwrite";
          -
          -const client = new Client();
          -
          -const account = new Account(client);
          -
          -client
          -    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
          -    .setProject('[PROJECT_ID]')                  // Your Project ID
          -;
          +        
          const promise = account.updateSession('[SESSION_ID]');
           
          -// Go to Amazon OAuth login page
          -account.createOAuth2Session('amazon', '[LINK_ON_SUCCESS]', '[LINK_ON_FAILURE]');
          +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +});
        • Flutter

          import 'package:appwrite/appwrite.dart';
          -void main() async {
          -    final client = new Client();
          -    final account = new Account(client);
          -    
          -    client
          -        .setEndpoint('https://cloud.appwrite.io/v1') // YOUR API Endpoint
          -        .setProject('[PROJECT_ID]')                  // YOUR PROJECT ID
          -    ;
          -    
          -    // OAuth Login, for simplest implementation you can leave both success and
          -    // failure link empty so that Appwrite handles everything.
          -    await account.createOAuth2Session(provider: 'amazon');
          -        
          +
          +void main() { // Init SDK
          +  Client client = Client();
          +  Account account = Account(client);
          +
          +  client
          +    .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
          +    .setProject('5df5acd0d48c2') // Your project ID
          +  ;
          +  Future result = account.updateSession(
          +    sessionId: '[SESSION_ID]',
          +  );
          +
          +  result
          +    .then((response) {
          +      print(response);
          +    }).catchError((error) {
          +      print(error.response);
          +  });
           }
        • @@ -280,23 +280,29 @@ import io.appwrite.services.Account val client = Client(context) .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint - .setProject("[PROJECT_ID]") // Your Project ID + .setProject("5df5acd0d48c2") // Your project ID val account = Account(client) -account.createOAuth2Session(provider = "amazon") +val response = account.updateSession( + sessionId = "[SESSION_ID]" +)
        • Apple

          -
          func scene(_ scene: UIScene, openURLContexts URLContexts: Set) {
          -    guard let url = URLContexts.first?.url,
          -        url.absoluteString.contains("appwrite-callback") else {
          -        return
          -    }
          -    WebAuthComponent.handleIncomingCookie(from: url)
          -}
          +
          import Appwrite
          +
          +let client = Client()
          +    .setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
          +    .setProject("5df5acd0d48c2") // Your project ID
          +
          +let account = Account(client)
          +
          +let session = try await account.updateSession(
          +    sessionId: "[SESSION_ID]"
          +)
        • diff --git a/app/views/docs/authentication.phtml b/app/views/docs/authentication.phtml index bade8dfc9..05e44aa9c 100644 --- a/app/views/docs/authentication.phtml +++ b/app/views/docs/authentication.phtml @@ -145,7 +145,7 @@ mutation {

          - Log in with magic URL + Log in with Magic URL

          From 7d01bd477acbb8dfdca04fade1d8acb779af81cc Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Wed, 23 Aug 2023 00:34:39 +0000 Subject: [PATCH 17/21] Personal Information -> Data --- app/views/docs/authentication-email-pass.phtml | 2 +- app/views/docs/authentication-oauth.phtml | 2 +- app/views/docs/authentication-security.phtml | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/views/docs/authentication-email-pass.phtml b/app/views/docs/authentication-email-pass.phtml index d5f77c4ed..8fde1db9a 100644 --- a/app/views/docs/authentication-email-pass.phtml +++ b/app/views/docs/authentication-email-pass.phtml @@ -639,7 +639,7 @@ let token = try await account.updateRecovery(

          Security

          Appwrite's security first mindset goes beyond a securely implementated of authentication API. - You can enable features like password dictionary, password history, and disallow personal information to encourage users to pick better passwords. + You can enable features like password dictionary, password history, and disallow personal data in passwords to encourage users to pick better passwords. By enabling these features, you protect user data and teach better password choices, which helps make the internet a safer place.

          diff --git a/app/views/docs/authentication-oauth.phtml b/app/views/docs/authentication-oauth.phtml index e136c6af7..2d87b8f7b 100644 --- a/app/views/docs/authentication-oauth.phtml +++ b/app/views/docs/authentication-oauth.phtml @@ -216,7 +216,7 @@ print(session.providerAccessToken); providerAccessToken - Access token from the OAuth 2 provider. Use this to make requests to the OAuth 2 provider to fetch personal information. + Access token from the OAuth 2 provider. Use this to make requests to the OAuth 2 provider to fetch personal data. diff --git a/app/views/docs/authentication-security.phtml b/app/views/docs/authentication-security.phtml index 776c320d8..9bae92804 100644 --- a/app/views/docs/authentication-security.phtml +++ b/app/views/docs/authentication-security.phtml @@ -97,9 +97,9 @@

          Password dictionary can be enabled in the Auth service's Security tab on the Appwrite console.

          -

          Personal Information

          +

          Personal Data

          - Encourage passwords that are hard to guess by disallowing users to pick passwords that contain personal information. - Personal information includes the user's name, email, and phone number. + Encourage passwords that are hard to guess by disallowing users to pick passwords that contain personal data. + Personal data includes the user's name, email, and phone number.

          -

          Disallowing personal information can be enabled in the Auth service's Security tab on the Appwrite console.

          +

          Disallowing personal data can be enabled in the Auth service's Security tab on the Appwrite console.

          From cda41f592d8cfbc5b83243a93335cdefe536af61 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Wed, 23 Aug 2023 00:52:59 +0000 Subject: [PATCH 18/21] address OAuth2 issues like redirect --- app/views/docs/authentication-oauth.phtml | 58 ++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) diff --git a/app/views/docs/authentication-oauth.phtml b/app/views/docs/authentication-oauth.phtml index 2d87b8f7b..c1ab9671c 100644 --- a/app/views/docs/authentication-oauth.phtml +++ b/app/views/docs/authentication-oauth.phtml @@ -41,7 +41,7 @@ const client = new Client() const account = new Account(client); // Go to OAuth provider login page -account.createOAuth2Session('amazon'); +account.createOAuth2Session('amazon', [LINK_ON_SUCCESS], [LINK_ON_FAILURE]);
        • @@ -61,6 +61,26 @@ await account.createOAuth2Session(provider: 'amazon');
        • Android

          +

          In order to capture the Appwrite OAuth callback url, the following activity needs to be added inside the `<application>` tag, along side the existing `<activity>` tags in your AndroidManifest.xml. Be sure to replace the [PROJECT_ID] string with your actual Appwrite project ID. You can find your Appwrite project ID in your project settings screen in your Appwrite console.

          + +
          +
          escape('
          +  ...
          +  
          +    ...
          +    
          +    
          +      
          +        
          +        
          +        
          +        
          +      
          +    
          +  
          +'); ?>
          +
          +
          import io.appwrite.Client
           import io.appwrite.services.Account
          @@ -77,6 +97,38 @@ account.createOAuth2Session(provider = "amazon")
        • Apple

          +

          In order to capture the Appwrite OAuth callback url, the following URL scheme needs to added to your `Info.plist`

          + +
          +
          escape('CFBundleURLTypes
          +
          +
          +    CFBundleTypeRole
          +    Editor
          +    CFBundleURLName
          +    io.appwrite
          +    CFBundleURLSchemes
          +    
          +        appwrite-callback-[PROJECT_ID]
          +    
          +
          +
          +');?>
          +
          + +

          If you're using UIKit, you'll also need to add a hook to your SceneDelegate.swift file to ensure cookies work correctly.

          + +
          +
          escape('
          +func scene(_ scene: UIScene, openURLContexts URLContexts: Set) {
          +    guard let url = URLContexts.first?.url,
          +        url.absoluteString.contains("appwrite-callback") else {
          +        return
          +    }
          +    WebAuthComponent.handleIncomingCookie(from: url)
          +}
          +');?>
          +
          import Appwrite
           
          @@ -103,6 +155,10 @@ try await account.createOAuth2Session(provider: "amazon")
          Once complete, you'll be redirected to the redirect URL configured in your OAuth 2 provider.

          +

          + You can optionally configure success or failure redirect links on web to handle success and failure scenarios. +

          +

          OAuth 2 Profile

          After authenticating a user through their OAuth 2 provider, you can fetch their profile information such as their avatar image or name. From a4eac315c321292cceabb71a5a15a117e85b7fe7 Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Wed, 23 Aug 2023 00:57:40 +0000 Subject: [PATCH 19/21] improve getting started guide because we should --- app/views/docs/authentication-oauth.phtml | 6 +++--- app/views/docs/getting-started-for-android.phtml | 2 +- app/views/docs/getting-started-for-apple.phtml | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/views/docs/authentication-oauth.phtml b/app/views/docs/authentication-oauth.phtml index c1ab9671c..0a3ec4854 100644 --- a/app/views/docs/authentication-oauth.phtml +++ b/app/views/docs/authentication-oauth.phtml @@ -61,7 +61,7 @@ await account.createOAuth2Session(provider: 'amazon');

        • Android

          -

          In order to capture the Appwrite OAuth callback url, the following activity needs to be added inside the `<application>` tag, along side the existing `<activity>` tags in your AndroidManifest.xml. Be sure to replace the [PROJECT_ID] string with your actual Appwrite project ID. You can find your Appwrite project ID in your project settings screen in your Appwrite console.

          +

          In order to capture the Appwrite OAuth callback url, the following activity needs to be added inside the <application> tag, along side the existing <activity> tags in your AndroidManifest.xml. Be sure to replace the [PROJECT_ID] string with your actual Appwrite project ID. You can find your Appwrite project ID in your project settings screen in your Appwrite console.

          escape('
          @@ -97,7 +97,7 @@ account.createOAuth2Session(provider = "amazon")
        • Apple

          -

          In order to capture the Appwrite OAuth callback url, the following URL scheme needs to added to your `Info.plist`

          +

          In order to capture the Appwrite OAuth callback url, the following URL scheme needs to added to your Info.plist.

          escape('CFBundleURLTypes
          @@ -116,7 +116,7 @@ account.createOAuth2Session(provider = "amazon")
          ');?>
          -

          If you're using UIKit, you'll also need to add a hook to your SceneDelegate.swift file to ensure cookies work correctly.

          +

          If you're using UIKit, you'll also need to add a hook to your SceneDelegate.swift file to ensure cookies work correctly.

          escape('
          diff --git a/app/views/docs/getting-started-for-android.phtml b/app/views/docs/getting-started-for-android.phtml
          index 74d35cbf0..c410e4caa 100644
          --- a/app/views/docs/getting-started-for-android.phtml
          +++ b/app/views/docs/getting-started-for-android.phtml
          @@ -40,7 +40,7 @@ $androidVersion = (isset($versions['android'])) ? $versions['android'] : '';
           
           

          OAuth Callback

          -

          In order to capture the Appwrite OAuth callback url, the following activity needs to be added inside the `<application>` tag, along side the existing `<activity>` tags in your AndroidManifest.xml. Be sure to replace the [PROJECT_ID] string with your actual Appwrite project ID. You can find your Appwrite project ID in your project settings screen in your Appwrite console.

          +

          In order to capture the Appwrite OAuth callback url, the following activity needs to be added inside the <application> tag, along side the existing <activity> tags in your AndroidManifest.xml. Be sure to replace the [PROJECT_ID] string with your actual Appwrite project ID. You can find your Appwrite project ID in your project settings screen in your Appwrite console.

          escape('
          diff --git a/app/views/docs/getting-started-for-apple.phtml b/app/views/docs/getting-started-for-apple.phtml
          index fc6ce3038..2e71911d9 100644
          --- a/app/views/docs/getting-started-for-apple.phtml
          +++ b/app/views/docs/getting-started-for-apple.phtml
          @@ -64,7 +64,7 @@ $appleVersion = $versions['apple'] ?? '';
           
           

          OAuth Callback

          -

          In order to capture the Appwrite OAuth callback url, the following URL scheme needs to added to your `Info.plist`

          +

          In order to capture the Appwrite OAuth callback url, the following URL scheme needs to added to your Info.plist.

          escape('CFBundleURLTypes
          @@ -83,7 +83,7 @@ $appleVersion = $versions['apple'] ?? '';
           ');?>
          -

          If you're using UIKit, you'll also need to add a hook to your SceneDelegate.swift file to ensure cookies work correctly.

          +

          If you're using UIKit, you'll also need to add a hook to your SceneDelegate.swift file to ensure cookies work correctly.

          escape('
          
          From 3eaa24612b83692fb221185647b42c596a9e83e9 Mon Sep 17 00:00:00 2001
          From: "Vincent (Wen Yu) Ge" 
          Date: Sun, 27 Aug 2023 11:17:01 -0400
          Subject: [PATCH 20/21] Apply suggestions from code review
          MIME-Version: 1.0
          Content-Type: text/plain; charset=UTF-8
          Content-Transfer-Encoding: 8bit
          
          Co-authored-by: Matej Bačo 
          ---
           app/views/docs/authentication-magic.phtml    | 2 +-
           app/views/docs/authentication-oauth.phtml    | 2 +-
           app/views/docs/authentication-security.phtml | 2 +-
           3 files changed, 3 insertions(+), 3 deletions(-)
          
          diff --git a/app/views/docs/authentication-magic.phtml b/app/views/docs/authentication-magic.phtml
          index e50694877..7ef26927f 100644
          --- a/app/views/docs/authentication-magic.phtml
          +++ b/app/views/docs/authentication-magic.phtml
          @@ -1,6 +1,6 @@
           

          Magic URL is a password-less way to authenticate users. - When a user logs in, they will receive an email with a "magic" link that contains a secret used to log in the user. + When a user logs in by providing their email, they will receive an email with a "magic" link that contains a secret used to log in the user. The user can simply click the link to be logged in.

          diff --git a/app/views/docs/authentication-oauth.phtml b/app/views/docs/authentication-oauth.phtml index 0a3ec4854..e8dee928b 100644 --- a/app/views/docs/authentication-oauth.phtml +++ b/app/views/docs/authentication-oauth.phtml @@ -284,7 +284,7 @@ print(session.providerAccessToken);

          Refresh Tokens

          - OAuth 2 sessions expire to protect from security risks. + OAuth 2 access tokens expire to protect from security risks. OAuth 2 sessions should be periodically refreshed to keep the user authenticated. You can do this by calling the Update OAuth Session endpoint when ever your user visits your app.

          diff --git a/app/views/docs/authentication-security.phtml b/app/views/docs/authentication-security.phtml index 9bae92804..ed68f5229 100644 --- a/app/views/docs/authentication-security.phtml +++ b/app/views/docs/authentication-security.phtml @@ -102,4 +102,4 @@ Encourage passwords that are hard to guess by disallowing users to pick passwords that contain personal data. Personal data includes the user's name, email, and phone number.

          -

          Disallowing personal data can be enabled in the Auth service's Security tab on the Appwrite console.

          +

          Disallowing personal data can be enabled in the Auth service's Security tab on the Appwrite Console.

          From 56213ec352b30326859e6bdbd2cdf7aa4f8cd85f Mon Sep 17 00:00:00 2001 From: "Vincent (Wen Yu) Ge" Date: Sun, 27 Aug 2023 19:29:31 +0000 Subject: [PATCH 21/21] Fix code example errors and other items pointed out during review --- app/views/docs/authentication-anonymous.phtml | 2 +- app/views/docs/authentication-magic.phtml | 106 +----------------- .../docs/authentication-management.phtml | 48 +++++--- app/views/docs/authentication-oauth.phtml | 15 ++- 4 files changed, 50 insertions(+), 121 deletions(-) diff --git a/app/views/docs/authentication-anonymous.phtml b/app/views/docs/authentication-anonymous.phtml index 4992ebe29..a64394aca 100644 --- a/app/views/docs/authentication-anonymous.phtml +++ b/app/views/docs/authentication-anonymous.phtml @@ -97,7 +97,7 @@ mutation {

          Attaching an Account

          Anonymous users cannot sign back in. - If they close their browser, or go to another computer, they won't be able to log in again. + If the session expires, they move to another computer, or they clear their browser data, they won't be able to log in again. Remember to prompt the user to create an account to not lose their data.

          diff --git a/app/views/docs/authentication-magic.phtml b/app/views/docs/authentication-magic.phtml index e50694877..2e3ea2262 100644 --- a/app/views/docs/authentication-magic.phtml +++ b/app/views/docs/authentication-magic.phtml @@ -8,7 +8,7 @@

          Initialize the log in process with the Create Magic URL Session route. - If the email has never been used, a new user ID is generated, then the user will receive an email. + If the email has never been used, a new account is generated, then the user will receive an email. If the email is already attached to an account, the user ID is ignored and the user will receive a link in their email.

          @@ -25,7 +25,7 @@ const client = new Client() const account = new Account(client); -const promise = account.createMagicURLSession('[USER_ID]', 'email@example.com'); +const promise = account.createMagicURLSession(ID.unique(), 'email@example.com'); promise.then(function (response) { console.log(response); // Success @@ -34,61 +34,12 @@ promise.then(function (response) { });
        • -
        • -

          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 user = await account.createMagicURLSession(
          -    userId: ID.unique(),
          -    email: 'email@example.com',
          -);
          -
        • -
        • -

          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 user = account.createMagicURLSession(
          -    userId = ID.unique(),
          -    email = "email@example.com"
          -)
          -
        • -
        • -

          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 user = try await account.createMagicURLSession(
          -    userId: ID.unique(),
          -    email: "email@example.com"
          -)
          -
        • GraphQL

          mutation {
               accountCreateMagicURLSession(
          -        userId: "email@example.com",
          +        userId: "ID.unique()",
                   email: "email@example.com"
               ) {
                   _id
          @@ -127,61 +78,12 @@ const userId = urlParams.get('userId');
           const user = await account.updateMagicURLSession(userId, secret);
        • -
        • -

          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 user = await account.updateMagicURLSession(
          -    userId: 'email@example.com',
          -    secret: '[SECRET]',
          -);
          -
        • -
        • -

          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 user = account.updateMagicURLSession(
          -    userId = 'email@example.com',
          -    secret = '[SECRET]'
          -)
          -
        • -
        • -

          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 user = try await account.updateMagicURLSession(
          -    userId: 'email@example.com',
          -    secret: "[SECRET]"
          -)
          -
        • GraphQL

          mutation {
               accountUpdateMagicURLSession(
          -        userId: "email@example.com",
          +        userId: "[USER_ID]",
                   secret: "[SECRET]"
               ) {
                   _id
          diff --git a/app/views/docs/authentication-management.phtml b/app/views/docs/authentication-management.phtml
          index 4e3514b27..d0b15fb2a 100644
          --- a/app/views/docs/authentication-management.phtml
          +++ b/app/views/docs/authentication-management.phtml
          @@ -26,7 +26,13 @@ const client = new Client()
           
           const account = new Account(client);
           
          -const user = await account.updatePrefs({darkTheme: true, language: 'en'});
          +const promise = account.updatePrefs({darkTheme: true, language: 'en'}); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +});
        • @@ -86,16 +92,7 @@ let user = try await account.updatePrefs( prefs: "{\"darkTheme\": true, \"language\": \"en\"}" ) { _id - _createdAt - _updatedAt name - registration - status - passwordUpdate - email - phone - emailVerification - phoneVerification prefs { data } @@ -119,7 +116,13 @@ const client = new Client() const account = new Account(client); -const user = await account.getPrefs(); +const promise = account.getPrefs(); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +});
        • @@ -205,11 +208,24 @@ let prefs = try await account.getPrefs()
          const sdk = require('node-appwrite');
           
          +// Init SDK
           const client = new sdk.Client();
           
           const users = new sdk.Users(client);
           
          -let res = await users.updateLabels('[USER_ID]', [ Role.label('subscriber') ]);
          +client + .setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint + .setProject('5df5acd0d48c2') // Your project ID + .setKey('919c2d18fb5d4...a2ae413da83346ad2') // Your secret API key +; + +const promise = users.updateLabels('[USER_ID]', [ Role.label('subscriber') ]); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +});
        • @@ -294,7 +310,13 @@ client ; -let res = await users.updateLabels('[USER_ID]', [ Role.label('subscriber') ]); +const promise = users.updateLabels('[USER_ID]', [ Role.label('subscriber') ]); + +promise.then(function (response) { + console.log(response); // Success +}, function (error) { + console.log(error); // Failure +});
        • diff --git a/app/views/docs/authentication-oauth.phtml b/app/views/docs/authentication-oauth.phtml index 0a3ec4854..00fa1c211 100644 --- a/app/views/docs/authentication-oauth.phtml +++ b/app/views/docs/authentication-oauth.phtml @@ -15,10 +15,13 @@

            -
          1. Navigate to your Appwrite project
          2. -
          3. Navigate to Auth > Settings
          4. +
          5. Navigate to your Appwrite project.
          6. +
          7. Navigate to Auth > Settings.
          8. Find and open the OAuth provider.
          9. -
          10. In the OAuth 2 settings modal, use the toggle to enable the provider
          11. +
          12. In the OAuth 2 settings modal, use the toggle to enable the provider.
          13. +
          14. Create and OAuth 2 app on the provider's developer platform.
          15. +
          16. Copy information from your OAuth2 provider's developer platform to fill the OAuth2 Settings modal in the Appwrite Console.
          17. +
          18. Configure redirect URL in your OAuth 2 provider's developer platform. Set it to URL provided to you by OAuth2 Settings modal in Appwrite Console.
          @@ -152,7 +155,7 @@ try await account.createOAuth2Session(provider: "amazon")

          You'll be redirected to the OAuth 2 provider's login page to log in. - Once complete, you'll be redirected to the redirect URL configured in your OAuth 2 provider. + Once complete, your user will be redirected back to your app.

          @@ -285,7 +288,9 @@ print(session.providerAccessToken);

          Refresh Tokens

          OAuth 2 sessions expire to protect from security risks. - OAuth 2 sessions should be periodically refreshed to keep the user authenticated. + OAuth 2 sessions should be refreshed periodically, so access tokens don't expire. + Check value of providerAccessTokenExpiry to know if the token is expired or is about to expire. + Refreshing before every request might cause rate limit problems. You can do this by calling the Update OAuth Session endpoint when ever your user visits your app.