> ## Documentation Index
> Fetch the complete documentation index at: https://docs.prelude.so/llms.txt
> Use this file to discover all available pages before exploring further.

# Password

> Implement password-based authentication with the Prelude JavaScript SDK.

## Log in a user

```javascript theme={null}
import { PrldErrors } from "@prelude.so/js-sdk";

try {
  await client.loginWithPassword({
    identifier: "user@example.com",
    password: "SecureP@ssw0rd!",
  });
  // User is now authenticated
} catch (error) {
  if (error instanceof PrldErrors.Unauthorized) {
    // Invalid credentials
  } else if (error instanceof PrldErrors.BadRequest) {
    // Invalid email format
  } else if (error instanceof PrldErrors.RateLimited) {
    // Too many login attempts
  }
}
```

<Accordion title="Try it" icon="flask">
  Replace `src/App.jsx` with:

  ```jsx src/App.jsx theme={null}
  import "@picocss/pico";
  import { useState } from "react";
  import { PrldSessionClient, PrldErrors, decode } from "@prelude.so/js-sdk";

  const client = new PrldSessionClient({ domain: `${import.meta.env.VITE_APP_ID}.session.prelude.dev` });

  export default function App() {
    const [email, setEmail] = useState("");
    const [password, setPassword] = useState("");
    const [user, setUser] = useState(null);
    const [error, setError] = useState(null);

    const handleLogin = async (e) => {
      e.preventDefault();
      setError(null);
      try {
        await client.loginWithPassword({ identifier: email, password });
        const { user } = await client.refresh();
        setUser(user);
      } catch (err) {
        if (err instanceof PrldErrors.Unauthorized) {
          setError("Invalid email or password.");
        } else if (err instanceof PrldErrors.InvalidPassword) {
          setError("Password does not meet the compliancy rules.");
        } else if (err instanceof PrldErrors.BadRequest) {
          setError("Invalid email format.");
        } else if (err instanceof PrldErrors.RateLimited) {
          setError("Too many attempts. Please try again later.");
        } else {
          setError("Something went wrong. Please try again.");
        }
      }
    };

    return (
      <>
        <style>{`body, #root { display: flex; justify-content: center; align-items: center; min-height: 100vh; margin: 0; padding: 0; }`}</style>
        <main style={{ textAlign: "center", maxWidth: "600px", width: "100%" }}>
          <h1>Log In</h1>
          {user ? (
            <article>
              <p>Logged in</p>
              <pre style={{ textAlign: "left", whiteSpace: "pre-wrap", wordBreak: "break-all" }}>
                {JSON.stringify(decode(user.accessToken).claims, null, 2)}
              </pre>
            </article>
          ) : (
            <form onSubmit={handleLogin}>
              <input type="email" placeholder="Email" value={email} onChange={(e) => setEmail(e.target.value)} required />
              <input type="password" placeholder="Password" value={password} onChange={(e) => setPassword(e.target.value)} required />
              {error && <p role="alert" style={{ color: "var(--pico-color-red-500)" }}>{error}</p>}
              <button type="submit">Log In</button>
            </form>
          )}
        </main>
      </>
    );
  }
  ```
</Accordion>

## Validate password compliancy (optional)

Password compliancy rules define the requirements a password must meet, such as minimum length, and required uppercase, lowercase, number, or symbol characters. These rules are configured on your application and enforced both client-side and server-side.

Before submitting a sign-up form, validate the password against your compliancy rules. The SDK fetches the rules from the server and checks the password locally:

```javascript theme={null}
const { valid, results } = await client.validatePassword("SecureP@ssw0rd!");

if (!valid) {
  // Show which criteria are not met
  for (const result of results) {
    if (!result.valid) {
      console.log(`${result.criteria}: expected ${result.expected}, got ${result.actual}`);
    }
  }
}
```

You can also retrieve the raw compliancy configuration to build your own validation UI:

```javascript theme={null}
const compliancy = await client.getPasswordCompliancy();
// { min_length: 12, max_length: 128, uppercase: 1, lowercase: 1, numbers: 1, symbols: 1 }
```

<Accordion title="Try it" icon="flask">
  Replace `src/App.jsx` with:

  ```jsx src/App.jsx theme={null}
  import "@picocss/pico";
  import { useState, useEffect } from "react";
  import { PrldSessionClient } from "@prelude.so/js-sdk";

  const client = new PrldSessionClient({ domain: `${import.meta.env.VITE_APP_ID}.session.prelude.dev` });

  export default function App() {
  const [password, setPassword] = useState("");
  const [results, setResults] = useState([]);
  const [valid, setValid] = useState(null);

  useEffect(() => {
  if (!password) return setResults([]);
  client.validatePassword(password).then((r) => {
  setResults(r.results);
  setValid(r.valid);
  });
  }, [password]);

  return (
  <>
  <style>{`body, #root { display: flex; justify-content: center; align-items: center; min-height: 100vh; margin: 0; padding: 0; }`}</style>
  <main style={{ textAlign: "center", maxWidth: "600px", width: "100%" }}>
  <h1>Password Validator</h1>
  <input
      type="password"
      placeholder="Type a password..."
      value={password}
      onChange={(e) => setPassword(e.target.value)}
  />
  {results.length > 0 && (
      <table>
          <thead>
          <tr><th>Criteria</th><th>Status</th><th>Expected</th><th>Actual</th></tr>
          </thead>
          <tbody>
          {results.map((r) => (
              <tr key={r.criteria}>
                  <td>{r.criteria}</td>
                  <td>{r.valid ? "\u2713" : "\u2717"}</td>
                  <td>{r.expected}</td>
                  <td>{r.actual}</td>
              </tr>
          ))}
          </tbody>
      </table>
  )}
  {valid !== null && <p>{valid ? "\u2713 Password is valid" : "\u2717 Password does not meet requirements"}</p>}
  </main>
  </>
  );
  }
  ```
</Accordion>
