Skip to content

Instantly share code, notes, and snippets.

@koakh
Last active April 6, 2024 02:04
Show Gist options
  • Save koakh/fbbc37cde630bedcf57acfd4d6a6956b to your computer and use it in GitHub Desktop.
Save koakh/fbbc37cde630bedcf57acfd4d6a6956b to your computer and use it in GitHub Desktop.
SurrealDB : How to use signin and signup (server + client nodesjs)
**As a developer you have complete control over the signup and signin functionality...**
```shell
$ surreal sql --conn http://localhost:8000 --user root --pass root --ns test --db test
```
```sql
-- optional : this is the default see --ns test --db test start server flags
-- USE NS test DB test;
-- define TABLE user SCHEMAFULL PERMISSIONS FOR select, update WHERE id = $auth.id FOR create, delete NONE; // miss ,
-- Tobie: However, make it schemaless, as you haven't defined fields.
-- SCHEMAFULL if we defined fields else use SCHEMALESS
---opt1:SCHEMALESS
-- DEFINE TABLE user SCHEMALESS
-- PERMISSIONS
-- FOR select, update WHERE id = $auth.id,
-- FOR create, delete NONE;
-- warn with opt1 if we re signup again it will create another user with same email, and after it all signin's will fail,
-- to fix this issue always use next opt2 that have a UNIQUE INDEX, and prevents create a user with same email, and this is the expected behavior
---opt2:SCHEMAFULL
DEFINE TABLE user SCHEMAFULL
PERMISSIONS
FOR select, update WHERE id = $auth.id,
FOR create, delete NONE;
DEFINE FIELD user ON user TYPE string;
DEFINE FIELD pass ON user TYPE string;
DEFINE FIELD settings.* ON user TYPE object;
DEFINE FIELD settings.marketing ON user TYPE string;
DEFINE FIELD tags ON user TYPE array;
DEFINE INDEX idx_user ON user COLUMNS user UNIQUE;
-- define scope
DEFINE SCOPE allusers
-- the JWT session will be valid for 14 days
SESSION 14d
-- The optional SIGNUP clause will be run when calling the signup method for this scope
-- It is designed to create or add a new record to the database.
-- If set, it needs to return a record or a record id
-- The variables can be passed in to the signin method
SIGNUP ( CREATE user SET settings.marketing = $marketing, user = $user, pass = crypto::argon2::generate($pass), tags = $tags )
-- The optional SIGNIN clause will be run when calling the signin method for this scope
-- It is designed to check if a record exists in the database.
-- If set, it needs to return a record or a record id
-- The variables can be passed in to the signin method
SIGNIN ( SELECT * FROM user WHERE user = $user AND crypto::argon2::compare(pass, $pass) )
-- this optional clause will be run when calling the signup method for this scope
```
ctrl+c
check info db in shell
```shell
$ echo "INFO FOR DB;" | surreal sql --conn http://localhost:8000 --user root --pass root --ns test --db test | jq
```
check info db in REPL
```shell
$ surreal sql --conn http://localhost:8000 --user root --pass root --ns test --db test --pretty
```
```sql
INFO FOR DB;
```
```json
[
{
"time": "249.753µs",
"status": "OK",
"result": {
"dl": {},
"dt": {},
"sc": {
"allusers": "DEFINE SCOPE allusers SESSION 2w SIGNUP (CREATE user SET settings.marketing = $marketing, email = $email, pass = crypto::argon2::generate($pass), tags = $tags) SIGNIN (SELECT * FROM user WHERE email = $email AND crypto::argon2::compare(pass, $pass))"
},
"tb": {
"user": "DEFINE TABLE user SCHEMALESS PERMISSIONS FOR select WHERE id = $auth.id, FOR create NONE, FOR update WHERE id = $auth.id, FOR delete NONE"
}
}
}
]
```
Then you could use the **following query from the client to signup (create) a new user**, or **signin (select) an existing user**...
```js
db.signup({
NS: 'my_ns',
DB: 'my_db',
SC: 'allusers', // We want to signup to the 'allusers' scope defined above
email: '[email protected]', // We can add any variable here to use in the SIGNUP clause
pass: 'some password', // We can add any variable here to use in the SIGNUP clause
marketing: true, // We can add any variable here to use in the SIGNUP clause
tags: ['rust', 'golang', 'javascript'], // We can add any variable here to use in the SIGNUP clause
});
// you should receive a jwt token
db.signin({
NS: 'my_ns',
DB: 'my_db',
SC: 'allusers', // We want to signup to the 'allusers' scope defined above
email: '[email protected]', // We can add any variable here to use in the SIGNUP clause
pass: 'some password', // We can add any variable here to use in the SIGNUP clause
});
// you should receive a jwt token
```
@sublayerio
Copy link

