- Get Started
- Product
- Resources
- Tools & SDKs
- Framework
- Reference
- User Guide
- Get Started
- Product
- Resources
- Tools & SDKs
- Framework
- Reference
- User Guide
Third-Party or Social Login in Storefront
To login a customer with a third-party service, such as Google or GitHub, you must follow the following flow:
Explanation
You'll implement the flow in this guide using Google as an example.
Step 1: Authenticate Customer in Medusa#
When the customer clicks on a "Login with Google" button, send a request to the Authenticate Customer API route.
For example:
1const loginWithGoogle = async () => {2 const result = await fetch(3 `http://localhost:9000/auth/customer/google`,4 {5 credentials: "include",6 method: "POST",7 }8 ).then((res) => res.json())9 10 if (result.location) {11 // redirect to Google for authentication12 window.location.href = result.location13 14 return15 }16 17 if (!result.token) {18 // result failed, show an error19 alert("Authentication failed")20 return21 }22 23 // authentication successful24 // use token in the authorization header of 25 // all follow up requests. For example:26 const { customer } = await fetch(27 `http://localhost:9000/store/customers/me`,28 {29 credentials: "include",30 headers: {31 "Content-Type": "application/json",32 "Authorization": `Bearer ${result.token}`,33 "x-publishable-api-key": process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY || "temp",34 },35 }36 )37 .then((res) => res.json())38}
If the Authenticate Customer API route returns a location
, then you redirect to the returned page for authentication with the third-party service.
If the route returns a token
, then the customer has been authenticated before. You can use the token for subsequent authenticated request.
google
, replace google
in the URL http://localhost:9000/auth/customer/google
with your provider ID.Step 2: Callback Page in Storefront#
The next step is to create a page in your storefront that the customer is redirected to after they authenticate with Google.
You'll use this page's URL as the Redirect Uri in your Google settings, and set it in the callbackUrl
of your Google provider's configurations.
First, install the react-jwt library in your storefront to use it for decoding the token:
Then, in a new page in your storefront that will be used as the callback / redirect uri destination, add the following:
1import { decodeToken } from "react-jwt"2 3// ...4 5const searchParams = new URLSearchParams(window.location.search)6const queryParams = Object.fromEntries(searchParams.entries())7 8const sendCallback = async () => {9 const { token } = await fetch(10 `http://localhost:9000/auth/customer/google/callback?${new URLSearchParams(queryParams).toString()}`, 11 {12 credentials: "include",13 method: "POST",14 }15 ).then((res) => res.json())16 17 if (!token) {18 alert("Authentication Failed")19 return20 }21 22 return token23}24 25// TODO add more functions...
This adds in the new page the function sendCallback
which sends a request to the Validate Callback API route, passing it the query parameters received from Google.
Then, replace the TODO
with the following:
1const createCustomer = async (token: string) => {2 await fetch(`http://localhost:9000/store/customers`, {3 credentials: "include",4 method: "POST",5 headers: {6 "Content-Type": "application/json",7 "Authorization": `Bearer ${token}`,8 "x-publishable-api-key": process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY || "temp",9 },10 body: JSON.stringify({11 // TODO show form to retrieve email from customer12 email: "example@medusajs.com",13 }),14 }).then((res) => res.json())15}16 17// TODO add more functions...
This adds to the page the function createCustomer
which, if the customer is new, it uses the token received from the Validate Callback API route to create a new customer.
Next, replace the new TODO
with the following:
1const refreshToken = async (token: string) => {2 const result = await fetch(`http://localhost:9000/auth/token/refresh`, {3 credentials: "include",4 method: "POST",5 headers: {6 "Authorization": `Bearer ${token}`,7 },8 }).then((res) => res.json())9 10 return result.token11}12 13// TODO add more functions...
This adds to the page the function refreshToken
which is used after the new customer is created to refresh their authentication token. This ensures that the authentication token includes the details of the created customer.
Finally, add in the place of the new TODO
the validateCallback
function that runs when the page first loads to validate the authentication:
1const validateCallback = async () => {2 let { token } = await sendCallback()3 4 const shouldCreateCustomer = (decodeToken(token) as { actor_id: string }).actor_id === ""5 6 if (shouldCreateCustomer) {7 await createCustomer(token)8 9 token = await refreshToken(token)10 }11 12 // use token to send authenticated requests13 const { customer } = await fetch(14 `http://localhost:9000/store/customers/me`, 15 {16 credentials: "include",17 method: "GET",18 headers: {19 "Content-Type": "application/json",20 "Authorization": `Bearer ${token}`,21 "x-publishable-api-key": process.env.NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY || "temp",22 },23 }24 ).then((res) => res.json())25}
The validateCallback
function uses the functions added earlier to:
- Send a request to the Validate Callback API route, which returns an authentication token.
- Decodes the token to check if it has an
actor_id
property.
- If so, then the customer is previously registered, and the authentication token can be used for subsequent authenticated requests.
- If not:
- Create a customer using the Create Customer API route.
- Refetch the customer's token after it's created using the Refresh Token API route.
- Use the token for subsequent authenticated requests.