mirror of
https://github.com/LukeHagar/website.git
synced 2025-12-11 04:22:19 +00:00
Merge pull request #912 from appwrite/feat-expand-auth-quickstart
Improve account overview page
This commit is contained in:
@@ -68,9 +68,10 @@ const languages = {
|
||||
const platformAliases: Record<string, keyof typeof languages> = {
|
||||
[Platform.ClientWeb]: 'js',
|
||||
[Platform.ClientFlutter]: 'dart',
|
||||
[Platform.ClientApple]: 'swift',
|
||||
[Platform.ClientAndroidJava]: 'java',
|
||||
[Platform.ClientAndroidKotlin]: 'kotlin',
|
||||
[Platform.ClientApple]: 'swift',
|
||||
[Platform.ClientReactNative]: 'js',
|
||||
[Platform.ClientGraphql]: 'graphql',
|
||||
[Platform.ClientRest]: 'http',
|
||||
[Platform.ServerDart]: 'dart',
|
||||
|
||||
@@ -29,6 +29,7 @@ export enum Platform {
|
||||
ClientApple = 'client-apple',
|
||||
ClientAndroidKotlin = 'client-android-kotlin',
|
||||
ClientAndroidJava = 'client-android-java',
|
||||
ClientReactNative = 'client-react-native',
|
||||
ClientGraphql = 'client-graphql',
|
||||
ClientRest = 'client-rest',
|
||||
ServerNodeJs = 'server-nodejs',
|
||||
@@ -51,6 +52,7 @@ export const platformMap: Record<Language | string, string> = {
|
||||
[Platform.ClientWeb]: 'Web',
|
||||
[Platform.ClientAndroidKotlin]: 'Android (Kotlin)',
|
||||
[Platform.ClientAndroidJava]: 'Android (Java)',
|
||||
[Platform.ClientReactNative]: 'React Native',
|
||||
[Platform.ClientGraphql]: 'GraphQL',
|
||||
[Platform.ClientRest]: 'REST',
|
||||
[Platform.ServerDart]: 'Dart',
|
||||
|
||||
@@ -8,9 +8,50 @@ back: /docs
|
||||
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 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 manage users.
|
||||
|
||||
{% arrow_link href="/docs/products/auth/quick-start" %}
|
||||
Quick start
|
||||
Add authentication to your app in 5 minutes
|
||||
{% /arrow_link %}
|
||||
|
||||
# Authentication methods {% #auth-methods %}
|
||||
Appwrite supports a variety of authentication methods to fit every app and every niche. Explore Appwrite's authentication flows.
|
||||
|
||||
{% cards %}
|
||||
{% cards_item href="/docs/products/auth/email-password" title="Email and password" %}
|
||||
Email and password login with just a few lines of code secured with state of the art Argon2 hasing.
|
||||
{% /cards_item %}
|
||||
{% cards_item href="/docs/products/auth/phone-sms" title="Phone (SMS)" %}
|
||||
Log in users with out a password using their phone number and SMS verification.
|
||||
{% /cards_item %}
|
||||
{% cards_item href="/docs/products/auth/magic-url" title="Magic URL" %}
|
||||
Passwordless login with a magic link sent to the user's email.
|
||||
{% /cards_item %}
|
||||
{% cards_item href="/docs/products/auth/email-otp" title="Email OTP" %}
|
||||
Generate a time-based single-use password sent to the user's email.
|
||||
{% /cards_item %}
|
||||
{% cards_item href="/docs/products/auth/oauth2" title="OAuth 2" %}
|
||||
Authenticate users with existing accounts from GitHub, Google, Facebook, and 30+ other providers.
|
||||
{% /cards_item %}
|
||||
{% cards_item href="/docs/products/auth/anonymous" title="Anonymous" %}
|
||||
Create guest sessions for visitors and convert to full accounts when they're ready.
|
||||
{% /cards_item %}
|
||||
{% cards_item href="/docs/products/auth/jwt" title="JWT" %}
|
||||
Deligate access for a user through passing JWT tokens.
|
||||
{% /cards_item %}
|
||||
{% cards_item href="/docs/products/auth/server-side-rendering" title="Server-side rendering (SSR)" %}
|
||||
Authenticate users in server-side rendered applications.
|
||||
{% /cards_item %}
|
||||
{% cards_item href="/docs/products/auth/custom-token" title="Custom Token" %}
|
||||
Implement custom authentication methods like biometric and passkey login by generating custom tokens.
|
||||
{% /cards_item %}
|
||||
{% cards_item href="/docs/products/auth/mfa" title="Multifactor authentication (MFA)" %}
|
||||
Implementing MFA to add extra layers of security to your app.
|
||||
{% /cards_item %}
|
||||
{% /cards %}
|
||||
|
||||
# Flexible permissions {% #flexible-permissions %}
|
||||
When users sign up using Appwrite, their identity is automatically attached to a robust permissions system.
|
||||
Appwrite Authentication provides permissions for individual users and groups of users through [teams](/docs/products/auth/teams) and [labels](/docs/products/auth/labels).
|
||||
|
||||
# Built in preferences {% #built-in-preferences %}
|
||||
Appwrite Authentication comes with built-in [preferences](/docs/products/auth/accounts#preferences) for users to manage their account settings.
|
||||
Store notification settings, themes, and other user preferences to be shared across devices.
|
||||
@@ -4,10 +4,9 @@ title: Start with Authentication
|
||||
description: Effortlessly add authentication to your apps - simple signup & login in just minutes with Appwrite Authentication
|
||||
---
|
||||
You can get up and running with Appwrite Authentication in minutes.
|
||||
Adding signup and login is as simple as this.
|
||||
|
||||
# Sign up {% #sign-up %}
|
||||
You can add basic email and password authentication to your app with just a few lines of code.
|
||||
|
||||
{% section #sign-up step=1 title="Signup" %}
|
||||
You can use the Appwrite [Client SDKs](/docs/sdks#client) to create an account using email and password.
|
||||
|
||||
{% multicode %}
|
||||
@@ -20,13 +19,11 @@ const client = new Client()
|
||||
|
||||
const account = new Account(client);
|
||||
|
||||
const promise = account.create('[USER_ID]', 'email@example.com', '');
|
||||
|
||||
promise.then(function (response) {
|
||||
console.log(response); // Success
|
||||
}, function (error) {
|
||||
console.log(error); // Failure
|
||||
});
|
||||
const user await = account.create(
|
||||
'ID.unique()',
|
||||
'email@example.com',
|
||||
'password'
|
||||
);
|
||||
```
|
||||
```client-flutter
|
||||
import 'package:appwrite/appwrite.dart';
|
||||
@@ -76,7 +73,6 @@ val user = account.create(
|
||||
)
|
||||
```
|
||||
```graphql
|
||||
|
||||
mutation {
|
||||
accountCreate(userId: "unique()", email: "email@example.com", password: "password") {
|
||||
_id
|
||||
@@ -85,15 +81,8 @@ mutation {
|
||||
}
|
||||
}
|
||||
```
|
||||
{% /multicode %}
|
||||
|
||||
# Login {% #login %}
|
||||
|
||||
After you've created your account, users can be logged in using the [Create Email Session](/docs/references/cloud/client-web/account#createEmailSession) method.
|
||||
|
||||
{% multicode %}
|
||||
```client-web
|
||||
import { Client, Account } from "appwrite";
|
||||
```client-react-native
|
||||
import { Client, Account, ID } from "appwrite";
|
||||
|
||||
const client = new Client()
|
||||
.setEndpoint('https://cloud.appwrite.io/v1') // Your API Endpoint
|
||||
@@ -101,24 +90,29 @@ const client = new Client()
|
||||
|
||||
const account = new Account(client);
|
||||
|
||||
const promise = account.createEmailSession('email@example.com', 'password');
|
||||
const user await = account.create(
|
||||
'ID.unique()',
|
||||
'email@example.com',
|
||||
'password'
|
||||
);
|
||||
```
|
||||
{% /multicode %}
|
||||
|
||||
promise.then(function (response) {
|
||||
console.log(response); // Success
|
||||
}, function (error) {
|
||||
console.log(error); // Failure
|
||||
});
|
||||
{% /section %}
|
||||
|
||||
{% section #login step=2 title="Login" %}
|
||||
|
||||
After you've created your account, users can be logged in using the [Create Email Session](/docs/references/cloud/client-web/account#createEmailSession) method.
|
||||
|
||||
{% multicode %}
|
||||
```client-web
|
||||
const session = await account.createEmailSession(
|
||||
email,
|
||||
password
|
||||
);
|
||||
```
|
||||
|
||||
```client-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 account.createEmailSession(
|
||||
email: 'email@example.com',
|
||||
password: 'password'
|
||||
@@ -126,14 +120,6 @@ final session = await account.createEmailSession(
|
||||
```
|
||||
|
||||
```client-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 session = try await account.createEmailSession(
|
||||
email: "email@example.com",
|
||||
password: "password"
|
||||
@@ -141,15 +127,6 @@ let session = try await account.createEmailSession(
|
||||
```
|
||||
|
||||
```client-android-kotlin
|
||||
import io.appwrite.Client
|
||||
import io.appwrite.services.Account
|
||||
|
||||
val client = Client()
|
||||
.setEndpoint("https://cloud.appwrite.io/v1") // Your API Endpoint
|
||||
.setProject("<PROJECT_ID>") // Your project ID
|
||||
|
||||
val account = Account(client)
|
||||
|
||||
val session = account.createEmailSession(
|
||||
email = "email@example.com",
|
||||
password = "password"
|
||||
@@ -166,14 +143,561 @@ mutation {
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```client-react-native
|
||||
const session = await account.createEmailSession(
|
||||
email,
|
||||
password
|
||||
);
|
||||
```
|
||||
{% /multicode %}
|
||||
{% /section %}
|
||||
|
||||
# More ways to authenticate {% #more-ways-to-authenticate %}
|
||||
You can signup and login a user with an account create through
|
||||
[email password](/docs/products/auth/email-password),
|
||||
[phone (SMS)](/docs/products/auth/phone-sms),
|
||||
[Anonymous](/docs/products/auth/anonymous)
|
||||
[magic URL](/docs/products/auth/magic-url), and
|
||||
[OAuth 2](/docs/products/auth/oauth2)
|
||||
authentication.
|
||||
{% section #check-authentication-state step=3 title="Check authentication state" %}
|
||||
After logging in, you can check the authentication state of the user.
|
||||
|
||||
Appwrite's SDKs are stateless, so you need to manage the session state in your app.
|
||||
You can use the [Get Account](/docs/references/cloud/client-web/account#get) method to check if the user is logged in.
|
||||
|
||||
{% multicode %}
|
||||
```client-web
|
||||
try {
|
||||
const user = await account.get();
|
||||
// Logged in
|
||||
} catch (err) {
|
||||
// Not logged in
|
||||
}
|
||||
```
|
||||
```client-flutter
|
||||
try {
|
||||
final user = await account.get();
|
||||
// Logged in
|
||||
} catch(e) {
|
||||
// Not logged in
|
||||
}
|
||||
```
|
||||
```client-apple
|
||||
do {
|
||||
let user = try account.get()
|
||||
// Logged in
|
||||
} catch {
|
||||
// Not logged in
|
||||
}
|
||||
```
|
||||
```client-android-kotlin
|
||||
return try {
|
||||
val user = account.get()
|
||||
// Logged in
|
||||
} catch (e: AppwriteException) {
|
||||
// Not logged in
|
||||
}
|
||||
```
|
||||
```graphql
|
||||
query {
|
||||
accountGet {
|
||||
_id
|
||||
_createdAt
|
||||
_updatedAt
|
||||
name
|
||||
registration
|
||||
status
|
||||
labels
|
||||
passwordUpdate
|
||||
email
|
||||
phone
|
||||
emailVerification
|
||||
phoneVerification
|
||||
prefs {
|
||||
data
|
||||
}
|
||||
accessedAt
|
||||
}
|
||||
}
|
||||
```
|
||||
```client-react-native
|
||||
try {
|
||||
const user = await account.get();
|
||||
// Logged in
|
||||
} catch (err) {
|
||||
// Not logged in
|
||||
}
|
||||
```
|
||||
{% /multicode %}
|
||||
{% /section %}
|
||||
|
||||
{% section #auth-and-nav step=4 title="Navigation (Optional)" %}
|
||||
A common pattern is to use route guards to redirect users to the login page if they are not authenticated.
|
||||
You can check the authentication state on app launch and before entering a protected route by calling `get()`.
|
||||
|
||||
Route guard implementations are **opinionated** and depend on the platform and frame you are using.
|
||||
Take a look at some example usages from different platforms as inspiration.
|
||||
|
||||
{% accordion %}
|
||||
{% accordion_item title="Web frameworks" %}
|
||||
Before routing to a page, you can check if the user is logged in and redirect them to the login page if they are not.
|
||||
|
||||
{% tabs %}
|
||||
{% tabsitem #react-router title="React router" %}
|
||||
You can use [React router loaders](https://reactrouter.com/en/main/route/loader) to check if the user is logged in before rendering a route.
|
||||
```client-web
|
||||
import * as React from "react";
|
||||
import {
|
||||
createBrowserRouter,
|
||||
} from "react-router-dom";
|
||||
import "./index.css";
|
||||
|
||||
import Login from "./Login";
|
||||
import Protected from "./Protected";
|
||||
import { account } from "./lib/appwrite";
|
||||
import { redirect } from "react-router-dom";
|
||||
|
||||
|
||||
const router = createBrowserRouter([
|
||||
{
|
||||
path: "/protected",
|
||||
element: <Protected />,
|
||||
loader: async () => {
|
||||
try{
|
||||
// logged in? pass user to the route
|
||||
const user = await account.get();
|
||||
return { user };
|
||||
}
|
||||
catch {
|
||||
// not logged in? redirect to login
|
||||
throw redirect('/login')
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
path: "/login",
|
||||
element: <Login />,
|
||||
},
|
||||
]);
|
||||
|
||||
export default router;
|
||||
```
|
||||
{% /tabsitem %}
|
||||
{% tabsitem #vue-router title="Vue router" %}
|
||||
You can use [Vue router](https://router.vuejs.org/) wiht a [Pinia store](https://pinia.vuejs.org/) to check if the user is logged in before rendering a route.
|
||||
|
||||
First, create a simple Pinia store to manage the authentication state.
|
||||
```client-web
|
||||
import { account, ID, type Models } from '@/lib/appwrite'
|
||||
import type { register } from 'module';
|
||||
import { defineStore } from 'pinia'
|
||||
|
||||
export const useAuthStore = defineStore({
|
||||
id: 'auth',
|
||||
state: () => ({
|
||||
user: null as null | Models.User<Models.Preferences>,
|
||||
}),
|
||||
getters: {
|
||||
isLoggedIn(): boolean {
|
||||
return !!this.user;
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
async init() {
|
||||
try {
|
||||
this.user = await account.get();
|
||||
}
|
||||
catch (error) {
|
||||
this.user = null;
|
||||
}
|
||||
},
|
||||
// ... other operations
|
||||
},
|
||||
})
|
||||
```
|
||||
Then, check the authentication state before routing to a protected route.
|
||||
```client-web
|
||||
import { createApp } from 'vue'
|
||||
import { createPinia } from 'pinia'
|
||||
|
||||
import App from './App.vue'
|
||||
import router from './router'
|
||||
import { useAuthStore } from './stores/auth'
|
||||
|
||||
const app = createApp(App)
|
||||
app.use(createPinia())
|
||||
|
||||
const auth = useAuthStore();
|
||||
|
||||
auth.init().then(() => {
|
||||
router.beforeEach((to, from, next) => {
|
||||
// Not logged in?
|
||||
if (to.name == 'protected' && auth.isLoggedIn == false) {
|
||||
// Redirect to login if going to a protected route
|
||||
next({ name: 'login' })
|
||||
} else {
|
||||
next()
|
||||
}
|
||||
})
|
||||
app.use(router)
|
||||
app.mount('#app')
|
||||
})
|
||||
```
|
||||
{% /tabsitem %}
|
||||
{% tabsitem #angular-router title="Angular router" %}
|
||||
```client-web
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ActivatedRouteSnapshot, CanActivate, RouterStateSnapshot, UrlTree, Router } from '@angular/router';
|
||||
import { Observable, from, of } from 'rxjs';
|
||||
import { catchError, map } from 'rxjs/operators';
|
||||
import { account } from './lib/appwrite';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class AuthGuardGuard implements CanActivate {
|
||||
constructor(private router: Router) {}
|
||||
|
||||
canActivate(
|
||||
route: ActivatedRouteSnapshot,
|
||||
state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
|
||||
if (route.routeConfig?.path === "protected") {
|
||||
return this.checkLogin();
|
||||
}
|
||||
return of(true);
|
||||
}
|
||||
|
||||
private checkLogin(): Observable<boolean | UrlTree> {
|
||||
return from(account.get()).pipe(
|
||||
map(() => true),
|
||||
catchError(() => of(this.router.createUrlTree(['/login'])))
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
{% /tabsitem %}
|
||||
{% tabsitem #svelte title="Svelte" %}
|
||||
In the root level `+layout.svelte` file, you can check the authentication state before rendering a route.
|
||||
```client-web
|
||||
// src/routes/+layout.js
|
||||
import { appwrite } from "$lib/appwrite";
|
||||
|
||||
// Turn off SSR globally, turning the project into a static site
|
||||
export const ssr = false;
|
||||
|
||||
export const load = async () => {
|
||||
try {
|
||||
return {
|
||||
account: await appwrite.account.get(),
|
||||
};
|
||||
} catch {
|
||||
return {
|
||||
account: null,
|
||||
};
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
This will be accessible in the `load` function of each child route.
|
||||
```client-web
|
||||
// src/routes/protected/+page.js
|
||||
import { redirect } from '@sveltejs/kit';
|
||||
|
||||
/** @type {import('./$types').PageLoad} */
|
||||
export async function load({ parent }) {
|
||||
const { account } = await parent();
|
||||
if (!account) {
|
||||
throw redirect(303, '/login');
|
||||
}
|
||||
}
|
||||
```
|
||||
{% /tabsitem %}
|
||||
{% /tabs %}
|
||||
|
||||
{% /accordion_item %}
|
||||
{% accordion_item title="Mobile and native" %}
|
||||
With mobile apps, you can apply similar logic to check the authentication state before displaying a screen or view.
|
||||
|
||||
{% tabs %}
|
||||
{% tabsitem #flutter-go-router title="Flutter Go router" %}
|
||||
This example uses the Flutter Go router as an example, but the same concepts apply to other routing libraries.
|
||||
|
||||
First, create a `ChangeNotifier` to manage the authentication state.
|
||||
|
||||
```client-flutter
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:appwrite/appwrite.dart' show Client, ID;
|
||||
import 'package:appwrite/appwrite.dart' as Appwrite;
|
||||
import 'package:appwrite/models.dart' show User;
|
||||
|
||||
class Account extends ChangeNotifier {
|
||||
final Appwrite.Account _account;
|
||||
|
||||
User? _user;
|
||||
User? get user => _user;
|
||||
|
||||
Account(Client client) : _account = Appwrite.Account(client);
|
||||
|
||||
Future<void> init() async {
|
||||
try {
|
||||
_user = await _account.get();
|
||||
|
||||
notifyListeners();
|
||||
} catch(e) {
|
||||
debugPrint(e.toString());
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
// ... other operations
|
||||
}
|
||||
```
|
||||
|
||||
You can then use this state to redirect users to the login page if they are not authenticated.
|
||||
```client-flutter
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import './providers/account.dart';
|
||||
|
||||
import './pages/login.dart';
|
||||
import './pages/protected.dart';
|
||||
|
||||
String Function(BuildContext context, GoRouterState state) redirect =
|
||||
(BuildContext context, GoRouterState state) =>
|
||||
context.read<Account>().user == null && state.matchedLocation != '/login'
|
||||
? '/login'
|
||||
: state.matchedLocation;
|
||||
|
||||
final router = GoRouter(
|
||||
redirect: redirect,
|
||||
initialLocation: '/login',
|
||||
routes: [
|
||||
GoRoute(
|
||||
path: '/login',
|
||||
pageBuilder: (context, state) => const MaterialPage(child: LoginPage()),
|
||||
),
|
||||
GoRoute(
|
||||
path: '/protected',
|
||||
pageBuilder: (context, state) => const MaterialPage(child: ProtectedPage()),
|
||||
)
|
||||
],
|
||||
);
|
||||
```
|
||||
{% /tabsitem %}
|
||||
|
||||
{% tabsitem #apple title="Apple" %}
|
||||
For Apple platforms, this example uses a `NavigationStack` but you can use similar concepts with other navigation methods.
|
||||
|
||||
Initialize Appwrite and create an `AppwriteService`.
|
||||
```client-apple
|
||||
import Foundation
|
||||
import Appwrite
|
||||
import AppwriteModels
|
||||
import JSONCodable
|
||||
|
||||
class Appwrite {
|
||||
var client: Client
|
||||
var account: Account
|
||||
var databases: Databases
|
||||
let databaseId = "default"
|
||||
let collectionId = "ideas-tracker"
|
||||
|
||||
public init() {
|
||||
self.client = Client()
|
||||
.setEndpoint("https://cloud.appwrite.io/v1")
|
||||
.setProject("<YOUR_PROJECT_ID>")
|
||||
|
||||
self.account = Account(client)
|
||||
}
|
||||
public func getUser() async throws -> User<[String: AnyCodable]> {
|
||||
let user = try await account.get()
|
||||
// you can also store the user in a local store
|
||||
return user
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
On launch, you can display a `SplashView` while you verify the authentication state.
|
||||
```client-apple
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
|
||||
struct SplashView: View {
|
||||
@EnvironmentObject private var router: Router
|
||||
@EnvironmentObject private var AppwriteService: AppwriteService
|
||||
|
||||
var body: some View {
|
||||
NavigationStack(path: $router.routes) {
|
||||
VStack {
|
||||
Text("Example App")
|
||||
.font(.largeTitle)
|
||||
.fontWeight(.bold)
|
||||
.padding()
|
||||
}.task {
|
||||
let user = await self.AppwriteService.getUser();
|
||||
|
||||
if !user {
|
||||
router.pushReplacement(.login)
|
||||
} else {
|
||||
router.pushReplacement(.protected)
|
||||
}
|
||||
}
|
||||
.navigationDestination(for: Route.self, destination: { $0 })
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In your router, you can also check the authentication state before rendering a route.
|
||||
|
||||
```client-apple
|
||||
final class Router: ObservableObject {
|
||||
@Published var routes = [Route]()
|
||||
|
||||
func push(_ screen: Route) {
|
||||
// Make sure you've already stored the user and auth state in a local store
|
||||
if (screen == .protected && !isLoggedIn){
|
||||
routes.append(.login)
|
||||
}
|
||||
routes.append(screen)
|
||||
}
|
||||
// ... other operations
|
||||
}
|
||||
```
|
||||
{% /tabsitem %}
|
||||
{% tabsitem #android title="Android" %}
|
||||
Create some Appwrite Service, for example, `AppwriteService` to manage the authentication state.
|
||||
You can find a version of this example in the [Appwrite Android tutorial](/docs/tutorials/android/step-1).
|
||||
```client-android-kotlin
|
||||
//... imports
|
||||
|
||||
object Appwrite {
|
||||
private const val ENDPOINT = "https://cloud.appwrite.io/v1"
|
||||
private const val PROJECT_ID = "<YOUR_PROJECT_ID>"
|
||||
|
||||
private lateinit var client: Client
|
||||
|
||||
fun init(context: Context) {
|
||||
client = Client(context)
|
||||
.setEndpoint(ENDPOINT)
|
||||
.setProject(PROJECT_ID)
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Then, create an auth service to manage the authentication state.
|
||||
|
||||
```client-android-kotlin
|
||||
//... imports
|
||||
|
||||
class AccountService(client: Client) {
|
||||
private val account = Account(client)
|
||||
|
||||
suspend fun getLoggedIn(): User<Map<String, Any>>? {
|
||||
return try {
|
||||
account.get()
|
||||
} catch (e: AppwriteException) {
|
||||
null
|
||||
}
|
||||
}
|
||||
// ... other operations
|
||||
}
|
||||
```
|
||||
|
||||
Wrap your routes in some view, for example, `AppContent`, to check the authentication state before rendering a route.
|
||||
|
||||
```client-android-kotlin
|
||||
@Composable
|
||||
private fun AppContent(accountService: AccountService) {
|
||||
val user = remember { mutableStateOf<User<Map<String, Any>>?>(null) }
|
||||
val screen = remember { mutableStateOf(Screen.Protected) }
|
||||
|
||||
LaunchedEffect(screen) {
|
||||
user.value = accountService.getLoggedIn()
|
||||
}
|
||||
|
||||
Scaffold(bottomBar = { AppBottomBar(screen) }) { padding ->
|
||||
Column(modifier = Modifier.padding(padding)) {
|
||||
when (screen.value) {
|
||||
Screen.User -> LoginScreen(user, accountService)
|
||||
else -> ProtectedScreen(user.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In the `MainActivity` class, initialize the Appwrite service and display the `AppContent` based on the authentication state.
|
||||
|
||||
```client-android-kotlin
|
||||
// ...imports
|
||||
In the `MainActivity` class, initialize the Appwrite service.
|
||||
class MainActivity : ComponentActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
Appwrite.init(applicationContext)
|
||||
|
||||
setContent {
|
||||
// Update this line 👇
|
||||
AppContent(Appwrite.account)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
{% /tabsitem %}
|
||||
{% tabsitem #react-native title="React Native" %}
|
||||
This example will use `@react-navigation/native` and `@react-navigation/native-stack` to manage the authentication state and redirect users to the login page if they are not authenticated.
|
||||
You can find a version of this example in the [Appwrite Android tutorial](/docs/tutorials/android/step-1).
|
||||
|
||||
Create a `UserContext` to manage the authentication state.
|
||||
```client-react-native
|
||||
import { StyleSheet, Text, View } from 'react-native';
|
||||
import { UserProvider } from './contexts/UserContext';
|
||||
import { Router } from './lib/Router';
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
<UserProvider>
|
||||
<Router />
|
||||
</UserProvider >
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
Then, consume the `UserContext` in your `Router` component to check the authentication state before rendering a route.
|
||||
```client-react-native
|
||||
import { NavigationContainer } from '@react-navigation/native';
|
||||
import LoginScreen from '../views/Login';
|
||||
import ProtectedSCreen from '../views/Protected';
|
||||
import { createNativeStackNavigator } from '@react-navigation/native-stack';
|
||||
import { useUser } from '../contexts/UserContext';
|
||||
|
||||
const Stack = createNativeStackNavigator();
|
||||
export function Router() {
|
||||
const user = useUser();
|
||||
return (
|
||||
<NavigationContainer>
|
||||
<Stack.Navigator>
|
||||
{user.current == null ? (
|
||||
<Stack.Screen
|
||||
name="Login"
|
||||
component={LoginScreen}
|
||||
options={{ title: 'Login' }}
|
||||
/>
|
||||
) : (
|
||||
<Stack.Screen
|
||||
name="Protected"
|
||||
component={ProtectedSCreen}
|
||||
options={{ title: 'Protected' }}
|
||||
/>
|
||||
)}
|
||||
|
||||
</Stack.Navigator>
|
||||
</NavigationContainer>
|
||||
);
|
||||
}
|
||||
```
|
||||
{% /tabsitem %}
|
||||
{% /tabs %}
|
||||
{% /accordion_item %}
|
||||
{% /accordion %}
|
||||
{% /section %}
|
||||
|
||||
@@ -88,7 +88,7 @@ Open `App.js` and add the following code to it, replace `<YOUR_PROJECT_ID>` with
|
||||
|
||||
This imports and initializes Appwrite and defines some basic authentication methods.
|
||||
|
||||
```ts
|
||||
```client-react-native
|
||||
import { StatusBar } from 'expo-status-bar';
|
||||
import { StyleSheet, Text, View, TextInput, TouchableOpacity } from 'react-native';
|
||||
import { Client, Account, ID } from 'react-native-appwrite';
|
||||
@@ -137,7 +137,7 @@ With `Client` and `Account` service initialized, you can now use them to make yo
|
||||
|
||||
Add the following components to your `App.js` file to create a simple login form.
|
||||
|
||||
```ts
|
||||
```client-react-native
|
||||
<View style={styles.root}>
|
||||
<Text>
|
||||
{loggedInUser ? `Logged in as ${loggedInUser.name}` : 'Not logged in'}
|
||||
@@ -192,7 +192,7 @@ Add the following components to your `App.js` file to create a simple login form
|
||||
|
||||
You can also add some simple styling to your app by adding the following styles to your `App.js` file.
|
||||
|
||||
```ts
|
||||
```client-react-native
|
||||
const styles = StyleSheet.create({
|
||||
root: {
|
||||
marginTop: 40,
|
||||
|
||||
@@ -12,7 +12,7 @@ You can use a context and a custom hook to manage our user's data.
|
||||
|
||||
Create a new file `contexts/UserContext.jsx` and add the following code to it.
|
||||
|
||||
```js
|
||||
```client-react-native
|
||||
import { ID } from "react-native-appwrite";
|
||||
import { createContext, useContext, useEffect, useState } from "react";
|
||||
import { account } from "../lib/appwrite";
|
||||
@@ -76,7 +76,7 @@ For a better user experience, display toasts when the users perform an action, s
|
||||
|
||||
We can do this by creating a new file `lib/toast.js` and adding the following code to it.
|
||||
|
||||
```js
|
||||
```client-react-native
|
||||
import { ToastAndroid, Platform, AlertIOS } from 'react-native';
|
||||
|
||||
export function toast(msg) {
|
||||
@@ -93,7 +93,7 @@ Create a new file `views/Login.jsx` and add the following code to it.
|
||||
this page contains a basic form to allow the user to login or register.
|
||||
Notice how this page consumes the `useUser` hook to access the user's data and perform login and register actions.
|
||||
|
||||
```js
|
||||
```client-react-native
|
||||
import React, { useState } from 'react';
|
||||
import { View, Text, TextInput, Button, StyleSheet } from 'react-native';
|
||||
import { useUser } from '../contexts/UserContext';
|
||||
|
||||
@@ -12,7 +12,7 @@ Based on the user's login status, you'll redirect them to the login page or the
|
||||
Create a new file `views/Home.jsx` and add the following stub code to it.
|
||||
We'll update this page later to display the ideas posted by other users and allow the user to post their ideas.
|
||||
|
||||
```js
|
||||
```client-react-native
|
||||
import React from 'react';
|
||||
import { View, Text } from 'react-native';
|
||||
import { useUser } from '../contexts/UserContext';
|
||||
@@ -37,7 +37,7 @@ To handle basic routing, you can use the `react-navigation` library.
|
||||
This router also consumes the `UserContext` to determine if the user is logged in or not to redirect the user automatically.
|
||||
|
||||
Create a file `lib/Router.jsx` and add the following code to it.
|
||||
```js
|
||||
```client-react-native
|
||||
import { NavigationContainer } from '@react-navigation/native';
|
||||
import LoginScreen from '../views/Login';
|
||||
import HomeScreen from '../views/Home';
|
||||
@@ -72,7 +72,7 @@ export function Router() {
|
||||
|
||||
We'll display this router in the `App.js` file.
|
||||
|
||||
```js
|
||||
```client-react-native
|
||||
|
||||
import { StyleSheet, Text, View } from 'react-native';
|
||||
import { UserProvider } from './contexts/UserContext';
|
||||
|
||||
@@ -45,7 +45,7 @@ Now that you have a collection to hold ideas, we can read and write to it from o
|
||||
Like you did with the user data, we will create a React context to hold our ideas.
|
||||
Create a new file `contexts/IdeasContext.jsx` and add the following code to it.
|
||||
|
||||
```js
|
||||
```client-react-native
|
||||
import { ID, Permission, Role, Query } from "react-native-appwrite";
|
||||
import { createContext, useContext, useEffect, useState } from "react";
|
||||
import { databases } from "../lib/appwrite";
|
||||
@@ -108,7 +108,7 @@ This permission ensures that only the user who created the idea can modify it.
|
||||
|
||||
Remeber to add the `IdeasProvider` to your `App.js` file.
|
||||
|
||||
```js
|
||||
```client-react-native
|
||||
|
||||
import { StyleSheet, Text, View } from 'react-native';
|
||||
import { UserProvider } from './contexts/UserContext';
|
||||
|
||||
@@ -13,7 +13,7 @@ that only the owner of the idea can remove it.
|
||||
|
||||
Overwrite the contents of `views/Home.jsx` with the following:
|
||||
|
||||
```js
|
||||
```client-react-native
|
||||
import React, { useState } from 'react';
|
||||
import { View, Text, TextInput, Button, StyleSheet, ScrollView } from 'react-native';
|
||||
import { useUser } from '../contexts/UserContext';
|
||||
|
||||
Reference in New Issue
Block a user