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.
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
}
}
Replace src/App.jsx with: 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 } ` );
}
}
}
You can also retrieve the raw compliancy configuration to build your own validation UI:
const compliancy = await client . getPasswordCompliancy ();
// { min_length: 12, max_length: 128, uppercase: 1, lowercase: 1, numbers: 1, symbols: 1 }
Replace src/App.jsx with: 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 >
</>
);
}