Authentication
Stashly uses a centralized authentication service. There are two authentication methods: JWT tokens for interactive user sessions and API keys for programmatic access.
No passwords
Stashly uses OTP-based authentication. There are no passwords — users sign in via a one-time code sent to their email.
JWT Authentication#
Login Flow (OTP)
Request an OTP
curl -X POST https://auth.stashly.io/auth/send-otp \
-H "Content-Type: application/json" \
-d '{"email": "you@example.com"}'
Verify the OTP
curl -X POST https://auth.stashly.io/auth/verify-otp \
-H "Content-Type: application/json" \
-d '{"email": "you@example.com", "otp": "123456"}'
Response:
{
"success": true,
"data": {
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user": { "id": "usr_01j9", "email": "you@example.com", "role": "admin" }
}
}
A refreshToken is also set as an HTTP-only cookie on .stashly.io.
Use the access token
Include it in the Authorization header:
curl -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
Token Lifetimes
| Token | Lifetime | Storage |
|---|---|---|
| Access token | 15 minutes | In-memory / localStorage |
| Refresh token | 7–30 days | HTTP-only cookie on .stashly.io |
Refreshing Tokens
When the access token expires, use the refresh endpoint:
curl -X POST https://auth.stashly.io/auth/refresh \
--cookie "refreshToken=<value>"
Response returns a new accessToken.
Get Current User
curl -X GET https://auth.stashly.io/auth/me \
-H "Authorization: Bearer <token>"
{
"success": true,
"data": {
"id": "usr_01j9",
"email": "you@example.com",
"role": "admin",
"tenantId": "ten_abc123"
}
}
Logout
curl -X POST https://auth.stashly.io/auth/logout \
-H "Authorization: Bearer <token>"
Clears the refresh token cookie.
API Key Authentication#
API keys are ideal for server-to-server calls where interactive login is not appropriate.
Creating an API Key
Log into your dashboard → Settings → API Keys → Create Key.
Select the permission scopes you need:
Permission Scopes
| Name | Type | Description |
|---|---|---|
view | boolean | List buckets, objects, and download files |
add | boolean | Upload files, create buckets and directories |
edit | boolean | Rename, move, and copy files and buckets |
delete | boolean | Delete files, directories, and buckets |
Using an API Key
Pass the key in the X-API-Key header:
curl -X GET https://api.stashly.io/api/buckets \
-H "X-API-Key: sk_live_01j9xk2m..."
API keys cannot manage other API keys
For security, API keys cannot be used to create, list, or revoke other API keys. Use a JWT for those operations.
Rate Limits#
Rate Limits
| Name | Type | Description |
|---|---|---|
send-otp | endpoint | 5 requests per 15 minutes per IP |
verify-otp | endpoint | 10 attempts per OTP before lockout |
API (general) | global | 1,000 requests per minute per tenant |
Upload session | endpoint | 60 file uploads per session per hour |
When rate-limited, you receive a 429 Too Many Requests response.