---
title: Users and authentication
nav: Users and login
group: Build your app
updated: 2026-11-13
description: Sign up and log in users in your SashiDo app. Email verification and password reset, sessions, password policy, account lockout, multi-factor authentication, anonymous users, and social login with Apple, Google, Facebook, GitHub, LinkedIn, Microsoft and Twitter.
keywords: parse server authentication, parse user login, parse email verification, parse password reset, parse social login, sign in with apple parse, google login parse server, sashido users
---

Users live in the `_User` class. Parse handles passwords (hashed, never returned), sessions and permissions; you choose in the dashboard how users may log in and what the rules are. Everything below is in **App Settings › Users** and **App Settings › Emails & Hosting**.

## Sign up and log in

```javascript
const user = new Parse.User();
user.set('username', 'ada@example.com');
user.set('email', 'ada@example.com');
user.set('password', 'a-long-password');
await user.signUp();

await Parse.User.logIn('ada@example.com', 'a-long-password');
const current = Parse.User.current();   // the logged-in user, kept between visits
await Parse.User.logOut();
```

After login, every request carries the user's session, so class-level permissions and ACLs apply to them. Username and password login is on by default (**User Authentication › Allow username and password-based authentication**).

## Email verification

Turn on **Emails & Hosting › Verify user emails**: a verification email goes out on sign-up, and the user's `emailVerified` field shows whether they clicked it. In the same section set the sender address, display name and reply-to address, and edit the email templates. The sender address must be on a domain you own.

## Password reset

```javascript
await Parse.User.requestPasswordReset('ada@example.com');
```

The user gets an email with a link to a page where they choose a new password. **Password Policy › Reset link validity (hours)** sets how long the link works. You can replace the hosted pages with your own (**Emails & Hosting**: custom "choose a new password", "password changed", "email verified" and invalid-link pages).

## Sessions

| Setting (User Sessions) | |
|---|---|
| Session length (days) | How long a login lasts |
| Expire inactive sessions | End sessions that aren't used |
| Revoke session on password change | Log out other devices when the password changes |

## Password policy and lockout

| Setting | |
|---|---|
| Password pattern | A regular expression new passwords must match |
| Password expires after (days) | Force a change after this many days |
| Password history | Refuse the last N passwords |
| Lock accounts after failed logins | With **Failed attempts** and **Lock for (minutes)**: slows down password guessing |

## Anonymous users

**User Authentication › Allow anonymous users** lets an app create a user without credentials (`Parse.AnonymousUtils.logIn()`), e.g. to save a cart before sign-up, and link a real login to it later. Leave it off if your app doesn't use it.

## Multi-factor authentication

Users can protect their account with an authenticator app (Google Authenticator, 1Password, Authy...): after their password, they enter the app's 6-digit code. Turn it on in **App Settings › Users › Allow multi-factor authentication**. It's available on Parse Server **8.6.104 and newer**; earlier versions have flaws in it, so the option isn't offered there.

Your app adds two things: a screen to set it up, and the code field at login. With the JS SDK and the [otpauth](https://www.npmjs.com/package/otpauth) library:

```javascript
import * as OTPAuth from 'otpauth';

// set up, while the user is logged in
const secret = new OTPAuth.Secret({ size: 20 });
const totp = new OTPAuth.TOTP({ issuer: 'My App', label: user.get('username'), secret });
showQrCode(totp.toString());                 // otpauth://totp/... for the authenticator app

const code = await askForCode();             // the code the app now shows
await user.linkWith('mfa', { authData: { secret: secret.base32, token: code } });
const recovery = user.get('authDataResponse').mfa.recovery;  // 2 one-time recovery codes
showRecoveryCodes(recovery);
```

```javascript
// log in: the password alone is refused once MFA is on
await Parse.User.logInWithAdditionalAuth(username, password, { mfa: { token: code } });
```

- A wrong code is refused with `Invalid MFA token`, a login without one with `Missing additional authData mfa`. Ask for the code when you get the latter.
- Each recovery code works once, in place of the app's code, e.g. after losing the phone. Ask users to keep them somewhere safe.
- The user's `authData.mfa` shows only `{ "status": "enabled" }`: the secret never leaves the server.
- Over REST, send the same `authData` with `PUT /users/<id>` (to set it up) and `POST /login` (to log in).

## Social login

Turn each provider on in **App Settings › Users › Social Login** and enter its credentials:

| Provider | What SashiDo needs |
|---|---|
| Apple | Bundle ID |
| Google | Your apps' OAuth client IDs (iOS, Android, web) |
| Facebook | App ID and App Secret |
| GitHub, LinkedIn | Client ID and secret of your OAuth app |
| Microsoft | Client ID and secret (Parse Server 4.1 and newer) |
| Twitter | Consumer Key and Consumer Secret |

Your app gets the provider's token with the provider's SDK, then logs in to Parse with it, which creates the user on the first login:

```javascript
// e.g. after Sign in with Apple returned an identity token
await Parse.User.logInWith('apple', {
  authData: { id: appleUserId, token: identityToken },
});
```

Each provider's `authData` fields are in Parse's [third-party authentication guide](https://docs.parseplatform.org/parse-server/guide/#oauth-and-3rd-party-authentication).

From Parse Server 8, Google requires your client IDs, and GitHub, LinkedIn and Microsoft verify an authorization code with your client secret instead of trusting a token from the app. Fill these in before you upgrade: the [version change](/en/docs/developers/api#put-appsappobjectidversion) is refused while they're missing.

## Protect the users

- `_User` is readable by everyone by default: anyone with your client keys can list your users. In **Core › Browser › _User › Security**, allow **Find** only to roles or the master key; sign-up, login and fetching the current user keep working.
- Never store secrets in public `_User` fields; use a class only the user's ACL can read.
- [Secure your app](/en/docs/developers/security) covers permissions in depth, and `get_app_advice` through [MCP](/en/docs/developers/mcp) checks them for you.
