www/apps/resources/app/storefront-development/customers/login/page.mdx
import { CodeTabs, CodeTab, Table } from "docs-ui"
export const metadata = {
title: Login Customer in Storefront,
}
In this guide, you'll learn about the two ways to login a customer in your storefront.
<Note>This guide covers login using email and password. For authentication with third-party providers, refer to the Third-Party Login guide.
</Note>There are two ways to login a customer in your storefront:
/auth/customer/emailpass API route and is used as a bearer token in the authorization header of all requests./auth/session API route to set the authenticated session ID in the cookies.The JS SDK simplifies the login approach in a single auth.login method. The upcoming sections explain the authentication approach whether you're using the JS SDK or not.
The authentication method you choose depends on your use case and the type of storefront you're building.
Refer to the JS SDK Authentication guide to learn more about the differences between JWT and session authentication and which one is best for your use case.
Before implementing the login flow, you need to configure in the JS SDK the authentication method you're using in your storefront. This defines how the JS SDK will handle sending authenticated requests after the customer is authenticated.
For example, add the following configuration to your JS SDK initialization:
<Note title="Tip">Learn how to install and configure the JS SDK in the JS SDK documentation.
</Note> <CodeTabs group="authenticated-configuration"> <CodeTab label="JWT" value="jwt">export const sdk = new Medusa({
// ...
auth: {
type: "jwt",
},
})
export const sdk = new Medusa({
// ...
auth: {
type: "session",
},
})
The JS SDK will now pass the JWT token or the session ID cookie in the authorization header of all subsequent requests based on the authentication method you've configured.
Refer to the JS SDK Authentication guide for more information about these configurations, as well as other authentication configurations.
<Note title="Tip">By default, when you choose the jwt method, the JWT token is stored in the browser's localStorage. However, you can change how the token is stored, which is useful in environments where localStorage is not available. For example, in React Native.
To learn how to change the storage method with an example for a React Native storefront, refer to the JS SDK Authentication guide.
</Note>The JS SDK provides an auth.login method that handles all authentication steps based on the configured authentication method. Then, all subsequent requests will have the necessary authentication headers or cookies.
For example, to implement the login flow in your storefront with the JS SDK:
<CodeTabs group="store-request"> <CodeTab label="React" value="react">export const highlights = [ ["24", "login", "Send a request to obtain a JWT token."], ["28", "catch", "If an error occurs, show an alert and exit execution."], ["33", "", "If the token is not a string, show an alert and exit execution."], ["39", "retrieve", "Retrieve the customer's details as an example of testing authentication."], ]
"use client" // include with Next.js 13+
import { useState } from "react"
import { sdk } from "@/lib/sdk"
export default function Login() {
const [loading, setLoading] = useState(false)
const [email, setEmail] = useState("")
const [password, setPassword] = useState("")
const handleLogin = async (
e: React.MouseEvent<HTMLButtonElement, MouseEvent>
) => {
e.preventDefault()
if (!email || !password) {
return
}
setLoading(true)
let token: string | { location: string }
try {
token = await sdk.auth.login("customer", "emailpass", {
email,
password,
})
} catch (error) {
alert(`An error occurred while logging in: ${error}`)
return
}
if (typeof token !== "string") {
alert("Authentication requires more actions, which isn't supported by this flow.")
return
}
// all next requests will be authenticated
const { customer } = await sdk.store.customer.retrieve()
console.log(customer)
setLoading(false)
}
return (
<form>
<input
type="email"
name="email"
value={email}
placeholder="Email"
onChange={(e) => setEmail(e.target.value)}
/>
<input
type="password"
name="password"
value={password}
placeholder="Password"
onChange={(e) => setPassword(e.target.value)}
/>
<button
disabled={loading}
onClick={handleLogin}
>
Login
</button>
</form>
)
}
export const fetchHighlights = [ ["5", "login", "Send a request to obtain a JWT token."], ["9", "catch", "If an error occurs, show an alert and exit execution."], ["14", "", "If the token is not a string, show an alert and exit execution."], ["20", "retrieve", "Retrieve the customer's details as an example of testing authentication."], ]
const handleLogin = async () => {
let token: string | { location: string }
try {
token = await sdk.auth.login("customer", "emailpass", {
email,
password,
})
} catch (error) {
alert(`An error occurred while logging in: ${error}`)
return
}
if (typeof token !== "string") {
alert("Authentication requires more actions, which isn't supported by this flow.")
return
}
// all next requests will be authenticated
const { customer } = await sdk.store.customer.retrieve()
console.log(customer)
}
In the example above, you:
handleLogin function that logs in a customer.sdk.auth.login method.
location property. This occurs when using third-party authentication providers. Learn more about implementing third-party authentication in the Third-Party Login guide.If you're not using the JS SDK, the next sections cover the general flow for authenticating a customer in your storefront for both methods.
The first authentication approach is to pass an authenticated JWT token in the authorization header of all requests. You can do that by:
/auth/customer/emailpass Authenticate Customer API route:curl -X POST '{backend_url}/auth/customer/emailpass' \
-H 'Content-Type: application/json' \
--data-raw '{
"email": "[email protected]",
"password": "supersecret"
}'
Authorization: Bearer {jwt_token}
You can store the obtained JWT token based on your use case. For example, you can store it in the browser's localStorage or sessionStorage. This way, you can retrieve it later and pass it in the authorization header of all requests.
The second authentication approach is to authenticate the customer with a cookie session. You do that by:
/auth/customer/emailpass Authenticate Customer API route:curl -X POST '{backend_url}/auth/customer/emailpass' \
-H 'Content-Type: application/json' \
--data-raw '{
"email": "[email protected]",
"password": "supersecret"
}'
/auth/session Authentication Session API route passing in the authorization header the token as a Bearer token. This sets the authenticated session ID in the cookies:curl -X POST '{backend_url}/auth/session' \
-H 'Authorization: Bearer {jwt_token}'
curl '{backend_url}/store/products' \
-H 'Cookie: connect.sid={sid}'
fetch(`<BACKEND_URL>/store/products`, {
credentials: "include",
})