docs: update auth docs + add new storefront guides (#9020)

* docs: update auth docs + add new storefront guides

* lint content

* fix vale error

* add callback response schema

* Update www/apps/resources/app/commerce-modules/auth/auth-providers/github/page.mdx

Co-authored-by: Stevche Radevski <sradevski@live.com>

* Update www/apps/resources/app/commerce-modules/auth/auth-providers/github/page.mdx

Co-authored-by: Stevche Radevski <sradevski@live.com>

* Update www/apps/resources/app/commerce-modules/auth/authentication-route/page.mdx

Co-authored-by: Stevche Radevski <sradevski@live.com>

* address PR comments

* replace google -> github

* better explanation for refresh token

---------

Co-authored-by: Stevche Radevski <sradevski@live.com>
This commit is contained in:
Shahed Nasser
2024-09-06 15:26:10 +03:00
committed by GitHub
parent cf3c25addf
commit a28c911c24
29 changed files with 1477 additions and 316 deletions

View File

@@ -168,7 +168,7 @@ export default async function productCreateHandler({
disposition: "attachment or inline attachment",
id: "id", // only needed for inline attachment
},
]
],
})
}

View File

@@ -50,24 +50,38 @@ This method calls the `authenticate` method of the provider specified in the fir
## Auth Flow 1: Basic Authentication
The basic authentication flow requires first using the `register` method, then the `authenticate` method.
If the `authenticate` method returns the following object:
The basic authentication flow requires first using the `register` method, then the `authenticate` method:
```ts
data = {
success: true,
authIdentity: {
const { success, authIdentity } = await authModuleService.register(
"emailpass",
// passed to auth provider
{
// ...
},
}
)
// later (can be another route for log-in)
const { success, authIdentity, location } = await authModuleService.authenticate(
"emailpass",
// passed to auth provider
{
// ...
}
)
if (success && !location) {
// user is authenticated
}
```
Then, the user is authenticated successfully, and their authentication details are available within the `authIdentity` object.
If `success` is true and `location` isn't set, the user is authenticated successfully, and their authentication details are available within the `authIdentity` object.
The next section explains the flow if `location` is set.
<Note>
Check out the [AuthIdentity](/references/auth/models/AuthIdentity) reference for the expected properties in `authIdentity`.
Check out the [AuthIdentity](/references/auth/models/AuthIdentity) reference for the received properties in `authIdentity`.
</Note>
@@ -77,18 +91,31 @@ Check out the [AuthIdentity](/references/auth/models/AuthIdentity) reference for
## Auth Flow 2: Third-Party Service Authentication
The third-party service authentication method requires using the `authenticate` method first.
If the `authenticate` method returns the following object:
The third-party service authentication method requires using the `authenticate` method first:
```ts
data = {
success: true,
location: "https://....",
const { success, authIdentity, location } = await authModuleService.authenticate(
"emailpass",
// passed to auth provider
{
// ...
}
)
if (location) {
// return the location for the front-end to redirect to
}
if (!success) {
// authentication failed
}
// authentication successful
```
It means the authentication process requires the user to perform an action with a third-party service. For example, when using the `google` provider, the user goes to the URL specified in the `location`'s value to log in with their Google account.
If the `authenticate` method returns a `location` property, the authentication process requires the user to perform an action with a third-party service. So, you return the `location` to the front-end or client to redirect to that URL.
For example, when using the `google` provider, the `location` is the URL that the user is navigated to login.
![Diagram showcasing the first part of the third-party authentication flow](https://res.cloudinary.com/dza7lstvk/image/upload/v1711374847/Medusa%20Resources/third-party-auth-1_enyedy.jpg)
@@ -96,27 +123,29 @@ It means the authentication process requires the user to perform an action with
Providers handling this authentication flow must implement the `validateCallback` method. It implements the logic to validate the authentication with the third-party service.
So, once the user performs the required action, the third-party service must redirect to an API route that uses the [validateCallback method of the Auth Module's main service](/references/auth/validateCallback). The method calls the specified providers `validateCallback` method passing it the authentication details it received in the second parameter:
So, once the user performs the required action with the third-party service (for example, log-in with Google), the frontend must redirect to an API route that uses the [validateCallback method of the Auth Module's main service](/references/auth/validateCallback).
The method calls the specified providers `validateCallback` method passing it the authentication details it received in the second parameter:
```ts
const data = await authModuleService.validateCallback(
"google",
// passed to auth provider
{
// ...
}
)
```
const { success, authIdentity } = await authModuleService.validateCallback(
"google",
// passed to auth provider
{
// request data, such as
url,
headers,
query,
body,
protocol,
}
)
If the authentication is successful, the `validateCallback` method returns the same data as the basic authentication:
```ts
data = {
success: true,
authIdentity: {
// ...
},
if (success) {
// authentication succeeded
}
```
If the returned `success` property is `true`, the authentication with the third-party provider was successful.
![Diagram showcasing the second part of the third-party authentication flow](https://res.cloudinary.com/dza7lstvk/image/upload/v1711375123/Medusa%20Resources/third-party-auth-2_kmjxju.jpg)

View File

@@ -8,9 +8,9 @@ In this document, youll learn about concepts related to identity and actors i
## What is an Auth Identity?
The [AuthIdentity data model](/references/auth/model/AuthIdentity) represents a previously-authenticated user.
The [AuthIdentity data model](/references/auth/model/AuthIdentity) represents a registered user.
When a user is authenticated, a record of `AuthIdentity` is created. This record is used to validate the users authentication in future requests.
When a user is registered, a record of `AuthIdentity` is created. This record is used to validate the users authentication in future requests.
---
@@ -18,7 +18,7 @@ When a user is authenticated, a record of `AuthIdentity` is created. This record
An actor type is a type of user that can be authenticated. This user is a record of a data model defined by a module.
For example, the `customer` belongs to the Customer Modules `Customer` data model. Similarly, the `user` belongs to the User Modules `User` data model.
For example, the `customer` actor type belongs to the Customer Modules `Customer` data model. Similarly, the `user` actor type belongs to the User Modules `User` data model.
### Protect Routes by Actor Type
@@ -48,7 +48,7 @@ export default defineMiddlewares({
})
```
By specifying `user` as the first parameter of `authenticate`, only authenticated users of actor type `user` can access API routes starting with `/custom/admin`.
By specifying `user` as the first parameter of `authenticate`, only authenticated users of actor type `user` (admin users) can access API routes starting with `/custom/admin`.
---

View File

@@ -1,186 +0,0 @@
import { Table } from "docs-ui"
export const metadata = {
title: `Google Auth Module Provider`,
}
# {metadata.title}
In this document, youll learn about the Google auth module provider and how to install and use it in the Auth Module.
## Features
The Google auth module provider handles authenticating users with their Google accounts.
By integrating the Google auth provider, you provide your users and customers with the ability to login with their Google account.
---
## Install the Google Auth Module Provider
<Note type="check">
- [Create a project in Google Cloud.](https://cloud.google.com/resource-manager/docs/creating-managing-projects).
- [Create authorization credentials](https://developers.google.com/identity/protocols/oauth2/web-server#creatingcred).
- Set the Redirect Uri of your Oauth Client ID to `{medusa_url}/auth/{actor_type}/google/callback`, where:
- `{medusa_url}` is the URL of your Medusa backend.
- `{actor_type}` is the actor type that the Google auth provider can authenticate. For example, `customer`.
</Note>
To install the Google auth module provider, run the following command in the directory of your Medusa application:
```bash npm2yarn
npm install @medusajs/auth-google
```
Next, add the module to the array of providers passed to the Auth Module:
```js title="medusa-config.js"
import { Modules } from "@medusajs/utils"
// ...
const modules = {
// ...
[Modules.AUTH]: {
resolve: "@medusajs/auth",
options: {
providers: [
{
resolve: "@medusajs/auth-google",
id: "google",
options: {
clientID: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
callbackURL: process.env.GOOGLE_CALLBACK_URL,
successRedirectUrl:
process.env.GOOGLE_SUCCESS_REDIRECT_URL,
},
},
],
},
},
}
```
### Environment Variables
Make sure to add the necessary environment variables for the above options in `.env`:
```bash
GOOGLE_CLIENT_ID=<YOUR_GOOGLE_CLIENT_ID>
GOOGLE_CLIENT_SECRET=<YOUR_GOOGLE_CLIENT_SECRET>
GOOGLE_CALLBACK_URL=<YOUR_GOOGLE_CALLBACK_URL>
GOOGLE_SUCCESS_REDIRECT_URL=<YOUR_GOOGLE_SUCCESS_REDIRECT_URL>
```
### Module Options
<Table>
<Table.Header>
<Table.Row>
<Table.HeaderCell>Configuration</Table.HeaderCell>
<Table.HeaderCell>Description</Table.HeaderCell>
<Table.HeaderCell>Required</Table.HeaderCell>
<Table.HeaderCell>Default</Table.HeaderCell>
</Table.Row>
</Table.Header>
<Table.Body>
<Table.Row>
<Table.Cell>
`clientID`
</Table.Cell>
<Table.Cell>
A string indicating the [Google API Client ID](https://developers.google.com/identity/oauth2/web/guides/get-google-api-clientid).
</Table.Cell>
<Table.Cell>
Yes
</Table.Cell>
<Table.Cell>
\-
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
`clientSecret`
</Table.Cell>
<Table.Cell>
A string indicating the [Google Client Secret](https://support.google.com/cloud/answer/6158849?hl=en#zippy=%2Cstep-create-a-new-client-secret).
</Table.Cell>
<Table.Cell>
Yes
</Table.Cell>
<Table.Cell>
\-
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
`callbackURL`
</Table.Cell>
<Table.Cell>
A string indicating the URL to redirect to in your app after the user completes their authentication in Google.
The Medusa application provides the API route `/auth/[scope]/google/callback` that you can use, where `[scope]` is the scope this config belongs to.
For example, `/auth/store/google/callback`.
</Table.Cell>
<Table.Cell>
Yes
</Table.Cell>
<Table.Cell>
\-
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
`successRedirectUrl`
</Table.Cell>
<Table.Cell>
A string indicating the URL to redirect to in your app after the authentication has been successful.
If not provided, the Medusa application's callback route just returns a JSON with the JWT token of the auth identity.
</Table.Cell>
<Table.Cell>
No
</Table.Cell>
<Table.Cell>
\-
</Table.Cell>
</Table.Row>
</Table.Body>
</Table>
{/* TODO add how to implement authentication flow with google */}

View File

@@ -8,8 +8,6 @@ export const metadata = {
In this document, youll learn about the Emailpass auth module provider and how to install and use it in the Auth Module.
## Features
Using the Emailpass auth module provider, you allow users to register and login with an email and password.
---
@@ -31,6 +29,7 @@ const modules = {
resolve: "@medusajs/auth",
options: {
providers: [
// other providers...
{
resolve: "@medusajs/auth-emailpass",
id: "emailpass",

View File

@@ -0,0 +1,152 @@
import { Table, Prerequisites } from "docs-ui"
export const metadata = {
title: `GitHub Auth Module Provider`,
}
# {metadata.title}
In this document, youll learn about the GitHub Auth Module Provider and how to install and use it in the Auth Module.
The Github Auth Module Provider handles authenticating users with their GitHub account.
<Note title="Tip">
Learn about the authentication flow in [this guide](../../authentication-route/page.mdx).
</Note>
---
## Install the Github Auth Module Provider
<Prerequisites
items={[
{
text: "Register GitHub App. When setting the Callback URL, set it to a URL in your frontend that later uses Medusa's callback route to validate the authentication.",
link: "https://docs.github.com/en/apps/creating-github-apps/setting-up-a-github-app/creating-a-github-app"
},
{
text: "Retrieve the client ID and client secret of your GitHub App",
link: "https://docs.github.com/en/rest/authentication/authenticating-to-the-rest-api?apiVersion=2022-11-28#using-basic-authentication"
}
]}
/>
To install the GitHub auth module provider, run the following command in the directory of your Medusa application:
```bash npm2yarn
npm install @medusajs/auth-github@preview
```
Next, add the module to the array of providers passed to the Auth Module:
```js title="medusa-config.js"
import { Modules } from "@medusajs/utils"
// ...
const modules = {
// ...
[Modules.AUTH]: {
resolve: "@medusajs/auth",
options: {
providers: [
// other providers...
{
resolve: "@medusajs/auth-github",
id: "github",
options: {
clientId: process.env.GITHUB_CLIENT_ID,
clientSecret: process.env.GITHUB_CLIENT_SECRET,
callbackUrl: process.env.GITHUB_CALLBACK_URL,
},
},
],
},
},
}
```
### Environment Variables
Make sure to add the necessary environment variables for the above options in `.env`:
```plain
GITHUB_CLIENT_ID=<YOUR_GITHUB_CLIENT_ID>
GITHUB_CLIENT_SECRET=<YOUR_GITHUB_CLIENT_SECRET>
GITHUB_CALLBACK_URL=<YOUR_GITHUB_CALLBACK_URL>
```
### Module Options
<Table>
<Table.Header>
<Table.Row>
<Table.HeaderCell>Configuration</Table.HeaderCell>
<Table.HeaderCell>Description</Table.HeaderCell>
<Table.HeaderCell className="w-1/5">Required</Table.HeaderCell>
</Table.Row>
</Table.Header>
<Table.Body>
<Table.Row>
<Table.Cell>
`clientId`
</Table.Cell>
<Table.Cell>
A string indicating the client ID of your GitHub app.
</Table.Cell>
<Table.Cell>
Yes
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
`clientSecret`
</Table.Cell>
<Table.Cell>
A string indicating the client secret of your GitHub app.
</Table.Cell>
<Table.Cell>
Yes
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
`callbackUrl`
</Table.Cell>
<Table.Cell>
A string indicating the URL to redirect to in your frontend after the user completes their authentication in GitHub.
At this URL, the frontend will receive a `code` query parameter. It then sends that `code` query parameter to the Medusa application's `/auth/{actor_type}/github/callback` route.
</Table.Cell>
<Table.Cell>
Yes
</Table.Cell>
</Table.Row>
</Table.Body>
</Table>
---
## Examples
- [How to implement third-party / social login in the storefront.](../../../../storefront-development/customers/third-party-login/page.mdx).

View File

@@ -0,0 +1,152 @@
import { Table, Prerequisites } from "docs-ui"
export const metadata = {
title: `Google Auth Module Provider`,
}
# {metadata.title}
In this document, youll learn about the Google Auth Module Provider and how to install and use it in the Auth Module.
The Google Auth Module Provider handles authenticating users with their Google account.
<Note title="Tip">
Learn about the authentication flow in [this guide](../../authentication-route/page.mdx).
</Note>
---
## Install the Google Auth Module Provider
<Prerequisites
items={[
{
text: "Create a project in Google Cloud.",
link: "https://cloud.google.com/resource-manager/docs/creating-managing-projects"
},
{
text: "Create authorization credentials. When setting the Redirect Uri, set it to a URL in your frontend that later uses Medusa's callback route to validate the authentication.",
link: "https://developers.google.com/identity/protocols/oauth2/web-server#creatingcred"
}
]}
/>
To install the Google auth module provider, run the following command in the directory of your Medusa application:
```bash npm2yarn
npm install @medusajs/auth-google@preview
```
Next, add the module to the array of providers passed to the Auth Module:
```js title="medusa-config.js"
import { Modules } from "@medusajs/utils"
// ...
const modules = {
// ...
[Modules.AUTH]: {
resolve: "@medusajs/auth",
options: {
providers: [
// other providers...
{
resolve: "@medusajs/auth-google",
id: "google",
options: {
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
callbackUrl: process.env.GOOGLE_CALLBACK_URL,
},
},
],
},
},
}
```
### Environment Variables
Make sure to add the necessary environment variables for the above options in `.env`:
```plain
GOOGLE_CLIENT_ID=<YOUR_GOOGLE_CLIENT_ID>
GOOGLE_CLIENT_SECRET=<YOUR_GOOGLE_CLIENT_SECRET>
GOOGLE_CALLBACK_URL=<YOUR_GOOGLE_CALLBACK_URL>
```
### Module Options
<Table>
<Table.Header>
<Table.Row>
<Table.HeaderCell>Configuration</Table.HeaderCell>
<Table.HeaderCell>Description</Table.HeaderCell>
<Table.HeaderCell className="w-1/5">Required</Table.HeaderCell>
</Table.Row>
</Table.Header>
<Table.Body>
<Table.Row>
<Table.Cell>
`clientId`
</Table.Cell>
<Table.Cell>
A string indicating the [Google API Client ID](https://developers.google.com/identity/oauth2/web/guides/get-google-api-clientid).
</Table.Cell>
<Table.Cell>
Yes
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
`clientSecret`
</Table.Cell>
<Table.Cell>
A string indicating the [Google Client Secret](https://support.google.com/cloud/answer/6158849?hl=en#zippy=%2Cstep-create-a-new-client-secret).
</Table.Cell>
<Table.Cell>
Yes
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>
`callbackUrl`
</Table.Cell>
<Table.Cell>
A string indicating the URL to redirect to in your frontend after the user completes their authentication in Google.
At this URL, the frontend will receive a `code` query parameter. It then sends that `code` query parameter to the Medusa application's `/auth/{actor_type}/google/callback` route.
</Table.Cell>
<Table.Cell>
Yes
</Table.Cell>
</Table.Row>
</Table.Body>
</Table>
---
## Examples
- [How to implement Google social login in the storefront.](../../../../storefront-development/customers/third-party-login/page.mdx).

View File

@@ -1,3 +1,5 @@
import { CardList } from "docs-ui"
export const metadata = {
title: `Auth Providers`,
}
@@ -12,11 +14,24 @@ An auth module provider handles authenticating customers and users, either using
For example, the EmailPass Auth Module Provider authenticates a user using their email and password, whereas the Google Auth Module Provider authenticates users using their Google account.
<Note type="soon">
### Auth Providers List
Support for the Google Auth Module Provider is coming soon.
</Note>
<CardList
items={[
{
title: "Emailpass",
href: "/commerce-modules/auth/auth-providers/emailpass"
},
{
title: "Google",
href: "/commerce-modules/auth/auth-providers/google"
},
{
title: "GitHub",
href: "/commerce-modules/auth/auth-providers/github"
},
]}
/>
---

View File

@@ -18,24 +18,51 @@ These routes are added by Medusa's application layer, not the Auth Module.
This authentication flow doesn't require validation with third-party services.
It requires the following steps:
<Note title="Example">
1. Registering the user with the [Register Route](#register-route).
2. Authenticating the user with the [Auth Route](#auth-route).
[How to register customer in storefront using basic authentication flow](../../../storefront-development/customers/register/page.mdx).
</Note>
The steps are:
![Diagram showcasing the basic authentication flow between the frontend and the Medusa application](https://res.cloudinary.com/dza7lstvk/image/upload/v1725539370/Medusa%20Resources/basic-auth-routes_pgpjch.jpg)
1. Register the user with the [Register Route](#register-route).
5. Use the authentication token to create the user with their respective API route.
- For example, for customers you would use the [Create Customer API route](!api!/store#customers_postcustomers).
- For admin users, you accept an invite using the [Accept Invite API route](!api!/admin#invites_postinvitesaccept)
2. Authenticate the user with the [Auth Route](#auth-route).
After registration, you only use the [Auth Route](#auth-route) for subsequent authentication.
### 2. Third-Party Service Authenticate Flow
This authentication flow authenticates the user with a third-party service, such as Google.
<Note title="Example">
[How to authenticate customer with a third-party provider in the storefront.](../../../storefront-development/customers/third-party-login/page.mdx).
</Note>
It requires the following steps:
1. Authenticate the user with the [Auth Route](#auth-route).
2. If the authentication requires more action with the third-party service:
1. The auth route redirects to the third-party service's authentication portal. The URL is returned by the Auth Module Provider.
2. Once the authentication with the third-party service finishes, it redirects back to the [Callback Route](#callback-route). So, make sure your third-party service is configured to redirect to the [Callback Route](#callback-route).
3. If the callback validation is successful, you'll receive the authentication token.
![Diagram showcasing the authentication flow between the frontend, Medusa application, and third-party service](https://res.cloudinary.com/dza7lstvk/image/upload/v1725528159/Medusa%20Resources/Third_Party_Auth_tvf4ng.jpg)
1. Authenticate the user with the [Auth Route](#auth-route).
2. The auth route returns a URL to authenticate with third-party service, such as login with Google. The frontend (such as a storefront), when it receives a `location` property in the response, must redirect to the returned location.
3. Once the authentication with the third-party service finishes, it redirects back to the frontend with a `code` query parameter. So, make sure your third-party service is configured to redirect to your frontend page after successful authentication.
4. The frontend sends a request to the [Callback Route](#callback-route) passing the `code` query parameter.
5. If the callback validation is successful, the frontend receives the authentication token.
6. Decode the received token in the frontend using tools like [react-jwt](https://www.npmjs.com/package/react-jwt).
- If the decoded data has an `actor_id` property, then the user is already registered. So, use this token for subsequent authenticated requests.
- If not, follow the rest of the steps.
7. The frontend uses the authentication token to create the user with their respective API route.
- For example, for customers you would use the [Create Customer API route](!api!/store#customers_postcustomers).
- For admin users, you accept an invite using the [Accept Invite API route](!api!/admin#invites_postinvitesaccept)
8. The frontend sends a request to the [Refresh Token Route](#refresh-token-route) to retrieve a new token with the user information populated.
You may then use the [Auth Route](#auth-route) for subsequent authentication.
---
@@ -43,6 +70,15 @@ You may then use the [Auth Route](#auth-route) for subsequent authentication.
The Medusa application defines an API route at `/auth/{actor_type}/{provider}/register` that creates an auth identity for an actor type, such as a `customer`. It returns a JWT token that you pass to an API route that creates the user.
```bash
curl -X POST http://localhost:9000/auth/{actor_type}/{providers}/register
-H 'Content-Type: application/json' \
--data-raw '{
"email": "Whitney_Schultz@gmail.com"
// ...
}'
```
<Note>
This API route is useful for providers like `emailpass` that uses custom logic to authenticate a user. For authentication providers that authenticate with third-party services, such as Google, use the [Auth Route](#auth-route) instead.
@@ -77,11 +113,7 @@ If the authentication is successful, you'll receive a `token` field in the respo
}
```
<Note title="Example">
[How to register Customers using the authentication route](../../../storefront-development/customers/register/page.mdx).
</Note>
Use that token in the header of subsequent requests to send authenticated requests.
---
@@ -89,6 +121,15 @@ If the authentication is successful, you'll receive a `token` field in the respo
The Medusa application defines an API route at `/auth/{actor_type}/{provider}` that authenticates a user of an actor type. It returns a JWT token that can be passed in [the header of subsequent requests](!api!/store#authentication) to send authenticated requests.
```bash
curl -X POST http://localhost:9000/auth/{actor_type}/{providers}
-H 'Content-Type: application/json' \
--data-raw '{
"email": "Whitney_Schultz@gmail.com"
// ...
}'
```
For example, if you're authenticating a customer, you send a request to `/auth/customer/emailpass`.
### Path Parameters
@@ -114,6 +155,18 @@ If the authentication is successful, you'll receive a `token` field in the respo
}
```
Use that token in the header of subsequent requests to send authenticated requests.
If the authentication requires more action with a third-party service, you'll receive a `location` property:
```json
{
"location": "https://..."
}
```
Redirect to that URL in the frontend to continue the authentication process with the third-party service.
<Note title="Example">
[How to login Customers using the authentication route](../../../storefront-development/customers/login/page.mdx).
@@ -124,18 +177,18 @@ If the authentication is successful, you'll receive a `token` field in the respo
## Validate Callback Route
The Medusa application defines an API route at `/auth/{actor_type}/{provider}/callback` that's useful for authenticating users with third-party services, such as Google.
The Medusa application defines an API route at `/auth/{actor_type}/{provider}/callback` that's useful for validating the authentication callback or redirect from third-party services like Google.
When integrating with a third-party service, you use [Auth Route](#auth-route) first to authenticate the user. If the authentication requires more action with the third-party provider, the request redirects to the authentication provider's authentication portal.
```bash
curl -X POST http://localhost:9000/auth/{actor_type}/{providers}/callback?code=123
```
<Note title="Tip">
The URL of the authentication portal is received from the Auth Module Provider.
Refer to the [third-party authentication flow](#2-third-party-service-authenticate-flow) section to see how this route fits into the authentication flow.
</Note>
Once the authentication with the third-party provider finishes, it should redirect back to this API route. So, make sure to add the necessary configuration in your provider to ensure this flow.
### Path Parameters
Its path parameters are:
@@ -143,9 +196,9 @@ Its path parameters are:
- `{actor_type}`: the actor type of the user you're authenticating. For example, `customer`.
- `{provider}`: the auth provider to handle the authentication. For example, `google`.
### Request Body Parameters
### Query Parameters
This route accepts in the request body the data from the third-party service, and passes it along to the authentication provider to validate whether the customer was authenticated.
This route accepts a `code` query parameter, which is the code received from the third-party provider.
### Response Fields
@@ -155,4 +208,34 @@ If the authentication is successful, you'll receive a `token` field in the respo
{
"token": "..."
}
```
```
In your frontend, decode the token using tools like [react-jwt](https://www.npmjs.com/package/react-jwt):
- If the decoded data has an `actor_id` property, the user is already registered. So, use this token for subsequent authenticated requests.
- If not, use the token in the header of a request that creates the user, such as the [Create Customer API route](!api!/store#customers_postcustomers).
---
## Refresh Token Route
The Medusa application defines an API route at `/auth/token/refresh` that's useful after authenticating a user with a third-party service to populate the user's token with their new information.
It requires the user's JWT token that they received from the authentication or callback routes.
```bash
curl -X POST http://localhost:9000/auth/token/refresh \
-H 'Authorization: Bearer {token}'
```
### Response Fields
If the token was refreshed successfully, you'll receive a `token` field in the response body object:
```json
{
"token": "..."
}
```
Use that token in the header of subsequent requests to send authenticated requests.

View File

@@ -251,7 +251,7 @@ To authenticate managers:
1. Send a `POST` request to `/auth/manager/emailpass/register` to create an auth identity for the manager:
```bash
curl -X POST 'http://localhost:9000/auth/manager/emailpass' \
curl -X POST 'http://localhost:9000/auth/manager/emailpass/register' \
-H 'Content-Type: application/json' \
--data-raw '{
"email": "manager@gmail.com",

View File

@@ -52,7 +52,7 @@ export async function POST(
}
if (location) {
res.redirect(location)
res.json({ location })
return
}
@@ -90,8 +90,7 @@ export async function POST(request: Request) {
}
if (location) {
return NextResponse.redirect(location)
return
return NextResponse.json({ location })
}
const token = jwt.sign(authIdentity, "supersecret")

View File

@@ -49,9 +49,8 @@ const { success, authIdentity, location } =
protocol: req.protocol,
} as AuthenticationInput)
if (!authIdentity && location) {
res.redirect(location)
return
if (location) {
return res.json({ location })
}
// in callback API route

View File

@@ -0,0 +1,650 @@
import { Prerequisites, CodeTabs, CodeTab, Details } from "docs-ui"
export const metadata = {
title: `Third-Party or Social Login in Storefront`,
}
# {metadata.title}
To login a customer with a third-party service, such as Google or GitHub, you must follow the following flow:
![Diagram illustrating the authentication flow between the storefront, Medusa application, and the third-party service.](https://res.cloudinary.com/dza7lstvk/image/upload/v1725531068/Medusa%20Resources/Social_Media_Graphics_third-party-auth-customer_kfn3k3.jpg)
<Details summaryContent="Explanation" className="my-1">
1. Authenticate the customer with the [Authenticate Customer API route](!api!/store#auth_postactor_typeauth_provider).
2. The auth route returns a URL to authenticate with third-party service, such as login with Google. The storefront, when it receives a `location` property in the response, must redirect to the returned location.
3. Once the authentication with the third-party service finishes, it redirects back to the storefront with a `code` query parameter. So, make sure your third-party service is configured to redirect to your storefront page after successful authentication.
4. The storefront sends a request to the [Validate Authentication Callback API route](!api!/store#auth_postactor_typeauth_providercallback) passing the `code` query parameter.
5. If the callback validation is successful, the storefront receives the authentication token.
6. Decode the received token in the frontend using tools like [react-jwt](https://www.npmjs.com/package/react-jwt).
- If the decoded data has an `actor_id` property, then the user is already registered. So, use this token for subsequent authenticated requests.
- If not, follow the rest of the steps.
7. The storefront uses the authentication token to create the customer using the [Create Customer API route](!api!/store#customers_postcustomers).
8. The storefront sends a request to the [Refresh Token Route](#refresh-token-route) to retrieve a new token for the customer.
</Details>
You'll implement the flow in this guide using Google as an example.
<Prerequisites
items={[
{
text: "Install the Google Auth Module Provider in your Medusa application, or follow along the same steps with the provider you're using.",
link: "/commerce-modules/auth/auth-providers/google"
}
]}
/>
## 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](!api!/store#auth_postactor_typeauth_provider).
For example:
<CodeTabs group="authenticated-request">
<CodeTab label="Fetch API" value="fetch">
export const fetchHighlights = [
["2", "fetch", "Send a request to the Authenticate Customer API route"],
["10", "result.location", "If the request returns a location, redirect to that location to continue the authentication."],
["17", "!result.token", "If the token isn't returned, the authentication has failed."],
["26", "fetch", "Send a request as an authenticated customer."]
]
```ts highlights={fetchHighlights}
const loginWithGoogle = async () => {
const result = await fetch(
`http://localhost:9000/auth/customer/google`,
{
credentials: "include",
method: "POST",
}
).then((res) => res.json())
if (result.location) {
// redirect to Google for authentication
window.location.href = result.location
return
}
if (!result.token) {
// result failed, show an error
alert("Authentication failed")
return
}
// authentication successful
// use token in the authorization header of
// all follow up requests. For example:
const { customer } = await fetch(
`http://localhost:9000/store/customers/me`,
{
credentials: "include",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${result.token}`,
},
}
)
.then((res) => res.json())
}
```
</CodeTab>
<CodeTab label="React" value="react">
export const reactHighlights = [
["5", "fetch", "Send a request to the Authenticate Customer API route"],
["13", "result.location", "If the request returns a location, redirect to that location to continue the authentication."],
["20", "!result.token", "If the token isn't returned, the authentication has failed."],
["29", "fetch", "Send a request as an authenticated customer."]
]
```tsx highlights={reactHighlights}
"use client" // include with Next.js 13+
export default function Login() {
const loginWithGoogle = async () => {
const result = await fetch(
`http://localhost:9000/auth/customer/google`,
{
credentials: "include",
method: "POST",
}
).then((res) => res.json())
if (result.location) {
// redirect to Google for authentication
window.location.href = result.location
return
}
if (!result.token) {
// result failed, show an error
alert("Authentication failed")
return
}
// authentication successful
// use token in the authorization header of
// all follow up requests. For example:
const { customer } = await fetch(
`http://localhost:9000/store/customers/me`,
{
credentials: "include",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${result.token}`,
},
}
)
.then((res) => res.json())
}
return (
<div>
<button onClick={loginWithGoogle}>Login with Google</button>
</div>
)
}
```
</CodeTab>
</CodeTabs>
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.
<Note title="Tip">
If you're using a provider other than Google, or if you've configured the Google provider with an ID other than `google`, replace `google` in the URL `http://localhost:9000/auth/customer/google` with your provider ID.
</Note>
---
## 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](https://www.npmjs.com/package/react-jwt) in your storefront to use it for decoding the token:
```bash npm2yarn
npm install react-jwt
```
Then, in a new page in your storefront that will be used as the callback / redirect uri destination, add the following:
<CodeTabs group="authenticated-request">
<CodeTab label="Fetch API" value="fetch">
export const sendCallbackFetchHighlights = [
["6", "code", "The code received from Google as a query parameter."],
["9", "fetch", "Send a request to the Validate Authentication Callback API route"],
["17", "!token", "If the token isn't returned, the authentication has failed."],
]
```ts highlights={sendCallbackFetchHighlights}
import { decodeToken } from "react-jwt"
// ...
const queryParams = new URLSearchParams(window.location.search)
const code = queryParams.get("code")
const sendCallback = async () => {
const { token } = await fetch(
`http://localhost:9000/auth/customer/google/callback?code=${code}`,
{
credentials: "include",
method: "POST",
}
).then((res) => res.json())
if (!token) {
alert("Authentication Failed")
return
}
return token
}
// TODO add more functions...
```
</CodeTab>
<CodeTab label="React" value="react">
export const sendCallbackReactHighlights = [
["11", "code", "The code received from Google as a query parameter."],
["18", "fetch", "Send a request to the Validate Authentication Callback API route"],
["26", "!token", "If the token isn't returned, the authentication has failed."],
]
```tsx highlights={sendCallbackReactHighlights}
"use client" // include with Next.js 13+
import { HttpTypes } from "@medusajs/types"
import { useEffect, useMemo, useState } from "react"
import { decodeToken } from "react-jwt"
export default function GoogleCallback() {
const [loading, setLoading] = useState(true)
const [customer, setCustomer] = useState<HttpTypes.StoreCustomer>()
// for other than Next.js
const code = useMemo(() => {
const queryParams = new URLSearchParams(window.location.search)
return queryParams.get("code")
}, [])
const sendCallback = async () => {
const { token } = await fetch(
`http://localhost:9000/auth/customer/google/callback?code=${code}`,
{
credentials: "include",
method: "POST",
}
).then((res) => res.json())
if (!token) {
alert("Authentication Failed")
return
}
return token
}
// TODO add more functions
return (
<div>
{loading && <span>Loading...</span>}
{customer && <span>Created customer {customer.email} with Google.</span>}
</div>
)
}
```
</CodeTab>
</CodeTabs>
This adds in the new page the function `sendCallback` which sends a request to the [Validate Callback API route](!api!/store#auth_postactor_typeauth_providercallback), passing it the `code` received from Google.
Then, replace the `TODO` with the following:
export const createCustomerHighlights = [
["1", "token", "The token received from the Validate Callback API route."],
["2", "fetch", "Create a customer"]
]
```ts highlights={createCustomerHighlights} title="Fetch API / React Applicable"
const createCustomer = async (token: string) => {
await fetch(`http://localhost:9000/store/customers`, {
credentials: "include",
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${token}`,
},
body: JSON.stringify({
// TODO show form to retrieve email from customer
email: "example@medusajs.com",
}),
}).then((res) => res.json())
}
// 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:
export const refreshTokenHighlights = [
["1", "token", "The token received from the Validate Callback API route."],
["2", "fetch", "Fetch a new token for the created customer."]
]
```ts highlights={refreshTokenHighlights} title="Fetch API / React Applicable"
const refreshToken = async (token: string) => {
const result = await fetch(`http://localhost:9000/auth/token/refresh`, {
credentials: "include",
method: "POST",
headers: {
"Authorization": `Bearer ${token}`,
},
}).then((res) => res.json())
return result.token
}
// 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:
<CodeTabs group="authenticated-request">
<CodeTab label="Fetch API" value="fetch">
export const validateFetchHighlights = [
["2", "sendCallback", "Validate the callback in Medusa and retrieve the authentication token"],
["4", "shouldCreateCustomer", "Check if the decoded token has an `actor_id` property to decide whether a customer to be created."],
["7", "createCustomer", "Create a customer if the decoded token doesn't have `actor_id`."],
["9", "refreshToken", "Fetch a new token for the created customer."],
["13", "fetch", "Send an authenticated request using the token."]
]
```ts highlights={validateFetchHighlights}
const validateCallback = async () => {
let { token } = await sendCallback()
const shouldCreateCustomer = (decodeToken(token) as { actor_id: string }).actor_id === ""
if (shouldCreateCustomer) {
await createCustomer(token)
token = await refreshToken(token)
}
// use token to send authenticated requests
const { customer } = await fetch(
`http://localhost:9000/store/customers/me`,
{
credentials: "include",
method: "GET",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${token}`,
},
body: JSON.stringify({
// TODO show form to retrieve email from customer
email: "example@medusajs.com",
}),
}
).then((res) => res.json())
}
```
</CodeTab>
<CodeTab label="React" value="react">
export const validateReactHighlights = [
["2", "sendCallback", "Validate the callback in Medusa and retrieve the authentication token"],
["4", "shouldCreateCustomer", "Check if the decoded token has an `actor_id` property to decide whether a customer to be created."],
["7", "createCustomer", "Create a customer if the decoded token doesn't have `actor_id`."],
["9", "refetchToken", "Fetch a new token for the created customer."],
["13", "fetch", "Send an authenticated request using the token."]
]
```tsx highlights={validateReactHighlights}
const validateCallback = async () => {
let { token } = await sendCallback()
const shouldCreateCustomer = (decodeToken(token) as { actor_id: string }).actor_id === ""
if (shouldCreateCustomer) {
await createCustomer(token)
token = await refreshToken(token)
}
// use token to send authenticated requests
const { customer: customerData } = await fetch(
`http://localhost:9000/store/customers/me`,
{
credentials: "include",
method: "GET",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${token}`,
},
body: JSON.stringify({
// TODO show form to retrieve email from customer
email: "example@medusajs.com",
}),
}
).then((res) => res.json())
setCustomer(customerData)
setLoading(false)
}
useEffect(() => {
if (!loading) {
return
}
validateCallback()
}, [loading])
```
</CodeTab>
</CodeTabs>
The `validateCallback` function uses the functions added earlier to:
1. Send a request to the Validate Callback API route, which returns an authentication token.
2. 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:
1. Create a customer using the Create Customer API route.
2. Refetch the customer's token after it's created using the Refresh Token API route.
3. Use the token for subsequent authenticated requests.
### Full Code Example for Callback Page
<Details summaryContent="Full Example">
<CodeTabs group="authenticated-request">
<CodeTab label="Fetch API" value="fetch">
```ts
import { decodeToken } from "react-jwt"
// ...
const queryParams = new URLSearchParams(window.location.search)
const code = queryParams.get("code")
const sendCallback = async () => {
const { token } = await fetch(
`http://localhost:9000/auth/customer/google/callback?code=${code}`,
{
credentials: "include",
method: "POST",
}
).then((res) => res.json())
if (!token) {
alert("Authentication Failed")
return
}
return token
}
const createCustomer = async (token: string) => {
await fetch(`http://localhost:9000/store/customers`, {
credentials: "include",
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${token}`,
},
body: JSON.stringify({
// TODO show form to retrieve email from customer
email: "example@medusajs.com",
}),
}).then((res) => res.json())
}
const refreshToken = async (token: string) => {
const result = await fetch(`http://localhost:9000/auth/token/refresh`, {
credentials: "include",
method: "POST",
headers: {
"Authorization": `Bearer ${token}`,
},
}).then((res) => res.json())
return result.token
}
const validateCallback = async () => {
let { token } = await sendCallback()
const shouldCreateCustomer = (decodeToken(token) as { actor_id: string }).actor_id === ""
if (shouldCreateCustomer) {
await createCustomer(token)
token = await refreshToken(token)
}
// use token to send authenticated requests
const { customer } = await fetch(
`http://localhost:9000/store/customers/me`,
{
credentials: "include",
method: "GET",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${token}`,
},
body: JSON.stringify({
// TODO show form to retrieve email from customer
email: "example@medusajs.com",
}),
}
).then((res) => res.json())
}
```
</CodeTab>
<CodeTab label="React" value="react">
```tsx
"use client" // include with Next.js 13+
import { HttpTypes } from "@medusajs/types"
import { useEffect, useMemo, useState } from "react"
import { decodeToken } from "react-jwt"
export default function GoogleCallback() {
const [loading, setLoading] = useState(true)
const [customer, setCustomer] = useState<HttpTypes.StoreCustomer>()
// for other than Next.js
const code = useMemo(() => {
const queryParams = new URLSearchParams(window.location.search)
return queryParams.get("code")
}, [])
const sendCallback = async () => {
const { token } = await fetch(
`http://localhost:9000/auth/customer/google/callback?code=${code}`,
{
credentials: "include",
method: "POST",
}
).then((res) => res.json())
if (!token) {
alert("Authentication Failed")
return
}
return token
}
const createCustomer = async (token: string) => {
await fetch(`http://localhost:9000/store/customers`, {
credentials: "include",
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${token}`,
},
body: JSON.stringify({
// TODO show form to retrieve email from customer
email: "example@medusajs.com",
}),
}).then((res) => res.json())
}
const refreshToken = async (token: string) => {
const result = await fetch(`http://localhost:9000/auth/token/refresh`, {
credentials: "include",
method: "POST",
headers: {
"Authorization": `Bearer ${token}`,
},
}).then((res) => res.json())
return result.token
}
const validateCallback = async () => {
let { token } = await sendCallback()
const shouldCreateCustomer = (decodeToken(token) as { actor_id: string }).actor_id === ""
if (shouldCreateCustomer) {
await createCustomer(token)
token = await refreshToken(token)
}
// use token to send authenticated requests
const { customer: customerData } = await fetch(
`http://localhost:9000/store/customers/me`,
{
credentials: "include",
method: "GET",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${token}`,
},
body: JSON.stringify({
// TODO show form to retrieve email from customer
email: "example@medusajs.com",
}),
}
).then((res) => res.json())
setCustomer(customerData)
setLoading(false)
}
useEffect(() => {
if (!loading) {
return
}
validateCallback()
}, [loading])
return (
<div>
{loading && <span>Loading...</span>}
{customer && <span>Created customer {customer.email} with Google.</span>}
</div>
)
}
```
</CodeTab>
</CodeTabs>
</Details>

View File

@@ -16,7 +16,7 @@ import { medusaIntegrationTestRunner } from "medusa-test-utils"
medusaIntegrationTestRunner({
testSuite: ({ api, getContainer }) => {
// TODO write tests...
}
},
})
```

View File

@@ -22,7 +22,7 @@ moduleIntegrationTestRunner<HelloModuleService>({
resolve: "./modules/hello",
testSuite: ({ service }) => {
// TODO write tests
}
},
})
```

View File

@@ -1,10 +1,10 @@
export const generatedEditDates = {
"app/commerce-modules/auth/auth-providers/emailpass/page.mdx": "2024-07-04T17:26:03+03:00",
"app/commerce-modules/auth/auth-providers/page.mdx": "2024-07-01T10:21:19+03:00",
"app/commerce-modules/auth/authentication-route/page.mdx": "2024-08-30T12:23:50.176Z",
"app/commerce-modules/auth/examples/page.mdx": "2024-07-04T17:26:03+03:00",
"app/commerce-modules/auth/auth-providers/emailpass/page.mdx": "2024-09-05T12:08:19.945Z",
"app/commerce-modules/auth/auth-providers/page.mdx": "2024-09-05T12:15:19.491Z",
"app/commerce-modules/auth/authentication-route/page.mdx": "2024-09-05T12:06:38.155Z",
"app/commerce-modules/auth/examples/page.mdx": "2024-09-05T08:09:32.466Z",
"app/commerce-modules/auth/module-options/page.mdx": "2024-07-04T17:26:03+03:00",
"app/commerce-modules/auth/page.mdx": "2024-08-05T07:24:27+00:00",
"app/commerce-modules/auth/page.mdx": "2024-09-05T08:08:28.782Z",
"app/commerce-modules/cart/_events/_events-table/page.mdx": "2024-07-03T19:27:13+03:00",
"app/commerce-modules/cart/_events/page.mdx": "2024-07-03T19:27:13+03:00",
"app/commerce-modules/cart/concepts/page.mdx": "2024-06-26T07:55:59+00:00",
@@ -222,13 +222,12 @@ export const generatedEditDates = {
"app/upgrade-guides/page.mdx": "2024-07-18T08:57:11+02:00",
"app/usage/page.mdx": "2024-05-13T18:55:11+03:00",
"app/page.mdx": "2024-08-13T08:51:20+02:00",
"app/commerce-modules/auth/auth-providers/_google/page.mdx": "2024-07-04T17:26:03+03:00",
"app/commerce-modules/auth/_events/_events-table/page.mdx": "2024-07-03T19:27:13+03:00",
"app/commerce-modules/auth/auth-flows/page.mdx": "2024-08-30T12:27:07.160Z",
"app/commerce-modules/auth/auth-flows/page.mdx": "2024-09-05T08:50:11.671Z",
"app/commerce-modules/auth/_events/page.mdx": "2024-07-03T19:27:13+03:00",
"app/commerce-modules/auth/auth-identity-and-actor-types/page.mdx": "2024-07-31T17:01:33+03:00",
"app/commerce-modules/auth/auth-identity-and-actor-types/page.mdx": "2024-09-05T08:11:28.936Z",
"app/commerce-modules/api-key/page.mdx": "2024-08-05T07:24:27+00:00",
"app/commerce-modules/auth/create-actor-type/page.mdx": "2024-07-31T17:01:33+03:00",
"app/commerce-modules/auth/create-actor-type/page.mdx": "2024-09-05T09:24:48.099Z",
"app/architectural-modules/page.mdx": "2024-05-28T13:25:03+03:00",
"app/commerce-modules/api-key/relations-to-other-modules/page.mdx": "2024-05-29T11:08:06+00:00",
"app/architectural-modules/workflow-engine/redis/page.mdx": "2024-07-18T13:04:29+02:00",
@@ -915,6 +914,9 @@ export const generatedEditDates = {
"references/types/HttpTypes/interfaces/types.HttpTypes.AdminClaimPreviewResponse/page.mdx": "2024-09-04T00:11:02.637Z",
"references/types/HttpTypes/interfaces/types.HttpTypes.AdminOrderEditPreviewResponse/page.mdx": "2024-09-04T00:11:02.897Z",
"references/types/interfaces/types.BaseClaim/page.mdx": "2024-09-04T00:11:02.485Z",
"app/commerce-modules/auth/auth-providers/github/page.mdx": "2024-09-05T12:13:04.991Z",
"app/commerce-modules/auth/auth-providers/google/page.mdx": "2024-09-05T12:12:59.196Z",
"app/storefront-development/customers/third-party-login/page.mdx": "2024-09-05T11:35:24.269Z",
"references/types/HttpTypes/types/types.HttpTypes.AdminWorkflowRunResponse/page.mdx": "2024-09-05T00:11:17.666Z",
"references/types/HttpTypes/types/types.HttpTypes.BatchResponse/page.mdx": "2024-09-05T00:11:17.182Z",
"references/types/WorkflowsSdkTypes/types/types.WorkflowsSdkTypes.Acknowledgement/page.mdx": "2024-09-05T00:11:18.150Z",

View File

@@ -123,14 +123,18 @@ export const filesMap = [
"filePath": "/www/apps/resources/app/commerce-modules/auth/auth-identity-and-actor-types/page.mdx",
"pathname": "/commerce-modules/auth/auth-identity-and-actor-types"
},
{
"filePath": "/www/apps/resources/app/commerce-modules/auth/auth-providers/_google/page.mdx",
"pathname": "/commerce-modules/auth/auth-providers/_google"
},
{
"filePath": "/www/apps/resources/app/commerce-modules/auth/auth-providers/emailpass/page.mdx",
"pathname": "/commerce-modules/auth/auth-providers/emailpass"
},
{
"filePath": "/www/apps/resources/app/commerce-modules/auth/auth-providers/github/page.mdx",
"pathname": "/commerce-modules/auth/auth-providers/github"
},
{
"filePath": "/www/apps/resources/app/commerce-modules/auth/auth-providers/google/page.mdx",
"pathname": "/commerce-modules/auth/auth-providers/google"
},
{
"filePath": "/www/apps/resources/app/commerce-modules/auth/auth-providers/page.mdx",
"pathname": "/commerce-modules/auth/auth-providers"
@@ -919,6 +923,10 @@ export const filesMap = [
"filePath": "/www/apps/resources/app/storefront-development/customers/retrieve/page.mdx",
"pathname": "/storefront-development/customers/retrieve"
},
{
"filePath": "/www/apps/resources/app/storefront-development/customers/third-party-login/page.mdx",
"pathname": "/storefront-development/customers/third-party-login"
},
{
"filePath": "/www/apps/resources/app/storefront-development/page.mdx",
"pathname": "/storefront-development"

View File

@@ -245,16 +245,7 @@ export const generatedSidebar = [
"type": "link",
"path": "/commerce-modules/auth/auth-providers",
"title": "Auth Providers",
"children": [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/commerce-modules/auth/auth-providers/emailpass",
"title": "Emailpass Auth Provider Module",
"children": []
}
]
"children": []
},
{
"loaded": true,
@@ -290,6 +281,38 @@ export const generatedSidebar = [
}
]
},
{
"loaded": true,
"isPathHref": true,
"type": "sub-category",
"title": "Providers",
"children": [
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/commerce-modules/auth/auth-providers/emailpass",
"title": "Emailpass Provider",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/commerce-modules/auth/auth-providers/google",
"title": "Google Provider",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/commerce-modules/auth/auth-providers/github",
"title": "GitHub Provider",
"children": []
}
]
},
{
"loaded": true,
"isPathHref": true,
@@ -8392,6 +8415,14 @@ export const generatedSidebar = [
"title": "Login Customer",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"type": "link",
"path": "/storefront-development/customers/third-party-login",
"title": "Third-Party (Social) Login",
"children": []
},
{
"loaded": true,
"isPathHref": true,

View File

@@ -120,13 +120,6 @@ export const sidebar = sidebarAttachHrefCommonOptions([
type: "link",
path: "/commerce-modules/auth/auth-providers",
title: "Auth Providers",
children: [
{
type: "link",
path: "/commerce-modules/auth/auth-providers/emailpass",
title: "Emailpass Auth Provider Module",
},
],
},
{
type: "link",
@@ -151,6 +144,27 @@ export const sidebar = sidebarAttachHrefCommonOptions([
},
],
},
{
type: "sub-category",
title: "Providers",
children: [
{
type: "link",
path: "/commerce-modules/auth/auth-providers/emailpass",
title: "Emailpass Provider",
},
{
type: "link",
path: "/commerce-modules/auth/auth-providers/google",
title: "Google Provider",
},
{
type: "link",
path: "/commerce-modules/auth/auth-providers/github",
title: "GitHub Provider",
},
],
},
{
type: "sub-category",
title: "References",
@@ -2065,6 +2079,11 @@ export const sidebar = sidebarAttachHrefCommonOptions([
path: "/storefront-development/customers/login",
title: "Login Customer",
},
{
type: "link",
path: "/storefront-development/customers/third-party-login",
title: "Third-Party (Social) Login",
},
{
type: "link",
path: "/storefront-development/customers/retrieve",

View File

@@ -2,7 +2,15 @@
* @oas [post] /auth/user/{auth_provider}
* operationId: PostActor_typeAuth_provider
* summary: Authenticate User
* description: Authenticate an admin user and receive the JWT token to be used in the header of subsequent requests.
* description: >
* Authenticate a user and receive the JWT token to be used in the header of subsequent requests.
*
*
* When used with a third-party provider, such as Google, the request returns a `location` property. You redirect to the
* specified URL in your frontend to continue authentication with the third-party service.
* externalDocs:
* url: https://docs.medusajs.com/v2/resources/commerce-modules/auth/authentication-route#types-of-authentication-flows
* description: Learn about different authentication flows.
* x-authenticated: false
* parameters:
* - name: auth_provider
@@ -12,10 +20,31 @@
* schema:
* type: string
* example: "emailpass"
* requestBody:
* content:
* application/json:
* schema:
* type: object
* title: input
* description: The input data necessary for authentication. For example, for email-pass authentication, pass `email` and `password` properties.
* x-codeSamples:
* - lang: Shell
* label: cURL
* source: curl -X POST '{backend_url}/auth/user/{auth_provider}'
* label: EmailPass Provider
* source: |-
* curl -X POST '{backend_url}/auth/user/emailpass' \
* -H 'Content-Type: application/json' \
* --data-raw '{
* "email": "admin@medusa-test.com",
* "password": "supersecret"
* }'
* - lang: Shell
* label: Google Provider
* source: |-
* curl -X POST '{backend_url}/auth/user/google'
* - lang: Shell
* label: GitHub Provider
* source: |-
* curl -X POST '{backend_url}/auth/user/github'
* tags:
* - Auth
* responses:
@@ -24,7 +53,9 @@
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/AuthResponse"
* oneOf:
* - $ref: "#/components/schemas/AuthResponse"
* - $ref: "#/components/schemas/AuthCallbackResponse"
* "400":
* $ref: "#/components/responses/400_error"
* "401":

View File

@@ -2,8 +2,18 @@
* @oas [post] /auth/user/{auth_provider}/callback
* operationId: PostActor_typeAuth_providerCallback
* summary: Validate Authentication Callback
* description: Third-party authentication providers, such as Google, require an API route to call once authentication with the third-party provider is finished.
* This API route validates callback for admin users logged-in with third-party providers.
* description: >
* This API route is used by your dashboard or frontend application when a third-party provider redirects to it after authentication.
*
*
* It validates the authentication with the third-party provider and, if successful, returns an authentication token.
*
*
* You can decode the JWT token using libraries like [react-jwt](https://www.npmjs.com/package/react-jwt) in the frontend. If the decoded data doesn't
* have an `actor_id` property, then you must create a user, typically using the Accept Invite route passing the token in the request's Authorization header.
* externalDocs:
* url: https://docs.medusajs.com/v2/resources/commerce-modules/auth/authentication-route#2-third-party-service-authenticate-flow
* description: Learn about third-party authentication flow.
* x-authenticated: false
* parameters:
* - name: auth_provider
@@ -15,8 +25,11 @@
* example: "google"
* x-codeSamples:
* - lang: Shell
* label: cURL
* source: curl -X POST '{backend_url}/auth/user/{auth_provider}/callback'
* label: Google Provider
* source: curl -X POST '{backend_url}/auth/user/google/callback?code=123'
* - lang: Shell
* label: GitHub Provider
* source: curl -X POST '{backend_url}/auth/user/github/callback?code=123'
* tags:
* - Auth
* responses:

View File

@@ -2,8 +2,10 @@
* @oas [post] /auth/user/{auth_provider}/register
* operationId: PostActor_typeAuth_provider_register
* summary: Retrieve Registration JWT Token
* description: A registration JWT token is used in the header of requests that create a user, such as the accept invitation request.
* This API route retrieves the JWT token of a user that hasn't been registered yet.
* description: This API route retrieves a registration JWT token of a user that hasn't been registered yet. The token is used in the header of requests that create a user, such as the Accept Invite API route.
* externalDocs:
* url: https://docs.medusajs.com/v2/resources/commerce-modules/auth/authentication-route#1-basic-authentication-flow
* description: Learn about the basic authentication flow.
* x-authenticated: false
* parameters:
* - name: auth_provider
@@ -13,10 +15,23 @@
* schema:
* type: string
* example: "emailpass"
* requestBody:
* content:
* application/json:
* schema:
* type: object
* title: input
* description: The input data necessary for authentication. For example, for email-pass authentication, pass `email` and `password` properties.
* x-codeSamples:
* - lang: Shell
* label: cURL
* source: curl -X POST '{backend_url}/auth/user/{auth_provider}/register'
* source: |-
* curl -X POST '{backend_url}/auth/user/emailpass/register' \
* -H 'Content-Type: application/json' \
* --data-raw '{
* "email": "admin@medusa-test.com",
* "password": "supersecret"
* }'
* tags:
* - Auth
* responses:

View File

@@ -0,0 +1,38 @@
/**
* @oas [post] /auth/token/refresh
* operationId: PostAdminAuthTokenRefresh
* summary: Refresh Authentication Token
* description: Refresh the authentication token of a user. This is useful after authenticating a user with a third-party service to ensure the token holds the new user's details, or when you don't want users to re-login every day.
* externalDocs:
* url: https://docs.medusajs.com/v2/resources/commerce-modules/auth/authentication-route#2-third-party-service-authenticate-flow
* description: Learn about third-party authentication flow.
* x-authenticated: true
* x-codeSamples:
* - lang: Shell
* label: cURL
* source: curl -X POST '{backend_url}/auth/token/refresh' \
* -H 'Authorization: Bearer {token}'
* tags:
* - Auth
* responses:
* "200":
* description: OK
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/AuthResponse"
* "400":
* $ref: "#/components/responses/400_error"
* "401":
* $ref: "#/components/responses/unauthorized"
* "404":
* $ref: "#/components/responses/not_found_error"
* "409":
* $ref: "#/components/responses/invalid_state_error"
* "422":
* $ref: "#/components/responses/invalid_request_error"
* "500":
* $ref: "#/components/responses/500_error"
*
*/

View File

@@ -2,7 +2,15 @@
* @oas [post] /auth/customer/{auth_provider}
* operationId: PostActor_typeAuth_provider
* summary: Authenticate Customer
* description: Authenticate a customer and receive the JWT token to be used in the header of subsequent requests.
* description: >
* Authenticate a customer and receive the JWT token to be used in the header of subsequent requests.
*
*
* When used with a third-party provider, such as Google, the request returns a `location` property. You redirect to the
* specified URL in your storefront to continue authentication with the third-party service.
* externalDocs:
* url: https://docs.medusajs.com/v2/resources/commerce-modules/auth/authentication-route#types-of-authentication-flows
* description: Learn about different authentication flows.
* x-authenticated: false
* parameters:
* - name: auth_provider
@@ -12,10 +20,31 @@
* schema:
* type: string
* example: "emailpass"
* requestBody:
* content:
* application/json:
* schema:
* type: object
* title: input
* description: The input data necessary for authentication. For example, for email-pass authentication, pass `email` and `password` properties.
* x-codeSamples:
* - lang: Shell
* label: cURL
* source: curl -X POST '{backend_url}/auth/customer/{auth_provider}'
* label: EmailPass Provider
* source: |-
* curl -X POST '{backend_url}/auth/customer/emailpass' \
* -H 'Content-Type: application/json' \
* --data-raw '{
* "email": "customer@gmail.com",
* "password": "supersecret"
* }'
* - lang: Shell
* label: Google Provider
* source: |-
* curl -X POST '{backend_url}/auth/customer/google'
* - lang: Shell
* label: GitHub Provider
* source: |-
* curl -X POST '{backend_url}/auth/customer/github'
* tags:
* - Auth
* responses:
@@ -24,7 +53,9 @@
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/AuthResponse"
* oneOf:
* - $ref: "#/components/schemas/AuthResponse"
* - $ref: "#/components/schemas/AuthCallbackResponse"
* "400":
* $ref: "#/components/responses/400_error"
* "401":

View File

@@ -2,8 +2,18 @@
* @oas [post] /auth/customer/{auth_provider}/callback
* operationId: PostActor_typeAuth_providerCallback
* summary: Validate Authentication Callback
* description: Third-party authentication providers, such as Google, require an API route to call once authentication with the third-party provider is finished.
* This API route validates callback for customers logged-in with third-party providers.
* description: >
* This API route is used by your storefront or frontend application when a third-party provider redirects to it after authentication.
*
*
* It validates the authentication with the third-party provider and, if successful, returns an authentication token.
*
*
* You can decode the JWT token using libraries like [react-jwt](https://www.npmjs.com/package/react-jwt) in the storefront. If the decoded data doesn't
* have an `actor_id` property, then you must register the customer using the Create Customer API route passing the token in the request's Authorization header.
* externalDocs:
* url: https://docs.medusajs.com/v2/resources/commerce-modules/auth/authentication-route#2-third-party-service-authenticate-flow
* description: Learn about third-party authentication flow.
* x-authenticated: false
* parameters:
* - name: auth_provider
@@ -15,8 +25,11 @@
* example: "google"
* x-codeSamples:
* - lang: Shell
* label: cURL
* source: curl -X POST '{backend_url}/auth/customer/{auth_provider}/callback'
* label: Google Provider
* source: curl -X POST '{backend_url}/auth/customer/google/callback?code=123'
* - lang: Shell
* label: GitHub Provider
* source: curl -X POST '{backend_url}/auth/customer/github/callback?code=123'
* tags:
* - Auth
* responses:

View File

@@ -2,8 +2,10 @@
* @oas [post] /auth/customer/{auth_provider}/register
* operationId: PostActor_typeAuth_provider_register
* summary: Retrieve Registration JWT Token
* description: A registration JWT token is used in the header of requests that create a customer.
* This API route retrieves the JWT token of a customer that hasn't been registered yet.
* description: This API route retrieves a registration JWT token of a customer that hasn't been registered yet. The token is used in the header of requests that create a customer.
* externalDocs:
* url: https://docs.medusajs.com/v2/resources/commerce-modules/auth/authentication-route#1-basic-authentication-flow
* description: Learn about the basic authentication flow.
* x-authenticated: false
* parameters:
* - name: auth_provider
@@ -13,10 +15,23 @@
* schema:
* type: string
* example: "emailpass"
* requestBody:
* content:
* application/json:
* schema:
* type: object
* title: input
* description: The input data necessary for authentication. For example, for email-pass authentication, pass `email` and `password` properties.
* x-codeSamples:
* - lang: Shell
* label: cURL
* source: curl -X POST '{backend_url}/auth/customer/{auth_provider}/register'
* source: |-
* curl -X POST '{backend_url}/auth/customer/emailpass/register' \
* -H 'Content-Type: application/json' \
* --data-raw '{
* "email": "customer@gmail.com",
* "password": "supersecret"
* }'
* tags:
* - Auth
* responses:

View File

@@ -0,0 +1,38 @@
/**
* @oas [post] /auth/token/refresh
* operationId: PostAdminAuthTokenRefresh
* summary: Refresh Authentication Token
* description: Refresh the authentication token of a customer. This is useful after authenticating a customer with a third-party service to ensure the token holds the new user's details, or when you don't want customers to re-login every day.
* externalDocs:
* url: https://docs.medusajs.com/v2/resources/commerce-modules/auth/authentication-route#2-third-party-service-authenticate-flow
* description: Learn about third-party authentication flow.
* x-authenticated: true
* x-codeSamples:
* - lang: Shell
* label: cURL
* source: curl -X POST '{backend_url}/auth/token/refresh' \
* -H 'Authorization: Bearer {token}'
* tags:
* - Auth
* responses:
* "200":
* description: OK
* content:
* application/json:
* schema:
* $ref: "#/components/schemas/AuthResponse"
* "400":
* $ref: "#/components/responses/400_error"
* "401":
* $ref: "#/components/responses/unauthorized"
* "404":
* $ref: "#/components/responses/not_found_error"
* "409":
* $ref: "#/components/responses/invalid_state_error"
* "422":
* $ref: "#/components/responses/invalid_request_error"
* "500":
* $ref: "#/components/responses/500_error"
*
*/

View File

@@ -0,0 +1,14 @@
/**
* @schema AuthCallbackResponse
* type: object
* description: The authentication's details.
* x-schemaName: AuthCallbackResponse
* required:
* - location
* properties:
* token:
* type: string
* title: location
* description: The location to redirect the user to for further authentication with the third-party provider.
*/

View File

@@ -22,13 +22,14 @@ const OAS_PREFIX_REGEX = /@oas \[(?<method>(get|post|delete))\] (?<path>.+)/
const ignoreSchemas = [
"AuthResponse",
"AuthCallbackResponse",
"AuthAdminSessionResponse",
"AuthStoreSessionResponse",
]
const ignoreTags = {
admin: ["Auth"],
store: ["Auth"]
store: ["Auth"],
}
export default async function () {
@@ -229,8 +230,8 @@ export default async function () {
}
const lengthBefore = parsedBaseYaml.tags?.length || 0
parsedBaseYaml.tags = parsedBaseYaml.tags?.filter((tag) =>
areaTags.has(tag.name) || ignoreTags[area].includes(tag.name)
parsedBaseYaml.tags = parsedBaseYaml.tags?.filter(
(tag) => areaTags.has(tag.name) || ignoreTags[area].includes(tag.name)
)
if (lengthBefore !== (parsedBaseYaml.tags?.length || 0)) {