Log in a user
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
}
}
Try it
Try it
Replace
src/App.jsx with:src/App.jsx
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>
</>
);
}
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: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}`);
}
}
}
const compliancy = await client.getPasswordCompliancy();
// { min_length: 12, max_length: 128, uppercase: 1, lowercase: 1, numbers: 1, symbols: 1 }
Try it
Try it
Replace
src/App.jsx with:src/App.jsx
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>
</>
);
}