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:
@@ -168,7 +168,7 @@ export default async function productCreateHandler({
|
||||
disposition: "attachment or inline attachment",
|
||||
id: "id", // only needed for inline attachment
|
||||
},
|
||||
]
|
||||
],
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||

|
||||
|
||||
@@ -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 provider’s `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 provider’s `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.
|
||||
|
||||

|
||||
|
||||
@@ -8,9 +8,9 @@ In this document, you’ll 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 user’s authentication in future requests.
|
||||
When a user is registered, a record of `AuthIdentity` is created. This record is used to validate the user’s 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 Module’s `Customer` data model. Similarly, the `user` belongs to the User Module’s `User` data model.
|
||||
For example, the `customer` actor type belongs to the Customer Module’s `Customer` data model. Similarly, the `user` actor type belongs to the User Module’s `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`.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1,186 +0,0 @@
|
||||
import { Table } from "docs-ui"
|
||||
|
||||
export const metadata = {
|
||||
title: `Google Auth Module Provider`,
|
||||
}
|
||||
|
||||
# {metadata.title}
|
||||
|
||||
In this document, you’ll 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 */}
|
||||
@@ -8,8 +8,6 @@ export const metadata = {
|
||||
|
||||
In this document, you’ll 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",
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
import { Table, Prerequisites } from "docs-ui"
|
||||
|
||||
export const metadata = {
|
||||
title: `GitHub Auth Module Provider`,
|
||||
}
|
||||
|
||||
# {metadata.title}
|
||||
|
||||
In this document, you’ll 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).
|
||||
@@ -0,0 +1,152 @@
|
||||
import { Table, Prerequisites } from "docs-ui"
|
||||
|
||||
export const metadata = {
|
||||
title: `Google Auth Module Provider`,
|
||||
}
|
||||
|
||||
# {metadata.title}
|
||||
|
||||
In this document, you’ll 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).
|
||||
@@ -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"
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||

|
||||
|
||||
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.
|
||||

|
||||
|
||||
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.
|
||||
@@ -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",
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||

|
||||
|
||||
<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>
|
||||
@@ -16,7 +16,7 @@ import { medusaIntegrationTestRunner } from "medusa-test-utils"
|
||||
medusaIntegrationTestRunner({
|
||||
testSuite: ({ api, getContainer }) => {
|
||||
// TODO write tests...
|
||||
}
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ moduleIntegrationTestRunner<HelloModuleService>({
|
||||
resolve: "./modules/hello",
|
||||
testSuite: ({ service }) => {
|
||||
// TODO write tests
|
||||
}
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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":
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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"
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -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":
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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"
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
Reference in New Issue
Block a user