Standalone login
The login capability gives the app its own session. When a DSM id cookie is available for the same host name, the app exchanges it for an app session. Otherwise it shows a sign-in page that checks the account, password and OTP code against DSM. The app stores no password or OTP code. It needs no administrator setup and no Node.js on the NAS.
It identifies the user. It does not give the app a File Station session: see Files.
Add it
Section titled “Add it”New project (the Vue UI is the default):
synopkgland init -t native-go --with login my-loginExisting project:
synopkgland add loginBoth set this in dsm-package.yaml:
capabilities: identity: standalonestandalone is the only value.
| Combination | Result |
|---|---|
Plain UI (--ui plain, no ui.build) | Not supported. check reports CAPABILITY_COMBINATION_INVALID and init refuses it |
| Binary backend | CAPABILITY_UNSUPPORTED |
armv7 | Allowed |
The generated Vue app shows its sign-in page whenever login is on and there is no session. The page needs HTTPS in the browser.
Use it
Section titled “Use it”How a user gets in
Section titled “How a user gets in”- DSM cookie. If the browser sends a valid DSM
idcookie, the backend validates it with DSM’s nativeauthenticate.cgi, preserving the browser’s client address, and issues an app session. This needs HTTPS. Cookies belong to a host name, not a port, so an app on another port of the same host name receives the cookie. An IP address and a DNS name are different host names. A cross-site frame cannot be assumed to receive DSM cookies. - Sign-in page. Without a usable DSM cookie, the user enters the DSM account and password. If DSM asks for a second factor, the page asks for the OTP code and sends the request again. The backend signs in to DSM once to prove the identity and then ends that DSM session right away. It never keeps it.
A disabled account, a wrong password and an account that may not sign in are refused with different codes, see Troubleshooting.
What an app session allows
Section titled “What an app session allows”The app session identifies the user. For every method except app.status and greeting.get, the backend checks again that a live DSM id cookie of the same user is present. A request without it fails with session_revalidation_required, or dsm_session_required for file and job-import methods. A cookie for another user ends the session. So a password sign-in alone opens only those two methods. For anything else, the user must also be signed in to DSM on the same host name.
Each successful check extends the session by the full lifetime.
All are public routes and need a same-origin JSON POST.
| Method | Params | Result |
|---|---|---|
identity.status | {} | { enabled: true } |
identity.session | { bootstrap?: boolean } | { user, uid, expiresAt }. With bootstrap and no app cookie, exchanges the DSM cookie (HTTPS only). The native session check also forwards the request’s X-SYNO-TOKEN when supplied by the DSM window |
identity.login | { account, password, otp? } | { user, uid, expiresAt } (HTTPS only) |
identity.logout | {} | { loggedOut: true } and clears the cookie |
createSession(ctx) from @synopackageland/sdk/vue wraps them. It returns enabled, ready, subject, notice, start, call, login, bootstrap, logout and dispose. Use session.call(method, params) instead of ctx.call for your own methods, as the generated App.vue does.
Limits
Section titled “Limits”| Item | Value |
|---|---|
| Transport | HTTPS for identity.login and for the DSM-cookie exchange |
| Session lifetime | 15 minutes, extended by each successful DSM-cookie check |
| Session cookie | spl_session_<16 hex digits>, HttpOnly, Secure, SameSite=Lax, limited to the app’s path |
| Sign-in attempts | 5 per account and 20 per client address in one minute. Every attempt counts |
| Sessions | At most 4096 |
| Time DSM has to answer | 10 seconds |
| Credentials accepted | Account up to 1024 characters, password 4096, OTP 128 |
| Requests | Same origin only. Origin scheme, host and port must match |
If the account or its DSM data changes so that the user name stops resolving to the same UID, the session ends.
Troubleshooting
Section titled “Troubleshooting”| Code | Cause | Fix |
|---|---|---|
https_required | Sign-in or the DSM-cookie exchange over plain HTTP | Open the app over HTTPS |
invalid_credentials | Wrong account or password | Try again |
account_disabled | The DSM account is disabled | Use another account |
otp_required | DSM wants a second factor | Send the OTP code in otp |
login_not_permitted | DSM refused the sign-in for any other reason | Check the account and its sign-in settings in DSM |
rate_limited | 5 attempts for the account or 20 for the address in a minute | Wait a minute |
cross_origin | The request came from another origin | Call from the app page, not another site |
origin_required | A POST carried neither Origin nor Referer | Open the app again in a current browser |
session_required | No app session, an expired one, or the DSM cookie did not match | Sign in again |
session_revalidation_required | The method needs the DSM id cookie and the browser did not send it | Sign in to DSM on the same host name, then retry |
dsm_session_required | Same, for nas.*, bg.browse and bg.jobs.submit | Sign in to DSM on the same host name |
auth_unavailable | DSM could not be asked, or 4096 sessions exist | Retry later |
Codes are described in Errors. To keep the app out of reach of some users, use entry as described in Native apps.