Nuvaka › Developer docs › Sign in with Nuvaka
Sign in with Nuvaka
Your desktop program, website or command-line tool can recognise users by their Nuvaka account. If the user allows it, your app can send them notifications and read and write inside one My Files folder they choose. It is standard OAuth 2.1 and OpenID Connect, so existing libraries work.
How it works
- No password is ever typed. The user never enters their Nuvaka password in a browser or in your app. Approval happens in Nuvaka General App, where they are already signed in.
- The approval page in the browser shows a short approval code (
XXXX-XXXX) and an "Approve in General App" button (nuvaka://oauth?code=…). The app opens and shows your app's name, return address and requested permissions; the user approves or denies. The code can also be typed in Profile › Connected apps. - Users see their connected apps in the same place and can Remove access at any time; all tokens stop working immediately. Every sign-in sends the user an "X signed in with your account" notification.
Registering a client
For now the Nuvaka team registers clients: write to support with your app's name, logo, client type, redirect URIs and the scopes you need. You get a client_id (and, for server-side apps, a nvcs_… secret shown only once).
| Type | For | Authentication |
|---|---|---|
public | desktop, mobile, command line (can't keep a secret) | client_id + PKCE only |
confidential | server-side web app | client_secret_post or client_secret_basic |
The redirect_uri must match the registration exactly. Accepted forms: https://…; loopback http://127.0.0.1:port/… (the port is registered too); a reverse-domain custom scheme (com.example.app:/cb).
Scopes
| scope | What it gives |
|---|---|
openid | sign-in; sub is the user's stable id. The user can't turn it off |
profile | preferred_username |
email | email, email_verified. The user can turn it off during approval, so be ready to work without it |
notifications.send | notifications to the user (20 per hour per connection) |
storage.folder | the one My Files folder the user picks during approval, with its subfolders: list, download, upload, delete. Secure Space and system folders can't be chosen |
offline_access | refresh token |
You can only request scopes allowed for your client; unknown or disallowed scopes return invalid_scope. Users can switch off everything except openid; the scope field of the token response says what was actually granted.
Endpoints
Issuer: https://generalappapi.nuvaka.com. The discovery document lists every address; pointing your library at it is enough.
| Endpoint | Description |
|---|---|
GET /.well-known/openid-configuration | discovery |
GET /oauth/jwks | id_token signing key (RS256, kid) |
GET /oauth/authorize | approval page (opened in the browser) |
POST /oauth/device | start the device flow |
POST /oauth/token | authorization_code, refresh_token, urn:ietf:params:oauth:grant-type:device_code |
GET|POST /oauth/userinfo | Bearer; needs openid |
POST /oauth/revoke | token revocation (RFC 7009, always 200) |
Errors follow RFC 6749: { error, error_description }; a bad client gets 401 invalid_client. Endpoints are limited to 60 requests per minute per IP (429).
Authorization code + PKCE (desktop and web)
PKCE is required and only S256 is accepted. state (CSRF) and nonce are recommended.
- Create PKCE
A random
code_verifierof 43–128 characters;code_challenge = BASE64URL(SHA256(code_verifier)). - Open the browser
Send the user to the approval page. On desktop use a loopback listener (
http://127.0.0.1:PORT/cb) or a custom scheme. - The user approves in General App
The page polls every 2 seconds. On approval it returns to
redirect_uri?code=nvac_…&state=…&iss=…, on denial toredirect_uri?error=access_denied&state=…&iss=…. Checkstateandiss. - Exchange the code
The code is single-use and valid for 5 minutes; send the same
redirect_uri. The request (approval page) is valid for 10 minutes.
# 2) Address to open in the browser
https://generalappapi.nuvaka.com/oauth/authorize?response_type=code
&client_id=example-desktop
&redirect_uri=http%3A%2F%2F127.0.0.1%3A53682%2Fcb
&scope=openid%20profile%20storage.folder%20offline_access
&state=RANDOM&nonce=RANDOM
&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
&code_challenge_method=S256
# 4) Code exchange
curl -X POST https://generalappapi.nuvaka.com/oauth/token \
-d grant_type=authorization_code -d code=nvac_… \
-d redirect_uri=http://127.0.0.1:53682/cb \
-d code_verifier=… -d client_id=example-desktop
{ "access_token": "nvo_…", "token_type": "Bearer", "expires_in": 3600,
"scope": "openid profile storage.folder offline_access",
"refresh_token": "nvr_…", "id_token": "eyJ…" }
Redirected errors (after the redirect URI is verified): unsupported_response_type, invalid_request (no PKCE or not S256), invalid_scope. An unknown client or an unregistered redirect URI is never redirected to; an error page is shown instead.
Device flow (TV, console, command line)
For tools without a browser or a redirect address (RFC 8628).
curl -X POST https://generalappapi.nuvaka.com/oauth/device -d client_id=example-cli -d scope="openid profile"
# → { device_code, user_code: "WDJB-MJHT", verification_uri, verification_uri_complete, expires_in: 600, interval: 5 }
# Show the user the user_code and verification_uri (or a QR of verification_uri_complete).
# Then poll every interval seconds:
curl -X POST https://generalappapi.nuvaka.com/oauth/token \
-d grant_type=urn:ietf:params:oauth:grant-type:device_code -d device_code=… -d client_id=example-cli
Poll results: authorization_pending (wait), slow_down (increase the interval), access_denied, expired_token, or the tokens on success.
Tokens
| Token | Prefix | Lifetime |
|---|---|---|
| access | nvo_ | 1 hour |
| refresh | nvr_ | 30 days, only with offline_access |
| id_token | JWT (RS256) | 1 hour |
- Refresh tokens rotate:
grant_type=refresh_tokenreturns a new access token and a new refresh token every time; the old one is revoked immediately. If a revoked refresh token is used again (a sign of leakage), every token of the connection is revoked andinvalid_grantis returned. Store the new token right away. - id_token:
iss,aud(= client_id),sub,iat,exp,nonceif given;preferred_usernamewithprofile,emailandemail_verifiedwithemail. Verify the signature with/oauth/jwks. - Tokens are opaque; don't rely on their contents. If access is refused, refresh or ask the user to sign in again.
App API
Base address https://generalappapi.nuvaka.com/api/oauth-api/, header Authorization: Bearer nvo_….
| Endpoint | scope | Description |
|---|---|---|
GET me | — | { sub, username?, email?, language, scopes, folderId? } |
POST notifications | notifications.send | { title (1–100), message (≤ 500) }; shown to the user as "App name: title", and the user can mute it. 20 per hour; more returns 429 rate_limited |
GET storage/items?folderId= | storage.folder | folder contents (default: the chosen root) |
GET storage/files/{fileId} | storage.folder | download, supports Range |
POST storage/upload?folderId=&name= | storage.folder | raw body ≤ 100 MB; the user's quota applies |
DELETE storage/files/{fileId} | storage.folder | moves to the trash |
Errors: invalid or expired token 401 invalid_token; missing scope 403 insufficient_scope; outside the chosen folder 403 out_of_scope. If the account is deleted or blocked, the client is disabled or the user removes access, the token stops working immediately.
Security recommendations
- Generate a random
statefor every request and compare it on return; verify theissparameter (RFC 9207). - Request only the scopes you actually use;
emailmay be switched off. - Keep tokens in the operating system's key store; never log them.
- Show the approval code in your app too; the Nuvaka approval screen warns "Don't approve if you didn't start this request".
Nuvaka Apps API v1 · last updated 2026-09-28