Sign-in for app developers
This page is for developers building an Arcel Konnect client (web, iOS, Android) against the Daily Dose API. It covers Google sign-in and email and password sign-in: what to call, in what order, what comes back, and which errors to handle. Every operation named here is in the API reference with its request, reply and examples; you can try them from the reference.
Base URL. Staging: https://staging.arcelintelligence.com (all paths below start with /v1). Send Content-Type: application/json on every request with a body.
The common parts
Ask which methods to show
Call listSignInProviders (GET /v1/auth/providers?platform=web|ios|android) when the sign-in screen opens and show the methods in the order it returns. Show only what it lists:
| Value | Show |
|---|---|
email | Email address with a one-time code (works for verified test addresses only until email delivery is enabled) |
password | Continue with email and password |
google | Google's sign-in button |
apple, linkedin, phone | Their buttons (Apple on iOS) |
guest | Continue without an account |
Identify the installation
Every sign-in request carries the same three device fields:
| Field | Value |
|---|---|
installationId | A random ID you create once per installation and keep (16 to 64 letters, digits or hyphens; a UUID works) |
platform | web, ios or android |
appVersion | Your app's version, for example 2.0.0 |
Guests
To let people browse first, call startGuestSession (POST /v1/auth/guest) with the device fields and keep the returned token. When the guest later signs in by any method, send the guest token as Authorization: Bearer <guest token> on the sign-in request: the guest's saves and preferences move into the account, and the guest token stops working.
The session you get back
Every successful sign-in answers 200 with:
{
"token": "…",
"expiresAt": "2027-10-11T08:12:40Z",
"account": { "id": 5311, "kind": "reader", "providers": ["password"], "email": null, "…": "…" }
}
- Store
tokenin secure storage (Keychain on iOS, EncryptedSharedPreferences or the Keystore on Android; on the web the app keeps it in local storage) and send it on every call asAuthorization: Bearer <token>. - The session lasts up to a year and ends after 90 days without use. A
401on any call means the session ended: sign in again. - Then call
getProfile(GET /v1/dailydose/profile).onboarded: falsemeans the reader still has to finish onboarding.displayNameis already filled with the name Google gave, so prefill your "What should we call you?" step with it. signOut(POST /v1/auth/logout) ends the session.
Google sign-in
Google sign-in uses Google's own SDK on the device to get an ID token, which you send to the API. There is no redirect URI and no client secret in the app.
Client IDs (public values, from the Google Cloud project arcel-daily-dose):
| Platform | Client ID |
|---|---|
| Web (staging) | 610493135736-i2bmqqic4qpvfvleioflugplv0o4dkmh.apps.googleusercontent.com |
| iOS, Android | Created per app when the mobile apps register their bundle ID or package name; ask the ARCEL team. The API accepts only tokens issued for the IDs it lists. |
The web origins Google accepts for this client are https://staging.arcelintelligence.com, https://d1cnuvka5u241f.cloudfront.net and http://localhost:5174. Until the Google project is published, only accounts listed as test users can sign in.
Steps
-
Create a random nonce (at least 16 characters) for this sign-in attempt.
-
Start Google sign-in with the client ID and that nonce:
- Web: Google Identity Services (
https://accounts.google.com/gsi/client),google.accounts.id.initialize({ client_id, nonce, callback }), then render Google's button. The callback'scredentialis the ID token. - Android: Credential Manager with
GetGoogleIdOption,setServerClientId(<web client ID>)andsetNonce(nonce); the result'sidToken. - iOS: Google Sign-In for iOS with the iOS client ID and the nonce;
user.idToken.tokenString.
- Web: Google Identity Services (
-
Call
signInWithGoogle(POST /v1/auth/google):{"idToken": "<the ID token>","nonce": "<the same nonce>","installationId": "8a1c4e7b-2d5f-4a9c-b3e6-0f7d9c2a5b18","platform": "android","appVersion": "1.4.0"} -
Store the session as described above.
Errors
| Reply | Meaning | What to show |
|---|---|---|
401 UNAUTHENTICATED | The token is not for our client ID, expired, or the nonce differs | "Google sign-in failed. Try again." Start again with a new nonce |
400 VALIDATION_ERROR | A missing or malformed field | A generic error; fix the request |
429 RATE_LIMITED | Too many attempts from this network | Wait for Retry-After seconds |
Each ID token works once; never reuse one.
Email and password
Readers can create an account with an email address and a password and sign in with them. Use this as the email option while email codes cannot reach every reader.
Password rules (checked by the API; check the length on the device too):
- 12 to 128 characters, any characters. No rules about symbols or digits: suggest a few unrelated words.
- A password that appears in known data breaches is refused.
- Turn on the platform's password managers:
autocomplete="email"andautocomplete="new-password"or"current-password"on the web, thetextContentTypeorautofillHintsequivalents on iOS and Android.
The email address is not verified yet. It identifies this sign-in method only: another method with the same address (a Google account, an email code) is a different account. When email delivery is enabled, readers will confirm their address with a code.
Create an account
registerWithPassword (POST /v1/auth/password/register), with the guest token if there is one:
{
"email": "layla.haddad@example.com",
"password": "three distant harbour lights",
"installationId": "3f2b8c1e-7a4d-4e9b-b6c2-1d5f8a9e0c47",
"platform": "web",
"appVersion": "2.0.0"
}
200 returns the session with passwordChangeRequired: false.
| Reply | Meaning | What to show |
|---|---|---|
400 VALIDATION_ERROR with fieldErrors.password | Too short, too long, or found in a data breach | The message from fieldErrors.password under the password field |
400 VALIDATION_ERROR with fieldErrors.email | Not an email address | The message under the email field |
409 EMAIL_TAKEN | This address already has a password | "An account with this email already exists." and a button to switch to sign-in |
429 RATE_LIMITED | Too many sign-ups from this network | Wait for Retry-After seconds |
Sign in
signInWithPassword (POST /v1/auth/password/sign-in) with email, password and the device fields (and the guest token if there is one). 200 returns the session and passwordChangeRequired.
| Reply | Meaning | What to show |
|---|---|---|
401 INVALID_CREDENTIALS | The email or the password is wrong (the API never says which) | "Email or password is incorrect" |
429 RATE_LIMITED | 10 wrong passwords in a row locked the address for 15 minutes, or too many attempts from this network | "Too many attempts. Try again in 15 minutes." |
403 FORBIDDEN | The account cannot sign in (suspended) | "You can't sign in with this account. Contact support." |
After a reset: passwordChangeRequired
A reader who forgot the password contacts ARCEL support. After checking who they are, support gives them a temporary password (there is no email reset yet). Signing in with it answers passwordChangeRequired: true. Keep the session, but show only a "Choose a new password" screen until they change it:
changePassword (POST /v1/auth/password/change, with the session token):
{ "currentPassword": "<the temporary password>", "newPassword": "a phrase they will keep" }
200 answers { "changed": true, "otherSessionsEnded": 0 }. Then continue as after any sign-in (getProfile).
Change the password
Offer Change password in the account settings when getAccount (GET /v1/auth/account) lists password in providers. Use the same changePassword call with the current password. The reader's other devices are signed out; this one stays signed in.
| Reply | Meaning | What to show |
|---|---|---|
400 with fieldErrors.currentPassword | The current password is wrong | Its message under the current-password field |
400 with fieldErrors.newPassword | Too short, the same as the current one, or found in a data breach | Its message under the new-password field |
404 NOT_FOUND | This account has no password (it signs in another way) | Hide the option |
429 RATE_LIMITED | Too many wrong current passwords | "Too many attempts. Try again in 15 minutes." |
Checklist
- The sign-in screen shows the methods
listSignInProvidersreturns, in that order. - One
installationIdper installation, sent on every sign-in. - A guest's token is sent on the sign-in request, then replaced by the new token.
- Tokens are kept in secure storage and sent as
Authorization: Bearer. - Google: a new nonce per attempt, the same nonce sent to the API, the ID token used once.
- Passwords: 12+ characters checked on the device, password-manager autofill on,
fieldErrorsshown under their fields, one message for any wrong email or password. -
passwordChangeRequired: trueleads straight to "Choose a new password". - Change password is offered only when
providerscontainspassword. - After
getProfile,onboarded: falsestarts onboarding withdisplayNameprefilled.