creating an axum rest api app and integrating with authjs through adaptor
passwords? where we’re going, we dont need passwords.
toc
create axum rest api app with loco
creating pg-adaptor tables
create rest api axum app with loco:
cargo install sea-orm-cli
? ❯ What would you like to build ? ›
lightweight-service (minimal, only controllers and views )
❯ Rest API (with DB and user auth )
SaaS app (with DB and user auth )
creating pg-adaptor tables
https://authjs.dev/reference/pg-adapter
we need to following tables:
CREATE TABLE verification_token (
identifier TEXT NOT NULL ,
expires TIMESTAMPTZ NOT NULL ,
PRIMARY KEY (identifier, token)
"userId" INTEGER NOT NULL ,
type VARCHAR ( 255 ) NOT NULL ,
provider VARCHAR ( 255 ) NOT NULL ,
"providerAccountId" VARCHAR ( 255 ) NOT NULL ,
"userId" INTEGER NOT NULL ,
expires TIMESTAMPTZ NOT NULL ,
"sessionToken" VARCHAR ( 255 ) NOT NULL ,
"emailVerified" TIMESTAMPTZ ,
create migrations with loco:
the rest api template app from loco already created a users table. we need to update that, but first let’s create the verification_token, accounts and sessions tables. add the --migration-only
flag to not migrate the db and create the rust entity because we need to do some modifications before migrating:
cargo loco generate model verification_token identifier:string! token:string! expires:tstz! --migration-only
by default loco creates created_at
and updated_at
timestamps for models
use sea_orm_migration :: { prelude ::* , schema ::* };
#[derive( DeriveMigrationName )]
#[async_trait :: async_trait]
impl MigrationTrait for Migration {
async fn up ( & self , manager : & SchemaManager ) -> Result <(), DbErr > {
// 👇 the table_auto command creates timestamps fields
table_auto ( VerificationTokens :: Table )
. col ( pk_auto ( VerificationTokens :: Id ))
. col ( string ( VerificationTokens :: Identifier ))
. col ( string ( VerificationTokens :: Token ))
. col ( timestamp_with_time_zone ( VerificationTokens :: Expires ))
async fn down ( & self , manager : & SchemaManager ) -> Result <(), DbErr > {
. drop_table ( Table :: drop () . table ( VerificationTokens :: Table ) . to_owned ())
enum VerificationTokens {
lets update the default migration to remove the created_at
and updated_at
timestamps and create the composite primary key on primary_key and token:
diff --git a/backend/migration/src/m20240508_101645_verification_tokens.rs b/backend/migration/src/m20240508_101645_verification_tokens.rs
index ebaca79..850901e 100644
--- a/backend/migration/src/m20240508_101645_verification_tokens.rs
+++ b/backend/migration/src/m20240508_101645_verification_tokens.rs
@@ -8,8 +8,14 @@ impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
- table_auto(VerificationTokens::Table)
- .col(pk_auto(VerificationTokens::Id))
+ .table(VerificationTokens::Table)
+ .name("verification_tokens_pkey")
+ .col(VerificationTokens::Identifier)
+ .col(VerificationTokens::Token),
.col(string(VerificationTokens::Identifier))
.col(string(VerificationTokens::Token))
.col(timestamp_with_time_zone(VerificationTokens::Expires))
@@ -28,7 +34,6 @@ impl MigrationTrait for Migration {
enum VerificationTokens {
run migration
update our rust models based on the schema
or verification_token entity will now look like this:
//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.15
use sea_orm :: entity :: prelude ::* ;
use serde :: { Deserialize , Serialize };
#[derive( Clone , Debug , PartialEq , DeriveEntityModel , Eq , Serialize , Deserialize )]
#[sea_orm(table_name = "verification_tokens" )]
#[sea_orm(primary_key, auto_increment = false)]
#[sea_orm(primary_key, auto_increment = false)]
pub expires : DateTimeWithTimeZone ,
#[derive( Copy , Clone , Debug , EnumIter , DeriveRelation )]
create migration for accounts
cargo loco generate model accounts userId:int! type:string! provider:string! providerAccountId:string! refresh_token:text access_token:text expires_at:big_int id_token:text scope:text session_state:text token_type:text --migration-only
remove created_at
and updated_at
fields:
use sea_orm_migration :: { prelude ::* , schema ::* };
#[derive( DeriveMigrationName )]
#[async_trait :: async_trait]
impl MigrationTrait for Migration {
async fn up ( & self , manager : & SchemaManager ) -> Result <(), DbErr > {
// table_auto(Accounts::Table)
. col ( pk_auto ( Accounts :: Id ))
. col ( integer ( Accounts :: UserId ))
. col ( string ( Accounts :: Type ))
. col ( string ( Accounts :: Provider ))
. col ( string ( Accounts :: ProviderAccountId ))
. col ( text_null ( Accounts :: RefreshToken ))
. col ( text_null ( Accounts :: AccessToken ))
. col ( big_integer_null ( Accounts :: ExpiresAt ))
. col ( text_null ( Accounts :: IdToken ))
. col ( text_null ( Accounts :: Scope ))
. col ( text_null ( Accounts :: SessionState ))
. col ( text_null ( Accounts :: TokenType ))
async fn down ( & self , manager : & SchemaManager ) -> Result <(), DbErr > {
. drop_table ( Table :: drop () . table ( Accounts :: Table ) . to_owned ())
create migration for sessions
.
cargo loco generate model sessions userId:int! expires:tstz! sessionToken:string! --migration-only
same drill: migration only, remove table_auto statement from default migration.
use sea_orm_migration :: { prelude ::* , schema ::* };
#[derive( DeriveMigrationName )]
#[async_trait :: async_trait]
impl MigrationTrait for Migration {
async fn up ( & self , manager : & SchemaManager ) -> Result <(), DbErr > {
// table_auto(Sessions::Table)
. col ( pk_auto ( Sessions :: Id ))
. col ( integer ( Sessions :: UserId ))
. col ( timestamp_with_time_zone ( Sessions :: Expires ))
. col ( string ( Sessions :: SessionToken ))
async fn down ( & self , manager : & SchemaManager ) -> Result <(), DbErr > {
. drop_table ( Table :: drop () . table ( Sessions :: Table ) . to_owned ())
credits