WIP: feat: adding supabase db #1540

Draft
asmogo wants to merge 34 commits from asmogo/feat/wallet-supabase into main
asmogo commented 2026-01-19 09:50:09 +00:00 (Migrated from github.com)

Description

Introducing supabase db to the cdk wallet.

  • added supabase crate
  • moved oicd client to common crate
  • auto refresh jwt token in the supabase crate
  • exported constructor, wrapper and helper functions (set_jwt_token, set_refresh_token and set_token_expiration)

Todo:

  • move migrations to common package + auto migrate
  • add call_rpc function to invoke custom db rpc
  • cleanup
  • remove SetTokenExpiration (set exp internally based on access token)
  • replace extra fields from other applications (dead_code) using serde(flatten) ?.
  • test with supabase provided authentication
  • make use of the ffi database macro crate::impl_ffi_wallet_database!

This example reuses the keycloak token for auth wallet and supabase.

My supabase is configured to use the jwt token from keycloak for user authentication and RBAC (golang):

// ProvideWallet creates the CDK FFI wallet instance with CAT token authentication
func ProvideWallet(params WalletParams) (WalletResult, error) {
	cfg := params.Config
	log := logger.WithComponent("wallet_provider")
	cdk_ffi.InitLogging("debug")

	ctx := context.Background()

	catToken, err := params.KeycloakClient.Login(ctx, cfg.Wallet.Username, cfg.Wallet.Password)
	if err != nil {
		return WalletResult{}, fmt.Errorf("failed to login to keycloak for wallet: %w", err)
	}
	log.Info("Obtained CAT token for wallet authentication")
	apiKey := "<my-supabase-public-anon-key>"

	wdb, err := cdk_ffi.WalletSupabaseDatabaseWithOidc("https://supabase.domain.com",
		apiKey,
		"https://auth.domain.com/realms/my-application-realm/.well-known/openid-configuration",
		&cfg.Keycloak.Verification.ClientID)

	if err != nil {
		return WalletResult{}, fmt.Errorf("failed to create supabase db concetion: %w", err)
	}
	wdb.SetJwtToken(&catToken.AccessToken)
	wdb.SetRefreshToken(&catToken.RefreshToken)
	
	exp := uint64(time.Now().Add(time.Duration(catToken.ExpiresIn)).Unix())
	wdb.SetTokenExpiration(&exp)

	wallet, err := cdk_ffi.NewWallet(
		cfg.Wallet.Mint,
		cdk_ffi.CurrencyUnitUsd{},
		cfg.Wallet.Mnemonic,
		wdb,
		cdk_ffi.WalletConfig{
			TargetProofCount: nil,
		},
	)

	if err != nil {
		return WalletResult{}, fmt.Errorf("failed to create wallet: %w", err)
	}
    // Set CAT token for wallet authentication (NUT-21 and NUT-22 auth wallet)
	if err := wallet.SetCat(catToken.AccessToken); err != nil {
		return WalletResult{}, fmt.Errorf("failed to set CAT token: %w", err)
	}

	// Set refresh token
	if err := wallet.SetRefreshToken(catToken.RefreshToken); err != nil {
		return WalletResult{}, fmt.Errorf("failed to set refresh token: %w", err)
	}

	return WalletResult{
		Wallet:          wallet,
	}, nil
}

Notes to the reviewers


Suggested CHANGELOG Updates

CHANGED

ADDED

REMOVED

FIXED


Checklist