How do I get a user object from a jwt token?

@ralyodio it's a json web token, you can decode it here https://jwt.io/

or use a package https://www.npmjs.com/package/jsonwebtoken

@koakh
Copy link
Author

koakh commented Oct 15, 2022

@wpitallo
Copy link

wpitallo commented Nov 4, 2022

Any way to use a third party authentication provider like google or git hub or authO

@koakh
Copy link
Author

koakh commented Nov 5, 2022 via email

@mysticaltech
Copy link

@wpitallo Have a look at https://authorizer.dev/. they will soon be supporting SurrealDB, and any help they can get would be welcome!

@alt-jero
Copy link

alt-jero commented Jan 2, 2023

I have a couple of questions. I run the setup, the SQL Part seems to work fine, but with JS I get an error: “There was a problem with authentication”. First Question, do you have to be signed in as root for the signup to work? So:

db.signin({user:root,pass:root})
db.signup({
  NS: 'my_ns',
  DB: 'my_db',
  SC: 'allusers', // We want to signup to the 'allusers' scope defined above
  email: '[email protected]', // We can add any variable here to use in the SIGNUP clause
  pass: 'some password', // We can add any variable here to use in the SIGNUP clause
  marketing: true, // We can add any variable here to use in the SIGNUP clause
  tags: ['rust', 'golang', 'javascript'], // We can add any variable here to use in the SIGNUP clause
});

Because in my case this didn't work either And with the namespaces, do you just need to do the SQL setup one time for all namespaces and db's ? Or is the SQL setup scoped to namespace or DB? And is there some deeper Documentation available for SurrealDB on the Documentation Page I found nothing about the setup to get signup working.

I have encountered the same problem as you did. The solution for me, as they often are, was a facepalm moment.

Are you ready?

  • Solution 1: Turn off strict mode. (Do this by omitting the --strict flag when starting the server)
  • Solution 2: Manually (as root) define the namespace, the database, and the table you used in the scope definition for signup and signin.

🤦

Unfortunately I don't know how to get the database to emit errors like this... if I knew rust I would be adding some pull requests, but alas at this point my skill is mostly node-based, and my focus is on my project. Anyway, I hope it helps the next one who comes here looking for:

  • There was a problem with authentication
  • surrealdb signup not working
  • surreal signup error

and other such search terms 😸

@hgoona
Copy link

hgoona commented Jan 17, 2023

I'm getting my head around scopes still and how to use them. I can see SC: allusers written into the request for Signin and Signup which is using the Root user and password, but what happens if someone uses those priveledges of Root and changes the SC: to something like an admin scope?

How is that prevented on the front-end app?? I'm a bit confused what parts need to be exposed and what parts are safe..

@kubeworkz
Copy link

kubeworkz commented Apr 17, 2023

@dustsucker did you ever get dynamic namespace/database creation working? I also need to create a namespace/database for each new user logging into the system. It seems like a trivial exercise but I can't seem to find a clear solution to this. Basically, a login flow like Supabase. Login -> Create a Project (new namespace/db in our case) and you're in. Extra bonus points for building a connection string so people can access SDB from the net.

@bitdom8
Copy link

bitdom8 commented Jun 29, 2023

@koakh hi, can you help us with argon2 https://github.com/orgs/surrealdb/discussions/2196#discussioncomment-6314556

Thanks for the great guidance

@pkastoori
Copy link

pkastoori commented Jul 4, 2023

I am using the signup function and providing a username and password. After that I use the signin function with the same username but with the a different password, I was expecting an error but I still got a token also calling the authenticate function after that did not throw an error. How is this possible? What am I doing wrong?

await db.signup({
NS: "mydb",
DB: "mydb",
SC: "allusers",
user: "jane",
password: "jane",
email: "[email protected]",
});

const token = await db.signin({
NS: "mydb",
DB: "mydb",
SC: "allusers",
user: "jane",
password: "jane1",
});

await db.authenticate(token)

All of this still works even though I give an incorrect pass while signin

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment