# Authenticating users

The Rust SDK for SurrealDB supports a number of methods for authenticating users and securing the database.

**3.x**

The [`.signup()`](https://docs.rs/surrealdb/latest/surrealdb/struct.Surreal.html#method.signup) and [`.signin()`](https://docs.rs/surrealdb/latest/surrealdb/struct.Surreal.html#method.signin) methods are used for both system users (users created with a [DEFINE USER](/docs/reference/query-language/statements/define/user.md) statement) and record users (users created with a [DEFINE ACCESS](/docs/reference/query-language/statements/define/access.md) statement). These two methods take any type that implements the [`Credentials`](https://docs.rs/surrealdb/latest/surrealdb/opt/auth/trait.Credentials.html) trait, namely the structs [`Root`](https://docs.rs/surrealdb/latest/surrealdb/opt/auth/struct.Root.html), [`Namespace`](https://docs.rs/surrealdb/latest/surrealdb/opt/auth/struct.Namespace.html), [`Database`](https://docs.rs/surrealdb/latest/surrealdb/opt/auth/struct.Database.html), and [`Record`](https://docs.rs/surrealdb/latest/surrealdb/opt/auth/struct.Record.html).

```rust
pub struct Root {
    pub username: String,
    pub password: String,
}

pub struct Namespace {
    pub namespace: String,
    pub username: String,
    pub password: String,
}

pub struct Database {
    pub namespace: String,
    pub database: String,
    pub username: String,
    pub password: String,
}

pub struct Record<P: SurrealValue> {
    pub namespace: String,
    pub database: String,
    pub access: String,
    pub params: P,
}
```

The `access` and `params` fields of the `Record` struct are the only one of the four that requires extra explanation.

The `access` field comes from the name of the [access method](/docs/reference/query-language/statements/define/access/record.md) used to create a record user. In our case, we will use an access method called 'account'. An access method will generally create a record on signup, and select a record on signin, which is the case with our access method as well.

```surql
DEFINE ACCESS account ON DATABASE TYPE RECORD
	SIGNUP ( CREATE user SET name = $name, pass = crypto::argon2::generate($pass) )
	SIGNIN ( SELECT * FROM user WHERE name = $name AND crypto::argon2::compare(pass, $pass) )
	DURATION FOR TOKEN 15m, FOR SESSION 12h;
```

Since the `params` of a `Record` struct used to sign up and sign can be any type that implements `SurrealValue`, we can put our own struct together and pass them into these methods. On signup, the database will CREATE a `user` record that holds the name and password, and on signin it will SELECT the user that has a matching name and password.

```rust
#[derive(SurrealValue)]
struct Params {
    name: String,
    pass: String,
}

db.signup(Record {
    access: "account".to_string(),
    namespace: "namespace".to_string(),
    database: "database".to_string(),
    params: Params {
        name: "username".to_string(),
        pass: "Str0ngpAASSword!".to_string(),
    },
})
```

All of the definitions for this example are as follows.

```surql
DEFINE TABLE person SCHEMALESS
    PERMISSIONS FOR 
        CREATE, SELECT WHERE $auth,
        FOR UPDATE, DELETE WHERE created_by = $auth;
DEFINE FIELD name ON TABLE person TYPE string;
DEFINE FIELD created_by ON TABLE person VALUE $auth READONLY;

DEFINE INDEX unique_name ON TABLE user FIELDS name UNIQUE;
DEFINE ACCESS account ON DATABASE TYPE RECORD
SIGNUP ( CREATE user SET name = $name, pass = crypto::argon2::generate($pass) )
SIGNIN ( SELECT * FROM user WHERE name = $name AND crypto::argon2::compare(pass, $pass) )
DURATION FOR TOKEN 15m, FOR SESSION 12h
```

Whenever a record user is signed into the database, the `$auth` parameter will be populated with its record ID. The `DEFINE TABLE` statement then uses this to give the record user permissions to `CREATE` and `SELECT` any `person` record, but to `UPDATE` and `DELETE` only when the `created_by` field matches the ID in `$auth`. This `created_by` field is automatically set and is `READONLY`. It will show up as `None` when a system user is signed in.

The `.signup()` and `.signin()` methods return an `AccessToken`, which can be printed out if needed using the `.into_insecure_token()` or `.as_insecure_token()` methods. As the method names imply, great care should be taken care with them. The `AccessToken` struct redacts the token so printing out a `AccessToken` on its own will not display it.

The sample code below uses a crate called [`faker_rand`](https://docs.rs/faker_rand/latest/faker_rand/index.html) to generate a random name and password to make it easy to rerun the code and experiment with the behaviour.

```rust
async fn make_new_user(db: &Surreal<Client>) -> Result<RecordUser, Error> {
    let name = rand::random::<FirstName>().to_string();
    let pass = rand::random::<FirstName>().to_string();
    println!("Signing in as user {name} and password {pass}");
    let jwt = db
        .signup(Record {
            access: "account".to_string(),
            namespace: "namespace".to_string(),
            database: "database".to_string(),
            params: Params {
                name: name,
                pass: pass,
            },
        })
        .await?
        .into_insecure_token();
    println!("New user created!\n\nName: {name}\nPassword: {pass}\nToken: {jwt}\n\nTo log in, use this command:\n\nsurreal sql --namespace namespace --database database --pretty --token \"{jwt}\"\n");
    Ok(RecordUser { name, pass })
}

async fn get_new_token(db: &Surreal<Client>, user: &RecordUser) -> Result<(), Error> {
    let jwt = db
        .signin(Record {
            access: "account".to_string(),
            namespace: "namespace".to_string(),
            database: "database".to_string(),
            params: Params {
                name: user.name,
                pass: user.pass,
            },
        })
        .await?
        .into_insecure_token();
    println!("New token! Sign in with surreal sql --namespace namespace --database database --pretty --token \"{jwt}\"\n");
    Ok(())
}
```

The entire code is as follows. Inside `main()`, the client first logs in as a root user to define the schema and create a `person` record. It then signs up as a new record user, and then signs in again to demonstrate that a new token is returned each time this method is called (as long as the name and password match). The record user then creates a `person` record - which it is permitted to do - and then tries to delete all of the `person` records in the database. However, the `person` record created by the root user will remain untouched.

```rust
use fake::{Fake, faker::name::en::FirstName};
use surrealdb::{
    Error, Surreal,
    engine::any::{Any, connect},
    opt::auth::{Record, Root},
    types::{RecordId, SurrealValue},
};

#[derive(Debug, SurrealValue)]
struct Person {
    name: String,
    id: RecordId,
    created_by: Option<RecordId>,
}

#[derive(SurrealValue)]
struct Params {
    name: String,
    pass: String,
}

#[derive(SurrealValue)]
struct RecordUser {
    name: String,
    pass: String,
}

async fn make_new_user(db: &Surreal<Any>) -> Result<RecordUser, Error> {
    let name: String = FirstName().fake();
    let pass: String = FirstName().fake();
    println!("Signing in as user {name} and password {pass}");
    let jwt = db
        .signup(Record {
            access: "account".to_string(),
            namespace: "main".to_string(),
            database: "main".to_string(),
            params: Params {
                name: name.clone(),
                pass: pass.clone(),
            },
        })
        .await?
        .access
        .into_insecure_token();
    println!(
        "New user created!\n\nName: {name}\nPassword: {pass}\nToken: {jwt}\n\nTo log in, use this command:\n\nsurreal sql --namespace namespace --database database --pretty --token \"{jwt}\"\n"
    );
    Ok(RecordUser { name, pass })
}

async fn get_new_token(db: &Surreal<Any>, user: RecordUser) -> Result<(), Error> {
    let jwt = db
        .signin(Record {
            access: "account".to_string(),
            namespace: "main".to_string(),
            database: "main".to_string(),
            params: Params {
                name: user.name,
                pass: user.pass,
            },
        })
        .await?;
    println!(
        "New token! Sign in with surreal sql --pretty --token \"{}\"\n",
        jwt.access.into_insecure_token()
    );
    Ok(())
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let db = connect("ws://localhost:8000").await?;

    db.use_ns("main").use_db("main").await?;

    db.signin(Root {
        username: "root".into(),
        password: "secret".into(),
    })
    .await?;

    db.query(
        "DEFINE TABLE person SCHEMALESS
        PERMISSIONS FOR
            CREATE, SELECT WHERE $auth,
            FOR UPDATE, DELETE WHERE created_by = $auth;
    DEFINE FIELD name ON TABLE person TYPE string;
    DEFINE FIELD created_by ON TABLE person VALUE $auth READONLY;

    DEFINE INDEX unique_name ON TABLE user FIELDS name UNIQUE;
    DEFINE ACCESS account ON DATABASE TYPE RECORD
	SIGNUP ( CREATE user SET name = $name, pass = crypto::argon2::generate($pass) )
	SIGNIN ( SELECT * FROM user WHERE name = $name AND crypto::argon2::compare(pass, $pass) )
	DURATION FOR TOKEN 15m, FOR SESSION 12h
;",
    )
    .await?;

    db.query("CREATE person SET name = 'Created by root'")
        .await?;

    let user = make_new_user(&db).await?;

    get_new_token(&db, user).await?;

    db.query("CREATE person SET name = 'Created by record user'")
        .await?;

    println!(
        "Two `person` records: {:?}\n",
        db.select::<Vec<Person>>("person").await?
    );

    db.query("DELETE person").await?;

    println!(
        "`person` created by root is still there: {:?}\n",
        db.select::<Vec<Person>>("person").await?
    );

    Ok(())
}
```

Example output:

```text
Signing in as user Emmett and password Izaiah
New user created!

Name: Emmett
Password: Izaiah
Token: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJpYXQiOjE3MzA4NjQ2NDAsIm5iZiI6MTczMDg2NDY0MCwiZXhwIjoxNzMwODY1NTQwLCJpc3MiOiJTdXJyZWFsREIiLCJqdGkiOiIwNmYwOGFhZi0zYzIyLTQ5N2UtYWRmNC0zNDMxMzA5YWYxOGEiLCJOUyI6Im5hbWVzcGFjZSIsIkRCIjoiZGF0YWJhc2UiLCJBQyI6ImFjY291bnQiLCJJRCI6InVzZXI6YW92bHN0dzBvN2R1Y2J4ZWpqZWsifQ.tHCVlubg3G2j05-LsEaE6jRHMwrBtccJcR6uC9Z6Lo-egrYlBybEEfOZh020OxWxKvUt8eA92-6TjwBvSpN5KA

To log in, use this command:

surreal sql --pretty --token "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJpYXQiOjE3MzA4NjQ2NDAsIm5iZiI6MTczMDg2NDY0MCwiZXhwIjoxNzMwODY1NTQwLCJpc3MiOiJTdXJyZWFsREIiLCJqdGkiOiIwNmYwOGFhZi0zYzIyLTQ5N2UtYWRmNC0zNDMxMzA5YWYxOGEiLCJOUyI6Im5hbWVzcGFjZSIsIkRCIjoiZGF0YWJhc2UiLCJBQyI6ImFjY291bnQiLCJJRCI6InVzZXI6YW92bHN0dzBvN2R1Y2J4ZWpqZWsifQ.tHCVlubg3G2j05-LsEaE6jRHMwrBtccJcR6uC9Z6Lo-egrYlBybEEfOZh020OxWxKvUt8eA92-6TjwBvSpN5KA"

New token! Sign in with surreal sql --pretty --token "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJpYXQiOjE3MzA4NjQ2NDAsIm5iZiI6MTczMDg2NDY0MCwiZXhwIjoxNzMwODY1NTQwLCJpc3MiOiJTdXJyZWFsREIiLCJqdGkiOiIyZjExZTQzZi04ODg1LTRmNzAtOGI2Zi0zNGZmZGZlZWY4MDUiLCJOUyI6Im5hbWVzcGFjZSIsIkRCIjoiZGF0YWJhc2UiLCJBQyI6ImFjY291bnQiLCJJRCI6InVzZXI6YW92bHN0dzBvN2R1Y2J4ZWpqZWsifQ.0GWwMiAjn5kKUoNAw2TxAdVLhWIHeJsVWvlAzw1QZ91qdIhkazygdG5uFl5DHVmmoYC-cLo-ko27jiRCid5xDg"

Two `person` records: [Person { name: "Created by record user", id: RecordId { table: "person", key: String("i2sv6bqk0mso0udgzmdx") }, created_by: Some(RecordId { table: "user", key: String("aovlstw0o7ducbxejjek") }) }, Person { name: "Created by root", id: RecordId { table: "person", key: String("u6mry7agmsmtbwl94yui") }, created_by: None }]

`person` created by root is still there: [Person { name: "Created by root", id: RecordId { table: "person", key: String("u6mry7agmsmtbwl94yui") }, created_by: None }]
```

## See also

Each of the crates featured in the Rust SDK also use the schema above. Three of them (Actix, Axum, Rocket) are web servers, while Egui is a visual UI. See the mini tutorials for each of these crates here:

* [Actix](/docs/reference/rust/frameworks/actix.md)
* [Axum](/docs/reference/rust/frameworks/axum.md)
* [Rocket](/docs/reference/rust/frameworks/rocket.md)
* [Egui](/docs/reference/rust/frameworks/egui.md)

Learn more about authentication in SurrealDB in our [security best practices](/docs/learn/security/best-practices/security-best-practices.md#authentication) documentation and in the [security](/docs/learn/security/authentication/authentication.md#expiration) section of the SurrealDB documentation.

**2.x**

The [`.signup()`](https://docs.rs/surrealdb/latest/surrealdb/struct.Surreal.html#method.signup) and [`.signin()`](https://docs.rs/surrealdb/latest/surrealdb/struct.Surreal.html#method.signin) methods are used for both system users (users created with a [DEFINE USER](/docs/reference/query-language/statements/define/user.md) statement) and record users (users created with a [DEFINE ACCESS](/docs/reference/query-language/statements/define/access.md) statement). These two methods take any type that implements the [`Credentials`](https://docs.rs/surrealdb/latest/surrealdb/opt/auth/trait.Credentials.html) trait, namely the structs [`Root`](https://docs.rs/surrealdb/latest/surrealdb/opt/auth/struct.Root.html), [`Namespace`](https://docs.rs/surrealdb/latest/surrealdb/opt/auth/struct.Namespace.html), [`Database`](https://docs.rs/surrealdb/latest/surrealdb/opt/auth/struct.Database.html), and [`Record`](https://docs.rs/surrealdb/latest/surrealdb/opt/auth/struct.Record.html).

```rust
pub struct Root<'a> {
    pub username: &'a str,
    pub password: &'a str,
}

pub struct Namespace<'a> {
    pub namespace: &'a str,
    pub username: &'a str,
    pub password: &'a str,
}

pub struct Database<'a> {
    pub namespace: &'a str,
    pub database: &'a str,
    pub username: &'a str,
    pub password: &'a str,
}

// P: any type that implements Serialize
pub struct Record<'a, P> {
    pub namespace: &'a str,
    pub database: &'a str,
    pub access: &'a str,
    pub params: P,
}
```

The `access` and `params` fields of the `Record` struct are the only one of the four that requires extra explanation.

The `access` field comes from the name of the [access method](/docs/reference/query-language/statements/define/access/record.md) used to create a record user. In our case, we will use an access method called 'account'. An access method will generally create a record on signup, and select a record on signin, which is the case with our access method as well.

```surql
DEFINE ACCESS account ON DATABASE TYPE RECORD
	SIGNUP ( CREATE user SET name = $name, pass = crypto::argon2::generate($pass) )
	SIGNIN ( SELECT * FROM user WHERE name = $name AND crypto::argon2::compare(pass, $pass) )
	DURATION FOR TOKEN 15m, FOR SESSION 12h;
```

Since the `params` of a `Record` struct used to sign up and sign can be any type that implements `Serialize`, we can put our own struct together and pass them into these methods. On signup, the database will CREATE a `user` record that holds the name and password, and on signin it will SELECT the user that has a matching name and password.

```rust
#[derive(Serialize, Deserialize)]
struct Params<'a> {
    name: &'a str,
    pass: &'a str,
}

db.signup(Record {
    access: "account",
    namespace: "namespace",
    database: "database",
    params: Params {
        name: "username",
        pass: "Str0ngpAASSword!",
    },
})
```

All of the definitions for this example are as follows.

```surql
DEFINE TABLE person SCHEMALESS
    PERMISSIONS FOR 
        CREATE, SELECT WHERE $auth,
        FOR UPDATE, DELETE WHERE created_by = $auth;
DEFINE FIELD name ON TABLE person TYPE string;
DEFINE FIELD created_by ON TABLE person VALUE $auth READONLY;

DEFINE INDEX unique_name ON TABLE user FIELDS name UNIQUE;
DEFINE ACCESS account ON DATABASE TYPE RECORD
SIGNUP ( CREATE user SET name = $name, pass = crypto::argon2::generate($pass) )
SIGNIN ( SELECT * FROM user WHERE name = $name AND crypto::argon2::compare(pass, $pass) )
DURATION FOR TOKEN 15m, FOR SESSION 12h
```

Whenever a record user is signed into the database, the `$auth` parameter will be populated with its record ID. The `DEFINE TABLE` statement then uses this to give the record user permissions to `CREATE` and `SELECT` any `person` record, but to `UPDATE` and `DELETE` only when the `created_by` field matches the ID in `$auth`. This `created_by` field is automatically set and is `READONLY`. It will show up as `None` when a system user is signed in.

The `.signup()` and `.signin()` methods return a [`Jwt`](https://docs.rs/surrealdb/latest/surrealdb/opt/auth/struct.Jwt.html), which can be printed out if needed using the `.into_insecure_token()` or `.as_insecure_token()` methods. As the method names imply, great care should be taken care with them. The `Jwt` struct redacts the token so printing out a `Jwt` on its own will not display it.

The code uses a crate called [`faker_rand`](https://docs.rs/faker_rand/latest/faker_rand/index.html) to generate a random name and password to make it easy to rerun the code and experiment with the behaviour.

```rust
async fn make_new_user(db: &Surreal<Client>) -> Result<RecordUser, Error> {
    let name = rand::random::<FirstName>().to_string();
    let pass = rand::random::<FirstName>().to_string();
    println!("Signing in as user {name} and password {pass}");
    let jwt = db
        .signup(Record {
            access: "account",
            namespace: "namespace",
            database: "database",
            params: Params {
                name: &name,
                pass: &pass,
            },
        })
        .await?
        .into_insecure_token();
    println!("New user created!\n\nName: {name}\nPassword: {pass}\nToken: {jwt}\n\nTo log in, use this command:\n\nsurreal sql --namespace namespace --database database --pretty --token \"{jwt}\"\n");
    Ok(RecordUser { name, pass })
}

async fn get_new_token(db: &Surreal<Client>, user: &RecordUser) -> Result<(), Error> {
    let jwt = db
        .signin(Record {
            access: "account",
            namespace: "namespace",
            database: "database",
            params: Params {
                name: &user.name,
                pass: &user.pass,
            },
        })
        .await?
        .into_insecure_token();
    println!("New token! Sign in with surreal sql --namespace namespace --database database --pretty --token \"{jwt}\"\n");
    Ok(())
}
```

The entire code is as follows. Inside `main()`, the client first logs in as a root user to define the schema and create a `person` record. It then signs up as a new record user, and then signs in again to demonstrate that a new token is returned each time this method is called (as long as the name and password match). The record user then creates a `person` record - which it is permitted to do - and then tries to delete all of the `person` records in the database. However, the `person` record created by the root user will remain untouched.

```rust
use surrealdb::engine::remote::ws::Client;
use surrealdb::engine::remote::ws::Ws;
use surrealdb::opt::auth::Root;
use surrealdb::Surreal;

use faker_rand::en_us::names::FirstName;
use surrealdb::opt::auth::Record;

use serde::{Deserialize, Serialize};
use surrealdb::{Error, RecordId};

#[derive(Debug, Serialize, Deserialize)]
struct Person {
    name: String,
    id: RecordId,
    created_by: Option<RecordId>,
}

#[derive(Serialize, Deserialize)]
struct Params<'a> {
    name: &'a str,
    pass: &'a str,
}

#[derive(Serialize, Deserialize)]
struct RecordUser {
    name: String,
    pass: String,
}

async fn make_new_user(db: &Surreal<Client>) -> Result<RecordUser, Error> {
    let name = rand::random::<FirstName>().to_string();
    let pass = rand::random::<FirstName>().to_string();
    println!("Signing in as user {name} and password {pass}");
    let jwt = db
        .signup(Record {
            access: "account",
            namespace: "namespace",
            database: "database",
            params: Params {
                name: &name,
                pass: &pass,
            },
        })
        .await?
        .into_insecure_token();
    println!("New user created!\n\nName: {name}\nPassword: {pass}\nToken: {jwt}\n\nTo log in, use this command:\n\nsurreal sql --namespace namespace --database database --pretty --token \"{jwt}\"\n");
    Ok(RecordUser { name, pass })
}

async fn get_new_token(db: &Surreal<Client>, user: &RecordUser) -> Result<(), Error> {
    let jwt = db
        .signin(Record {
            access: "account",
            namespace: "namespace",
            database: "database",
            params: Params {
                name: &user.name,
                pass: &user.pass,
            },
        })
        .await?
        .into_insecure_token();
    println!("New token! Sign in with surreal sql --namespace namespace --database database --pretty --token \"{jwt}\"\n");
    Ok(())
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let db = Surreal::new::<Ws>("localhost:8000").await?;

    db.signin(Root {
        username: "root",
        password: "secret",
    })
    .await?;

    db.use_ns("namespace").use_db("database").await?;

    db.query(
        "DEFINE TABLE person SCHEMALESS
        PERMISSIONS FOR 
            CREATE, SELECT WHERE $auth,
            FOR UPDATE, DELETE WHERE created_by = $auth;
    DEFINE FIELD name ON TABLE person TYPE string;
    DEFINE FIELD created_by ON TABLE person VALUE $auth READONLY;

    DEFINE INDEX unique_name ON TABLE user FIELDS name UNIQUE;
    DEFINE ACCESS account ON DATABASE TYPE RECORD
	SIGNUP ( CREATE user SET name = $name, pass = crypto::argon2::generate($pass) )
	SIGNIN ( SELECT * FROM user WHERE name = $name AND crypto::argon2::compare(pass, $pass) )
	DURATION FOR TOKEN 15m, FOR SESSION 12h
;",
    )
    .await?;

    db.query("CREATE person SET name = 'Created by root'")
        .await?;

    let user = make_new_user(&db).await?;

    get_new_token(&db, &user).await?;

    db.query("CREATE person SET name = 'Created by record user'")
        .await?;

    println!(
        "Two `person` records: {:?}\n",
        db.select::<Vec<Person>>("person").await?
    );

    db.query("DELETE person").await?;

    println!(
        "`person` created by root is still there: {:?}\n",
        db.select::<Vec<Person>>("person").await?
    );

    Ok(())
}
```

Example output:

```text
Signing in as user Emmett and password Izaiah
New user created!

Name: Emmett
Password: Izaiah
Token: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJpYXQiOjE3MzA4NjQ2NDAsIm5iZiI6MTczMDg2NDY0MCwiZXhwIjoxNzMwODY1NTQwLCJpc3MiOiJTdXJyZWFsREIiLCJqdGkiOiIwNmYwOGFhZi0zYzIyLTQ5N2UtYWRmNC0zNDMxMzA5YWYxOGEiLCJOUyI6Im5hbWVzcGFjZSIsIkRCIjoiZGF0YWJhc2UiLCJBQyI6ImFjY291bnQiLCJJRCI6InVzZXI6YW92bHN0dzBvN2R1Y2J4ZWpqZWsifQ.tHCVlubg3G2j05-LsEaE6jRHMwrBtccJcR6uC9Z6Lo-egrYlBybEEfOZh020OxWxKvUt8eA92-6TjwBvSpN5KA

To log in, use this command:

surreal sql --namespace namespace --database database --pretty --token "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJpYXQiOjE3MzA4NjQ2NDAsIm5iZiI6MTczMDg2NDY0MCwiZXhwIjoxNzMwODY1NTQwLCJpc3MiOiJTdXJyZWFsREIiLCJqdGkiOiIwNmYwOGFhZi0zYzIyLTQ5N2UtYWRmNC0zNDMxMzA5YWYxOGEiLCJOUyI6Im5hbWVzcGFjZSIsIkRCIjoiZGF0YWJhc2UiLCJBQyI6ImFjY291bnQiLCJJRCI6InVzZXI6YW92bHN0dzBvN2R1Y2J4ZWpqZWsifQ.tHCVlubg3G2j05-LsEaE6jRHMwrBtccJcR6uC9Z6Lo-egrYlBybEEfOZh020OxWxKvUt8eA92-6TjwBvSpN5KA"

New token! Sign in with surreal sql --namespace namespace --database database --pretty --token "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJpYXQiOjE3MzA4NjQ2NDAsIm5iZiI6MTczMDg2NDY0MCwiZXhwIjoxNzMwODY1NTQwLCJpc3MiOiJTdXJyZWFsREIiLCJqdGkiOiIyZjExZTQzZi04ODg1LTRmNzAtOGI2Zi0zNGZmZGZlZWY4MDUiLCJOUyI6Im5hbWVzcGFjZSIsIkRCIjoiZGF0YWJhc2UiLCJBQyI6ImFjY291bnQiLCJJRCI6InVzZXI6YW92bHN0dzBvN2R1Y2J4ZWpqZWsifQ.0GWwMiAjn5kKUoNAw2TxAdVLhWIHeJsVWvlAzw1QZ91qdIhkazygdG5uFl5DHVmmoYC-cLo-ko27jiRCid5xDg"

Two `person` records: [Person { name: "Created by record user", id: RecordId { table: "person", key: String("i2sv6bqk0mso0udgzmdx") }, created_by: Some(RecordId { table: "user", key: String("aovlstw0o7ducbxejjek") }) }, Person { name: "Created by root", id: RecordId { table: "person", key: String("u6mry7agmsmtbwl94yui") }, created_by: None }]

`person` created by root is still there: [Person { name: "Created by root", id: RecordId { table: "person", key: String("u6mry7agmsmtbwl94yui") }, created_by: None }]
```

## See also

Each of the crates featured in the Rust SDK also use the schema above. Three of them (Actix, Axum, Rocket) are web servers, while Egui is a visual UI. See the mini tutorials for each of these crates here:

* [Actix](/docs/reference/rust/frameworks/actix.md)
* [Axum](/docs/reference/rust/frameworks/axum.md)
* [Rocket](/docs/reference/rust/frameworks/rocket.md)
* [Egui](/docs/reference/rust/frameworks/egui.md)

Learn more about authentication in SurrealDB in our [security best practices](/docs/learn/security/best-practices/security-best-practices.md#authentication) documentation and in the [security](/docs/learn/security/authentication/authentication.md#expiration) section of the SurrealDB documentation.