### Description Introducing supabase db to the cdk wallet. * added supabase crate * moved oicd client to common crate * auto refresh jwt token in the supabase crate * exported constructor, wrapper and helper functions (set_jwt_token, set_refresh_token and set_token_expiration) Todo: - [x] move migrations to common package + auto migrate - [x] add `call_rpc` function to invoke custom db rpc - [x] cleanup - [x] remove `SetTokenExpiration` (set exp internally based on access token) - [x] replace extra fields from other applications (dead_code) using `serde(flatten)` ?. - [x] test with supabase provided authentication - [x] make use of the ffi database macro `crate::impl_ffi_wallet_database!` This example reuses the keycloak token for auth wallet and supabase. My supabase is configured to use the jwt token from keycloak for user authentication and RBAC (golang): ```go // ProvideWallet creates the CDK FFI wallet instance with CAT token authentication func ProvideWallet(params WalletParams) (WalletResult, error) { cfg := params.Config log := logger.WithComponent("wallet_provider") cdk_ffi.InitLogging("debug") ctx := context.Background() catToken, err := params.KeycloakClient.Login(ctx, cfg.Wallet.Username, cfg.Wallet.Password) if err != nil { return WalletResult{}, fmt.Errorf("failed to login to keycloak for wallet: %w", err) } log.Info("Obtained CAT token for wallet authentication") apiKey := "<my-supabase-public-anon-key>" wdb, err := cdk_ffi.WalletSupabaseDatabaseWithOidc("https://supabase.domain.com", apiKey, "https://auth.domain.com/realms/my-application-realm/.well-known/openid-configuration", &cfg.Keycloak.Verification.ClientID) if err != nil { return WalletResult{}, fmt.Errorf("failed to create supabase db concetion: %w", err) } wdb.SetJwtToken(&catToken.AccessToken) wdb.SetRefreshToken(&catToken.RefreshToken) exp := uint64(time.Now().Add(time.Duration(catToken.ExpiresIn)).Unix()) wdb.SetTokenExpiration(&exp) wallet, err := cdk_ffi.NewWallet( cfg.Wallet.Mint, cdk_ffi.CurrencyUnitUsd{}, cfg.Wallet.Mnemonic, wdb, cdk_ffi.WalletConfig{ TargetProofCount: nil, }, ) if err != nil { return WalletResult{}, fmt.Errorf("failed to create wallet: %w", err) } // Set CAT token for wallet authentication (NUT-21 and NUT-22 auth wallet) if err := wallet.SetCat(catToken.AccessToken); err != nil { return WalletResult{}, fmt.Errorf("failed to set CAT token: %w", err) } // Set refresh token if err := wallet.SetRefreshToken(catToken.RefreshToken); err != nil { return WalletResult{}, fmt.Errorf("failed to set refresh token: %w", err) } return WalletResult{ Wallet: wallet, }, nil } ``` <!-- Describe the purpose of this PR, what's being adding and/or fixed --> ----- ### Notes to the reviewers <!-- In this section you can include notes directed to the reviewers, like explaining why some parts of the PR were done in a specific way --> ----- ### Suggested [CHANGELOG](https://github.com/cashubtc/cdk/blob/main/CHANGELOG.md) Updates <!-- Please do not edit the actual changelog but note what you changed here. --> #### CHANGED #### ADDED #### REMOVED #### FIXED ---- ### Checklist * [x] I followed the [code style guidelines](https://github.com/cashubtc/cdk/blob/main/CODE_STYLE.md) * [ ] I ran `just final-check` before committing
asmogo commented 2026-01-24 19:15:36 +00:00 (Migrated from github.com)

Here’s another example for using this with supabase native authentication and e2e encryption.


	apiKey := "sb_publishable_key"
	supabaseURL := "https://myrandomstring.supabase.co"
	username := "user@domain.com"
	password := "mypassword"
	response, err := cdk_ffi.SupabaseSignin(supabaseURL, apiKey, username, password)
	if err != nil {
		return WalletResult{}, err
	}
	wdb, err := cdk_ffi.WalletSupabaseDatabaseWithSupabaseAuth(supabaseURL,
		apiKey)
	if err != nil {
		return WalletResult{}, fmt.Errorf("failed to create supabase db concetion: %w", err)
	}
	wdb.SetEncryptionPassword(password, "salt")
	wdb.SetJwtToken(&response.AccessToken)
	wdb.SetRefreshToken(response.RefreshToken)
        
    err = wdb.KvWrite("test", "namespace", "key", []byte("value"))
	if err != nil {
		return WalletResult{}, fmt.Errorf("failed to get mint info: %w", err)
	}
	value, err := wdb.KvRead("test", "namespace", "value")
	if err != nil {
		return WalletResult{}, fmt.Errorf("failed to get mint info: %w", err)
	}
Here’s another example for using this with supabase native authentication and e2e encryption. ```go apiKey := "sb_publishable_key" supabaseURL := "https://myrandomstring.supabase.co" username := "user@domain.com" password := "mypassword" response, err := cdk_ffi.SupabaseSignin(supabaseURL, apiKey, username, password) if err != nil { return WalletResult{}, err } wdb, err := cdk_ffi.WalletSupabaseDatabaseWithSupabaseAuth(supabaseURL, apiKey) if err != nil { return WalletResult{}, fmt.Errorf("failed to create supabase db concetion: %w", err) } wdb.SetEncryptionPassword(password, "salt") wdb.SetJwtToken(&response.AccessToken) wdb.SetRefreshToken(response.RefreshToken) err = wdb.KvWrite("test", "namespace", "key", []byte("value")) if err != nil { return WalletResult{}, fmt.Errorf("failed to get mint info: %w", err) } value, err := wdb.KvRead("test", "namespace", "value") if err != nil { return WalletResult{}, fmt.Errorf("failed to get mint info: %w", err) } ```
This pull request has changes conflicting with the target branch.
  • .gitignore
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin asmogo/feat/wallet-supabase:asmogo/feat/wallet-supabase
git switch asmogo/feat/wallet-supabase

Merge

Merge the changes and update on Forgejo.

Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.

git switch main
git merge --no-ff asmogo/feat/wallet-supabase
git switch asmogo/feat/wallet-supabase
git rebase main
git switch main
git merge --ff-only asmogo/feat/wallet-supabase
git switch asmogo/feat/wallet-supabase
git rebase main
git switch main
git merge --no-ff asmogo/feat/wallet-supabase
git switch main
git merge --squash asmogo/feat/wallet-supabase
git switch main
git merge --ff-only asmogo/feat/wallet-supabase
git switch main
git merge asmogo/feat/wallet-supabase
git push origin main
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
cashubtc/cdk!1540
No description provided.