Mobile Control - Custom Frappe Application
You can install this app using the bench CLI:
cd $PATH_TO_YOUR_BENCH
bench get-app $URL_OF_THIS_REPO --branch develop
bench install-app mobile_controlThese endpoints are exposed as whitelisted methods and are intended for a mobile
client. All endpoints expect POST requests and use the api/v2/method/ route.
Endpoints:
mobile_auth.login- Login with username/password.mobile_auth.logout- Logout and revoke refresh tokens.mobile_auth.send_login_otp- Send OTP to mobile number for login.mobile_auth.verify_login_otp- Verify OTP and complete login.mobile_auth.refresh_token- Refresh access token using refresh token.mobile_auth.permissions- Get current user permissions (requires authentication).mobile_auth.get_translations- Get translation dictionary for one or more languages (requires authentication). By default returns DB translations only; useall=1for full (apps + DB). Uselang=hi,enfor multiple languages.mobile_auth.get_social_login_providers- Discover enabled social providers fromSocial Login Key(guest).mobile_auth.get_social_authorize_url- Build provider-direct OAuth authorize URL for one-tap social login (guest).
Response tokens:
access_tokenexpires in 24 hours.refresh_tokenexpires in 30 days and is rotated on every refresh.
These APIs are designed for mobile SDK OAuth (PKCE) login and avoid the extra provider selection click on Frappe login page.
- Providers are auto-discovered from Frappe
Social Login Key. - No extra provider config is required in
mobile_control. - Sensitive data such as
client_secretis never returned.
Required mobile callback URI:
frappemobilesdk://oauth/callback
Provider discovery:
GET /api/method/mobile_auth.get_social_login_providers
Example response:
{
"providers": [
{ "id": "google", "label": "Google", "icon_url": "https://..." },
{ "id": "microsoft", "label": "Microsoft", "icon_url": null }
]
}Provider-direct authorize URL:
POST /api/v2/method/mobile_auth.get_social_authorize_url
Body:
{
"provider": "google",
"client_id": "mobile-client-id",
"redirect_uri": "frappemobilesdk://oauth/callback",
"scope": "openid all",
"state": "random-state",
"code_challenge": "pkce-code-challenge",
"code_challenge_method": "S256"
}Example response:
{
"authorize_url": "https://accounts.google.com/o/oauth2/v2/auth?...state=<encoded-with-redirect_to>"
}Notes:
- Returned URL is generated by Frappe Social Login flow for the selected provider.
client_idin request body is your Frappe OAuth Client ID (not Google client id).- After social login succeeds, Frappe redirects to its OAuth authorize endpoint, which then redirects to
redirect_uri(frappemobilesdk://oauth/callback) with authorization code.
Troubleshooting:
- Provider not showing: verify
Social Login Keyexists and social login is enabled for that key. - Invalid provider error: ensure
providermatches discovered providerid(google,microsoft, etc). - Redirect URI mismatch: ensure app sends
frappemobilesdk://oauth/callback(or add allowlisted URIs in site config). - Social opens wrong provider or fails immediately: verify
Social Login Keyfor that provider is enabled and configured with valid client credentials.
Login, mobile_auth.verify_login_otp, and mobile_auth.refresh_token return a response like:
{
"message": "Logged In",
"user": "user@example.com",
"full_name": "User Name",
"language": "en",
"access_token": "...",
"refresh_token": "...",
"offline_enabled": false,
"mobile_form_names": [
{
"mobile_workspace_item": "Mobile Refresh Token",
"group_name": "",
"doctype_meta_modifed_at": "2026-02-14 14:40:49.962439",
"doctype_icon": ""
}
],
"roles": ["Mobile User", "All", "Desk User"],
"permissions": [
{
"doctype": "Mobile Refresh Token",
"read": true,
"write": false,
"create": true,
"delete": false,
"submit": false,
"cancel": false,
"amend": false
}
]
}languageis the user's language (default"en"if blank).offline_enabledis the value of theMobile Configuration.offline_enabledCheck field. The mobile SDK uses this to decide whether to run as an offline-first client or a thin online client. Defaultfalse. Only emitted when the parentenabledflag is on. See the SDK'sdoc/OFFLINE_MODE_TOGGLE.mdfor the full client-side contract.rolesis an array of role names.permissionsis an array of objects; each hasdoctypeand the flagsread,write,create,delete,submit,cancel,amend.
Client flow:
- Login or OTP verify to receive
access_token+refresh_token. - Use
access_tokenasAuthorization: Bearer <access_token>for API calls. - When access token expires, call
mobile_auth.refresh_tokenwith therefresh_tokento get a new pair.
User permissions:
- Permissions are automatically included in login, OTP verify, and refresh token responses.
- Permissions include user roles and doctype-level permissions (read, write, create, delete, submit, cancel, amend) for mobile-configured doctypes.
- To refresh permissions without re-authenticating, call
mobile_auth.permissionsendpoint.
Translations:
- Call
GET /api/method/mobile_auth.get_translations?lang=hi(Bearer token required). Omitlangfor English (en). By default only DB translations (Translation doctype) are returned. Add&all=1or&all=trueto get full translations (apps CSV/MO + DB). For multiple languages, use comma-separated codes:?lang=hi,en. Response is always the same shape:{ "langs": ["hi"], "translations_by_lang": { "hi": { "source text": "translated text", ... } } }(or multiple keys inlangsandtranslations_by_lang). Usetranslations_by_lang[lang][source] ?? sourcefor lookup.
All requests use:
POST {{base_url}}/api/v2/method/<endpoint>
Login:
{
"username": "your.username",
"password": "your.password"
}Send OTP:
{
"mobile_no": "+15551234567"
}Verify OTP:
{
"tmp_id": "TMP_ID_FROM_SEND_OTP",
"otp": "123456"
}Refresh token:
{
"refresh_token": "REFRESH_TOKEN"
}Logout:
Authorization: Bearer <access_token>
Get permissions:
GET {{base_url}}/api/method/mobile_auth.permissions
Authorization: Bearer <access_token>
Response:
{
"roles": ["Mobile User", "System Manager"],
"permissions": [
{
"doctype": "Customer",
"read": true,
"write": true,
"create": true,
"delete": false,
"submit": true,
"cancel": false,
"amend": false
}
]
}The API/ directory contains a Bruno collection to try the mobile auth endpoints locally.
Collection: API/bruno.json
Requests:
| File | Description |
|---|---|
Login with username and password.bru |
POST login with username/password; returns access_token, refresh_token, roles, permissions, language. |
Login with mobile.bru |
POST send OTP to mobile number (mobile_auth.send_login_otp). |
Login with mobile verify.bru |
POST verify OTP and login (mobile_auth.verify_login_otp). |
Get Access Token.bru |
POST refresh token to get new access_token and refresh_token. |
Logout.bru |
POST logout (Bearer token required); revokes refresh tokens. |
permissions.bru |
GET current user roles and permissions (Bearer token required). |
get_translations.bru |
GET translation dictionary; optional ?lang=hi (Bearer token required). |
App Status.bru |
GET app status (enabled, package_name, app_title, version). Guest. |
App Configuration.bru |
GET mobile configuration list. Guest. |
Setup: Set base_url in collection/environment variables. For auth requests, set username, password, and after login use the returned access_token as Bearer token in subsequent requests (or use Bruno’s response scripts to save the token).
This app uses pre-commit for code formatting and linting. Please install pre-commit and enable it for this repository:
cd apps/mobile_control
pre-commit installPre-commit is configured to use the following tools for checking and formatting your code:
- ruff
- eslint
- prettier
- pyupgrade
