Expand description
Stackure is the Rust SDK for the Stackure authentication API.
Stackure provides passwordless B2B authentication. This SDK wraps the public API behind 10 free functions and a tower middleware.
§Quickstart
Protect an axum app:
let app = app.layer(stackure::auth());The layer works in any tower stack: axum, tonic or hyper.
Access the authenticated user inside a handler:
let user = stackure::user_from_request(parts);Manual verification without middleware:
let result = stackure::verify(parts).await;
if result.authenticated {
// use result.user
}Send a magic-link email:
let response = stackure::send_magic_link("user@example.com").await;Sign the user out, ending their access everywhere. Mount it for every method on the sign-out path. Trigger it with a form or button that POSTs from the app’s own page; a link or any other request is sent to Stackure’s sign-out page, where the user confirms. Awaiting it yields the redirect response, never an error:
async fn logout(parts: http::request::Parts) -> axum::response::Response {
stackure::logout(&parts).await
}
let app: Router = Router::new().route("/logout", any(logout));§Sign-in handoff
Stackure’s session cookie is scoped to the Stackure host and is never
visible to your app. After a successful magic-link sign-in, Stackure hands
the browser back to the app’s registered URL with a session_token POST
form field: an app-scoped session token valid only for this app, accepted
by the validate endpoint for your app ID and never by Stackure itself.
The auth layer consumes it automatically: it validates the token, stores
it in a cookie on your own domain and redirects to the same URL as a GET.
Invalid tokens are ignored, and handoff bodies over 4 KB are ignored (treated
as no token).
§Session binding
Sessions are not bound to the browser’s user agent or IP address. The SDK
still forwards the original User-Agent and X-Forwarded-For on every
validation call, but they are informational only; validation does not
depend on them.
Every request with a session token is validated against Stackure, so revoking
a session takes effect immediately. Requests without a well-formed token get
the sign-in URL without a Stackure call, except under auth() on localhost,
where the sign-in URL comes from Stackure.
§Content negotiation
The auth layer inspects the Accept header. Browser requests (Accept: text/html) redirect to the sign-in URL on 401. API requests (Accept: application/json) receive a JSON error body.
§MCP
Protect an MCP route:
let app = app.layer(stackure::mcp());AI clients such as Claude, Claude Code, VS Code and Cursor sign users in through Stackure. This one line checks every MCP request in real time with the same app secret; there is no extra setup. The MCP endpoint must be served from the same site as the app’s registered URL unless an MCP URL is set for the app in Stackure.
The mcp layer reads only Authorization: Bearer and ignores cookies.
It attaches the user exactly as auth does, and otherwise answers in
JSON, never with a redirect or a cookie: 401 with a WWW-Authenticate
header when not signed in, 503 when the check itself fails.
§Identity facts
Every authenticated User, from auth or mcp, also carries 2
facts from the user’s Stackure organization: user_is_app_admin is true
when the user is an app admin or owner there, in charge of its apps, and
user_teams lists the Stackure teams they belong to (empty when none).
Stackure defines no in-app permissions; the app decides what these mean.
List the users in the caller’s organization who can open the app, and the teams that have it, for pickers and sharing. Each call returns one page, sorted by name:
let opts = stackure::DirectoryOptions {
query: Some("ada".into()),
..Default::default()
};
let page = stackure::directory_users(parts, &opts).await?;
// page.items, page.next_cursor, page.total
let teams = stackure::directory_teams(parts, &Default::default()).await?;query matches a user’s name, email and job title, or a team’s name.
limit is the page size: 100 by default, 200 at most. Pass next_cursor
as cursor to get the next page; it’s None on the last one. total is
set on the first page when there are 10,000 matches or fewer. ids returns
only those IDs that can open the app, up to 200, to check or name people
and teams you already store.
directory_users and directory_teams are authenticated by the
request’s session cookie, so call them from a route behind auth; MCP
bearer tokens are not accepted. A request without a valid session gets
StackureError::Auth.
§Configuration
STACKURE_APP_ID must be set to the app’s UUID, shown on the app page in
Stackure, and STACKURE_APP_SECRET to the app secret shown when the app
was registered (or last rotated) in Stackure. The secret is sent as the
X-App-Secret header on every call except the sign-out made by
logout, which carries the user’s session token instead. The first call
that needs either fails with StackureError::Validation when it is
unset, or when STACKURE_APP_ID is not a UUID.
STACKURE_BASE_URL must be set to your region’s address,
https://eu.stackure.com or https://us.stackure.com. Every call goes
there, and the first call fails with StackureError::Validation when it
is unset.
People can open a newly registered app once an app admin gives it to everyone in the organization or to one of their teams in Stackure. App admins and the owner can always open it, so they can test sign-in first.
Every SDK call has one 2-second wall-clock deadline covering connect,
headers, body and the single retry. The SDK retries once, after 500 ms, on
a 5xx response or a connection failure, and only if more than 500 ms of the
deadline remain. A timeout, including while reading the body, surfaces as
StackureError::Timeout and is never retried. The localhost sign-in code
swap is never retried, because each code works only once.
§Errors
Every function except verify and logout returns StackureError.
logout never returns an error: a failed sign-out call still ends in a
redirect. Match on the variant, or call StackureError::code for the same
lowercase category string the other Stackure SDKs expose as .code.
Re-exports§
pub use errors::StackureError;pub use middleware::Auth;pub use middleware::AuthLayer;pub use middleware::auth;pub use middleware::logout;pub use middleware::mcp;pub use middleware::user_from_request;pub use middleware::verify;pub use types::DirectoryOptions;pub use types::DirectoryPage;pub use types::DirectoryUser;pub use types::MagicLinkResponse;pub use types::Session;pub use types::Team;pub use types::User;pub use types::VerifyError;pub use types::VerifyResult;
Modules§
- errors
- Stackure SDK error type.
- middleware
- Session verification and the tower authentication middleware.
- types
- Types returned by the Stackure SDK.
- validation
- Input validation for the Stackure SDK.
Constants§
- SESSION_
COOKIE - Name of the session cookie the SDK reads and writes.
- TOKEN_
PARAM - Name of the sign-in handoff parameter Stackure sends back.
Functions§
- base_
url - Resolve
STACKURE_BASE_URLfrom the environment. Empty when unset. - directory_
teams - List the teams in the caller’s Stackure organization that have the app, one page at a time: every team when the app is available to everyone, otherwise the teams it’s shared with.
- directory_
users - List the users in the caller’s Stackure organization who can open the app, one page at a time, for pickers and sharing.
- send_
magic_ link - Send a passwordless sign-in email for the app in
STACKURE_APP_ID. - validate_
session - Validate the request’s session against Stackure.