casdoor-rust-sdk
Casdoor Rust SDK is the official Rust client library for Casdoor. It lets you sign users in with Casdoor and manage users, organizations, applications, roles, permissions and every other Casdoor object from your Rust application.
The API follows the Casdoor Go SDK: the same objects, the same actions, one Rust module per Go file, so the two SDKs stay easy to keep in sync.
📋 Table of Contents
- Features
- Installation
- Quick Start
- Configuration
- Authentication
- Resource Management
- API Reference
- Examples
- Migrating from 1.x
- Development
- Documentation
- License
✨ Features
- OAuth 2.0 Authentication: the authorization code flow, token refresh, the password grant, impersonation and single sign-out
- JWT Verification: verify the tokens issued by Casdoor with the application's x509 certificate
- User Management: create, read, update and delete users, set passwords, look users up by email, phone or user ID
- Organization Management: manage organizations, applications, groups and invitations
- Role-Based Access Control (RBAC): roles, permissions, models, adapters, enforcers, policies,
enforce()andbatch_enforce() - Resource Management: certificates, providers, tokens, sessions, syncers, LDAP servers, webhooks, records and uploaded files
- Multi-Factor Authentication (MFA): initiate, verify, enable, prefer and delete MFA methods
- Email, SMS & Notifications: send emails, SMS messages and notifications through the application's providers
- Payment & Subscriptions: products, orders, payments, transactions, plans, pricings and subscriptions
- Async and Typed: every API is
asyncand returnsResult<T, CasdoorError>, the objects are plainserdestructs
📦 Installation
Add the SDK to your Cargo.toml. The APIs are async, so you also need an async runtime such as Tokio:
[]
= "2"
= { = "1", = ["macros", "rt-multi-thread"] }
🚀 Quick Start
use Client;
async
⚙️ Configuration
Creating a Client
A Client holds the config of one Casdoor application. Create as many clients as you need, for example one per Casdoor application or organization:
use Client;
// From the 6 config values
let client = new;
// From a TOML file, the path should be an absolute path (recommended)
let client = from_toml?;
// A second client for another application
let client2 = new;
The TOML file looks like this, org_name and app_name are also accepted, so the config files of the 1.x versions keep working:
= "http://localhost:8000"
= "<client-id>"
= "<client-secret>"
= "built-in"
= "app-built-in"
= """
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
"""
Configuration Parameters
| Parameter | Required | Description |
|---|---|---|
| endpoint | Yes | Casdoor server URL (e.g., http://localhost:8000) |
| client_id | Yes | Client ID of the Casdoor application |
| client_secret | Yes | Client secret of the Casdoor application |
| certificate | Yes | x509 certificate content of the application's cert (PEM format) |
| organization_name | Yes | The name of the Casdoor organization |
| application_name | No | The name of the Casdoor application |
Getting Configuration Parameters from Casdoor
- endpoint: your Casdoor server URL
- client_id and client_secret: found on your application's edit page in the Casdoor admin panel
- certificate: the content of the cert used by your application, copied from the "Certs" page (x509 PEM format, a bare
PUBLIC KEYPEM is also accepted) - organization_name: the organization that owns your application
- application_name: your application's name in Casdoor
Customizing the HTTP Client
The SDK sends requests with reqwest. Use with_http_client() to provide your own reqwest::Client, for example to set a timeout, a proxy or custom TLS options:
use Duration;
let http = builder
.timeout
.pool_max_idle_per_host
// .proxy(reqwest::Proxy::all("http://proxy.example.com:8080")?)
.build?;
// Returns a copy of the client that uses the given HTTP client
let client = client.with_http_client;
Custom HTTP Headers
Every request sent by a client includes the headers in its public custom_headers field. This is useful for:
- Getting localized error messages with
Accept-Language - Adding custom tenant identifiers
- Including trace IDs for debugging
// Returns a copy of the client with the extra header
let client = client.with_custom_header;
// Or modify the field directly
let mut client = client;
client.custom_headers.insert;
// Now all API calls include these headers
let users = client.get_users.await?;
Note: the Content-Type and Authorization headers are managed by the SDK.
🔐 Authentication
OAuth 2.0 Flow
Step 1: Redirect the User to Casdoor
// Casdoor sends the user back to the redirect URI with a `code` query parameter
let signin_url = client.get_signin_url;
// The sign-up page, `true` for the password sign-up page of the application
let signup_url = client.get_signup_url;
Step 2: Handle the OAuth Callback
// Exchange the code for an access token
let token = client.get_oauth_token.await?;
// Verify the token with the application's certificate and read the user out of it
let claims = client.parse_jwt_token?;
println!;
Step 3: Store the User Session
The claims are a serde struct, so they can be stored in your session as JSON:
let data = to_string?;
// Store in the session (depends on your web framework)
session.insert?;
Sign Out
// Sign the user out of all their sessions (single sign-out)
client.logout.await?;
// Or only out of the current session
client.logout_current_session.await?;
Token Refresh
let new_token = client.refresh_oauth_token.await?;
The other ways to get a token are get_oauth_token_by_password() (the password grant type) and impersonate_user() (an admin acting as a user). introspect_token() checks whether a token is still active.
Calling APIs With the User's Access Token
By default, the client calls the Casdoor APIs as the application itself, i.e., it authenticates with the client ID and client secret, so the calls have the application's (admin) permissions.
If you want to call the APIs on behalf of the signed-in user instead, use with_access_token() with the access token returned by get_oauth_token(). It returns a copy of the client that sends the Authorization: Bearer <access_token> header, so Casdoor treats the request as being made by that user, and the user's own permissions apply:
let token = client.get_oauth_token.await?;
// A client that acts as the user who owns the access token
let user_client = client.with_access_token;
// Get the user of the access token, i.e., "who am I"
let user = user_client.get_account.await?;
// Any other API can be called in the same way
let users = user_client.get_users.await?;
The original client is not affected, so it's safe to create one such client per incoming HTTP request.
Note: a non-admin user can only access their own data. If an API returns a permission error, the user simply isn't allowed to call it — use the application's client (without with_access_token()) for admin operations.
JWT Token Parsing
let claims = client.parse_jwt_token?;
// Access the user information
println!;
println!;
println!;
Profile Pages
// The profile page of a user, and of the signed-in user
let url = client.get_user_profile_url;
let url = client.get_my_profile_url;
📦 Resource Management
All the API methods are async and return Result<T, CasdoorError>. The getters of a single object return Option<T>, which is None when the object doesn't exist, and add_xxx() / update_xxx() / delete_xxx() return whether the object was affected.
Object Owner
Every object in Casdoor is identified by an ID of the form owner/name, where the owner is an organization (role, group, user, product, ldap, ...) or the built-in admin owner (organization, application, token).
By default the SDK fills in the owner for you: the organization_name of the client, or admin for the object types listed above. You can address an object in another organization by passing a qualified owner/name ID instead of a plain name, and by setting the owner field explicitly when creating or updating an object:
use Role;
// Uses the client's own organization: "my-org/my-role"
let role = client.get_role.await?;
// Uses the owner given in the name: "other-org/my-role"
let role = client.get_role.await?;
// Created in "other-org" instead of the client's organization
client
.add_role
.await?;
User Management
use User;
// Get all users of the organization
let users = client.get_users.await?;
// Get a user by name, email, phone or user ID
let user = client.get_user.await?;
let user = client.get_user_by_email.await?;
let user = client.get_user_by_phone.await?;
let user = client.get_user_by_user_id.await?;
// Get the users page by page, with optional query filters
let = client.get_pagination_users.await?;
// Get the number of users, "1" for the online users and "" for all users
let count = client.get_user_count.await?;
// Create a new user
let user = User ;
let affected = client.add_user.await?;
// Update a user, or only some of its fields
let affected = client.update_user.await?;
let affected = client.update_user_for_columns.await?;
// Delete a user
let affected = client.delete_user.await?;
// Set or change the password of a user
let affected = client.set_password.await?;
// Check the password of a user
let ok = client.check_user_password.await?;
Organization Management
use Organization;
let organizations = client.get_organizations.await?;
let organization = client.get_organization.await?;
let names = client.get_organization_names.await?;
let organization = Organization ;
client.add_organization.await?;
client.update_organization.await?;
client.delete_organization.await?;
Application Management
let applications = client.get_applications.await?;
let applications = client.get_organization_applications.await?;
let application = client.get_application.await?;
client.add_application.await?;
client.update_application.await?;
client.delete_application.await?;
Role and Permission Management
use ;
let roles = client.get_roles.await?;
let role = client.get_role.await?;
client
.add_role
.await?;
let permissions = client.get_permissions.await?;
let permissions = client.get_permissions_by_role.await?;
client
.add_permission
.await?;
Permission Enforcement
enforce() checks a request against a permission, model, resource or enforcer, given by its owner/name ID. batch_enforce() checks several requests at once:
use json;
let request = vec!;
// Check against a permission
let allowed = client.enforce.await?;
// Check against an enforcer
let allowed = client.enforce.await?;
// Check several requests at once
let results = client.batch_enforce.await?;
Models, Adapters, Enforcers and Policies
use ;
let models = client.get_models.await?;
let adapters = client.get_adapters.await?;
let enforcers = client.get_enforcers.await?;
let enforcer = client.get_enforcer.await?.unwrap;
// Get, add, update and remove the policies of an enforcer
let policies = client.get_policies.await?;
let policy = CasbinRule ;
client.add_policy.await?;
client.update_policy.await?;
client.remove_policy.await?;
// Get the policies that match some filters
let filter = PolicyFilter ;
let policies = client.get_filtered_policies.await?;
Session Management
let sessions = client.get_sessions.await?;
let session = client.get_session.await?;
client.delete_session.await?;
Provider, Certificate, Token and Webhook Management
let providers = client.get_providers.await?;
let provider = client.get_provider.await?;
let certs = client.get_certs.await?;
let global_certs = client.get_global_certs.await?;
let cert = client.get_cert.await?;
let tokens = client.get_tokens.await?;
let token = client.get_token.await?;
let webhooks = client.get_webhooks.await?;
let webhook = client.get_webhook.await?;
Each of them also has the add_xxx(), update_xxx() and delete_xxx() methods.
Email, SMS and Notifications
// Send an email through the email provider of the application
client.send_email.await?;
// Send an SMS message through the SMS provider of the application
client.send_sms.await?;
// Send a notification through the notification provider of the application
client.send_notification.await?;
send_email_by_provider() and send_sms_by_provider() send the message through a given provider instead.
Resource (File) Management
// Upload a file, returns its URL and the resource name
let = client.upload_resource.await?;
// Get the resources of a user
let resources = client.get_resources.await?;
// Delete a resource
client.delete_resource.await?;
Invitations
let invitations = client.get_invitations.await?;
let invitation = client.get_invitation.await?;
// Find an invitation by its code
let invitation = client.get_invitation_info.await?;
LDAP Servers
let ldaps = client.get_ldaps.await?;
let ldap = client.get_ldap.await?;
// Get the users of an LDAP server, and sync them to Casdoor
if let Some = client.get_ldap_users.await?
Products, Orders and Payments
use ProductInfo;
let products = client.get_products.await?;
// Place an order of some products for a user, then pay for it with a payment provider
let product_info = ProductInfo ;
let order = client.place_order.await?;
let payment = client.pay_order.await?;
// Get the orders, payments and transactions of a user
let orders = client.get_user_orders.await?;
let payments = client.get_user_payments.await?;
let transactions = client.get_user_transactions.await?;
// Cancel an order
client.cancel_order.await?;
Multi-Factor Authentication
// The arguments are the owner, the MFA type ("app", "sms" or "email") and the user name
let mfa = client.initiate_mfa.await?;
client.verify_mfa.await?;
client.enable_mfa.await?;
client.set_preferred_mfa.await?;
client.delete_mfa.await?;
📚 API Reference
Available Resources
| Resource | Description | Key Operations |
|---|---|---|
| User | User accounts and profiles | CRUD, password, lookup, pagination |
| Organization | Organization entities | CRUD, names |
| Application | Application configurations | CRUD |
| Group | User groups | CRUD |
| Role | User roles | CRUD |
| Permission | Access permissions | CRUD, enforcement, by role |
| Model | Casbin models | CRUD |
| Adapter | Casbin policy adapters | CRUD |
| Enforcer | Casbin enforcers | CRUD, enforcement |
| Policy | Casbin policies of an enforcer | Get, filter, add, update, remove |
| Provider | Third-party providers (OAuth, email, SMS, ...) | CRUD |
| Cert | Certificates | CRUD, global certs |
| Token | Access and refresh tokens | CRUD, introspection |
| Session | User sessions | CRUD |
| Syncer | User synchronization from external databases | CRUD |
| LDAP | LDAP servers | CRUD, get and sync users |
| Webhook | Event webhooks | CRUD |
| Invitation | User invitations | CRUD, lookup by code |
| Resource | Uploaded files | Upload, CRUD |
| Record | Audit records | Get, add |
| Product | Products/services | CRUD, buy |
| Order | Product orders | CRUD, place, pay, cancel |
| Payment | Payment records | CRUD, notify, invoice |
| Transaction | Payment transactions | CRUD |
| Plan | Subscription plans | CRUD |
| Pricing | Pricing configurations | CRUD |
| Subscription | User subscriptions | CRUD |
| MFA | Multi-factor authentication of a user | Initiate, verify, enable, delete |
Method Patterns
Most resources follow the same method patterns:
get_xxxs()- get all the objects of the organizationget_pagination_xxxs(page, page_size, query)- get the objects page by page, with the total countget_xxx(name)- get one object by its name orowner/nameID,Noneif it doesn't existadd_xxx(&object)- create an objectupdate_xxx(&object)- update an objectupdate_xxx_for_columns(&object, &columns)- update only some fields of an objectdelete_xxx(&object)- delete an object
The full API documentation is on docs.rs.
💡 Examples
Complete Authentication Example
With axum:
use HashMap;
use ;
use ;
async
async
async
User Management Example
use ;
async
Permission Enforcement Example
use Client;
use json;
async
🔄 Migrating from 1.x
The 2.0 version replaces AuthService and UserService with a single Client, which covers all the Casdoor objects instead of only the users, and makes every API return a typed CasdoorError instead of a Box<dyn Error>.
| 1.x | 2.0 |
|---|---|
CasdoorConfig::new(...) |
Client::new(...) |
CasdoorConfig::from_toml(path) |
Client::from_toml(path) |
CasdoorUser |
User |
AuthService::new(&conf) |
the Client itself |
auth.get_auth_token(code) |
client.get_oauth_token(&code).await? |
auth.parse_jwt_token(token) |
client.parse_jwt_token(&token)? |
auth.get_signin_url(uri) |
client.get_signin_url(&uri) |
auth.get_signup_url_enable_password() |
client.get_signup_url(true, "") |
auth.get_user_profile_url(name, tok) |
client.get_user_profile_url(&name, tok) |
UserService::new(&conf) |
the Client itself |
user_service.get_user(name) |
client.get_user(&name).await? (an Option) |
user_service.get_user_with_email(...) |
client.get_user_by_email(&email).await? |
user_service.add_user(user) |
client.add_user(&user).await? (a bool) |
The certificate is now parsed as a real x509 certificate, so the certificate copied from Casdoor's "Certs" page works as-is, and a bare PUBLIC KEY PEM is still accepted.
🛠️ Development
cargo test
The tests that need a running Casdoor server are marked as ignored, they mirror the tests of the Casdoor Go SDK. Run them with:
cargo test -- --ignored
They read the server config from the CASDOOR_TEST_ENDPOINT, CASDOOR_TEST_CLIENT_ID, CASDOOR_TEST_CLIENT_SECRET, CASDOOR_TEST_ORGANIZATION and CASDOOR_TEST_APPLICATION environment variables. By default they connect to http://localhost:8000, which CI starts from the casbin/casdoor-all-in-one Docker image with the data in .ci/casdoor/init_data.json:
docker run -d --name casdoor -p 8000:8000 \
-e driverName=sqlite \
-e dataSourceName='file:casdoor.db?cache=shared' \
-e initDataFile=/init_data.json \
-v "$PWD/.ci/casdoor/init_data.json:/init_data.json:ro" \
casbin/casdoor-all-in-one
📖 Documentation
📄 License
This project is licensed under the Apache License 2.0 - see the LICENSE file for details.
🌟 Star History
If you find this project useful, please consider giving it a star! ⭐