diff --git a/www/apps/resources/app/architectural-modules/notification/sendgrid/page.mdx b/www/apps/resources/app/architectural-modules/notification/sendgrid/page.mdx index 0c1b77a1171b7..ead7eb9234533 100644 --- a/www/apps/resources/app/architectural-modules/notification/sendgrid/page.mdx +++ b/www/apps/resources/app/architectural-modules/notification/sendgrid/page.mdx @@ -168,7 +168,7 @@ export default async function productCreateHandler({ disposition: "attachment or inline attachment", id: "id", // only needed for inline attachment }, - ] + ], }) } diff --git a/www/apps/resources/app/commerce-modules/auth/auth-flows/page.mdx b/www/apps/resources/app/commerce-modules/auth/auth-flows/page.mdx index 5762321e03a5f..ba1820b584a21 100644 --- a/www/apps/resources/app/commerce-modules/auth/auth-flows/page.mdx +++ b/www/apps/resources/app/commerce-modules/auth/auth-flows/page.mdx @@ -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. -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`. @@ -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 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 - { - // ... - } - ) -``` +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). -If the authentication is successful, the `validateCallback` method returns the same data as the basic authentication: +The method calls the specified provider’s `validateCallback` method passing it the authentication details it received in the second parameter: ```ts -data = { - success: true, - authIdentity: { - // ... - }, +const { success, authIdentity } = await authModuleService.validateCallback( + "google", + // passed to auth provider + { + // request data, such as + url, + headers, + query, + body, + protocol, + } +) + +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) diff --git a/www/apps/resources/app/commerce-modules/auth/auth-identity-and-actor-types/page.mdx b/www/apps/resources/app/commerce-modules/auth/auth-identity-and-actor-types/page.mdx index 96e7a49a9175a..40c8d6f0251a0 100644 --- a/www/apps/resources/app/commerce-modules/auth/auth-identity-and-actor-types/page.mdx +++ b/www/apps/resources/app/commerce-modules/auth/auth-identity-and-actor-types/page.mdx @@ -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`. --- diff --git a/www/apps/resources/app/commerce-modules/auth/auth-providers/_google/page.mdx b/www/apps/resources/app/commerce-modules/auth/auth-providers/_google/page.mdx deleted file mode 100644 index fbc166db6eaa4..0000000000000 --- a/www/apps/resources/app/commerce-modules/auth/auth-providers/_google/page.mdx +++ /dev/null @@ -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 - - - -- [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`. - - - -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= -GOOGLE_CLIENT_SECRET= -GOOGLE_CALLBACK_URL= -GOOGLE_SUCCESS_REDIRECT_URL= -``` - -### Module Options - - - - - Configuration - Description - Required - Default - - - - - - - `clientID` - - - - - A string indicating the [Google API Client ID](https://developers.google.com/identity/oauth2/web/guides/get-google-api-clientid). - - - - - Yes - - - - - \- - - - - - - - `clientSecret` - - - - - A string indicating the [Google Client Secret](https://support.google.com/cloud/answer/6158849?hl=en#zippy=%2Cstep-create-a-new-client-secret). - - - - - Yes - - - - - \- - - - - - - - `callbackURL` - - - - - 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`. - - - - - Yes - - - - - \- - - - - - - - `successRedirectUrl` - - - - - 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. - - - - - No - - - - - \- - - - - -
- -{/* TODO add how to implement authentication flow with google */} \ No newline at end of file diff --git a/www/apps/resources/app/commerce-modules/auth/auth-providers/emailpass/page.mdx b/www/apps/resources/app/commerce-modules/auth/auth-providers/emailpass/page.mdx index a62c363cbccea..eac100af4ef9e 100644 --- a/www/apps/resources/app/commerce-modules/auth/auth-providers/emailpass/page.mdx +++ b/www/apps/resources/app/commerce-modules/auth/auth-providers/emailpass/page.mdx @@ -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", diff --git a/www/apps/resources/app/commerce-modules/auth/auth-providers/github/page.mdx b/www/apps/resources/app/commerce-modules/auth/auth-providers/github/page.mdx new file mode 100644 index 0000000000000..8e49749e1b86c --- /dev/null +++ b/www/apps/resources/app/commerce-modules/auth/auth-providers/github/page.mdx @@ -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. + + + +Learn about the authentication flow in [this guide](../../authentication-route/page.mdx). + + + +--- + +## Install the Github Auth Module Provider + + + +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= +GITHUB_CLIENT_SECRET= +GITHUB_CALLBACK_URL= +``` + +### Module Options + + + + + Configuration + Description + Required + + + + + + + `clientId` + + + + + A string indicating the client ID of your GitHub app. + + + + + Yes + + + + + + + `clientSecret` + + + + + A string indicating the client secret of your GitHub app. + + + + + Yes + + + + + + + `callbackUrl` + + + + + 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. + + + + + Yes + + + + +
+ +--- + +## Examples + +- [How to implement third-party / social login in the storefront.](../../../../storefront-development/customers/third-party-login/page.mdx). diff --git a/www/apps/resources/app/commerce-modules/auth/auth-providers/google/page.mdx b/www/apps/resources/app/commerce-modules/auth/auth-providers/google/page.mdx new file mode 100644 index 0000000000000..80fb147bbeef8 --- /dev/null +++ b/www/apps/resources/app/commerce-modules/auth/auth-providers/google/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. + + + +Learn about the authentication flow in [this guide](../../authentication-route/page.mdx). + + + +--- + +## Install the Google Auth Module Provider + + + +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= +GOOGLE_CLIENT_SECRET= +GOOGLE_CALLBACK_URL= +``` + +### Module Options + + + + + Configuration + Description + Required + + + + + + + `clientId` + + + + + A string indicating the [Google API Client ID](https://developers.google.com/identity/oauth2/web/guides/get-google-api-clientid). + + + + + Yes + + + + + + + `clientSecret` + + + + + A string indicating the [Google Client Secret](https://support.google.com/cloud/answer/6158849?hl=en#zippy=%2Cstep-create-a-new-client-secret). + + + + + Yes + + + + + + + `callbackUrl` + + + + + 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. + + + + + Yes + + + + +
+ +--- + +## Examples + +- [How to implement Google social login in the storefront.](../../../../storefront-development/customers/third-party-login/page.mdx). diff --git a/www/apps/resources/app/commerce-modules/auth/auth-providers/page.mdx b/www/apps/resources/app/commerce-modules/auth/auth-providers/page.mdx index 7e144c435071e..ebde6f8c41eef 100644 --- a/www/apps/resources/app/commerce-modules/auth/auth-providers/page.mdx +++ b/www/apps/resources/app/commerce-modules/auth/auth-providers/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. - - -Support for the Google Auth Module Provider is coming soon. +### Auth Providers List - + --- diff --git a/www/apps/resources/app/commerce-modules/auth/authentication-route/page.mdx b/www/apps/resources/app/commerce-modules/auth/authentication-route/page.mdx index 288995623e484..590f0310f90db 100644 --- a/www/apps/resources/app/commerce-modules/auth/authentication-route/page.mdx +++ b/www/apps/resources/app/commerce-modules/auth/authentication-route/page.mdx @@ -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: + + +[How to register customer in storefront using basic authentication flow](../../../storefront-development/customers/register/page.mdx). + + + +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. Registering the user with the [Register Route](#register-route). -2. Authenticating the user with the [Auth Route](#auth-route). +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. + + +[How to authenticate customer with a third-party provider in the storefront.](../../../storefront-development/customers/third-party-login/page.mdx). + + + It requires the following steps: +![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. 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. +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" + // ... +}' +``` + 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 } ``` - - -[How to register Customers using the authentication route](../../../storefront-development/customers/register/page.mdx). - - +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. + [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 +``` -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. -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": "..." } -``` \ No newline at end of file +``` + +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. \ No newline at end of file diff --git a/www/apps/resources/app/commerce-modules/auth/create-actor-type/page.mdx b/www/apps/resources/app/commerce-modules/auth/create-actor-type/page.mdx index 5ad2ff5b50ea8..770338bd918cb 100644 --- a/www/apps/resources/app/commerce-modules/auth/create-actor-type/page.mdx +++ b/www/apps/resources/app/commerce-modules/auth/create-actor-type/page.mdx @@ -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", diff --git a/www/apps/resources/app/commerce-modules/auth/examples/page.mdx b/www/apps/resources/app/commerce-modules/auth/examples/page.mdx index b621197792900..f039a13b9ebbf 100644 --- a/www/apps/resources/app/commerce-modules/auth/examples/page.mdx +++ b/www/apps/resources/app/commerce-modules/auth/examples/page.mdx @@ -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") diff --git a/www/apps/resources/app/commerce-modules/auth/page.mdx b/www/apps/resources/app/commerce-modules/auth/page.mdx index 56e0a4637ed90..01f3833e4fcc7 100644 --- a/www/apps/resources/app/commerce-modules/auth/page.mdx +++ b/www/apps/resources/app/commerce-modules/auth/page.mdx @@ -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 diff --git a/www/apps/resources/app/storefront-development/customers/third-party-login/page.mdx b/www/apps/resources/app/storefront-development/customers/third-party-login/page.mdx new file mode 100644 index 0000000000000..2abd30a742c5d --- /dev/null +++ b/www/apps/resources/app/storefront-development/customers/third-party-login/page.mdx @@ -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) + +
+ +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. + +
+ +You'll implement the flow in this guide using Google as an example. + + + +## Step 1: Authenticate Customer in Medusa + +When the customer clicks on a "Login with Google" button, send a request to the [Authenticate Customer API route](!api!/store#auth_postactor_typeauth_provider). + +For example: + + + + +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()) +} +``` + + + + +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 ( +
+ +
+ ) +} +``` + +
+
+ +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. + + + +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. + + + +--- + +## 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: + + + + +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... +``` + + + + +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() + // 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 ( +
+ {loading && Loading...} + {customer && Created customer {customer.email} with Google.} +
+ ) +} +``` + +
+
+ +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: + + + + +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()) +} +``` + + + + +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]) +``` + + + + +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 + +
+ + + + +```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()) +} +``` + + + + +```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() + // 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 ( +
+ {loading && Loading...} + {customer && Created customer {customer.email} with Google.} +
+ ) +} +``` + +
+
+ +
diff --git a/www/apps/resources/app/test-tools-reference/medusaIntegrationTestRunner/page.mdx b/www/apps/resources/app/test-tools-reference/medusaIntegrationTestRunner/page.mdx index d074f76be6a07..84e0d6dbf67b9 100644 --- a/www/apps/resources/app/test-tools-reference/medusaIntegrationTestRunner/page.mdx +++ b/www/apps/resources/app/test-tools-reference/medusaIntegrationTestRunner/page.mdx @@ -16,7 +16,7 @@ import { medusaIntegrationTestRunner } from "medusa-test-utils" medusaIntegrationTestRunner({ testSuite: ({ api, getContainer }) => { // TODO write tests... - } + }, }) ``` diff --git a/www/apps/resources/app/test-tools-reference/moduleIntegrationTestRunner/page.mdx b/www/apps/resources/app/test-tools-reference/moduleIntegrationTestRunner/page.mdx index cd3afb3d06d56..739c4d5f2dbde 100644 --- a/www/apps/resources/app/test-tools-reference/moduleIntegrationTestRunner/page.mdx +++ b/www/apps/resources/app/test-tools-reference/moduleIntegrationTestRunner/page.mdx @@ -22,7 +22,7 @@ moduleIntegrationTestRunner({ resolve: "./modules/hello", testSuite: ({ service }) => { // TODO write tests - } + }, }) ``` diff --git a/www/apps/resources/generated/edit-dates.mjs b/www/apps/resources/generated/edit-dates.mjs index 5def5de5015c1..64c2b363f8874 100644 --- a/www/apps/resources/generated/edit-dates.mjs +++ b/www/apps/resources/generated/edit-dates.mjs @@ -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", diff --git a/www/apps/resources/generated/files-map.mjs b/www/apps/resources/generated/files-map.mjs index c307683e823ef..02948609467e1 100644 --- a/www/apps/resources/generated/files-map.mjs +++ b/www/apps/resources/generated/files-map.mjs @@ -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" diff --git a/www/apps/resources/generated/sidebar.mjs b/www/apps/resources/generated/sidebar.mjs index 759cbd0f23d82..49c10175591d7 100644 --- a/www/apps/resources/generated/sidebar.mjs +++ b/www/apps/resources/generated/sidebar.mjs @@ -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, @@ -8328,6 +8351,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, diff --git a/www/apps/resources/sidebar.mjs b/www/apps/resources/sidebar.mjs index dd5ed53d1158d..2636746127cb4 100644 --- a/www/apps/resources/sidebar.mjs +++ b/www/apps/resources/sidebar.mjs @@ -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", diff --git a/www/utils/generated/oas-output/operations/admin/post_auth_[actor_type]_[auth_provider].ts b/www/utils/generated/oas-output/operations/admin/post_auth_[actor_type]_[auth_provider].ts index ec41bd4bba538..26b88c19ba7ec 100644 --- a/www/utils/generated/oas-output/operations/admin/post_auth_[actor_type]_[auth_provider].ts +++ b/www/utils/generated/oas-output/operations/admin/post_auth_[actor_type]_[auth_provider].ts @@ -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": diff --git a/www/utils/generated/oas-output/operations/admin/post_auth_[actor_type]_[auth_provider]_callback.ts b/www/utils/generated/oas-output/operations/admin/post_auth_[actor_type]_[auth_provider]_callback.ts index 3938e90b99be1..7ddf9ecb3dfaf 100644 --- a/www/utils/generated/oas-output/operations/admin/post_auth_[actor_type]_[auth_provider]_callback.ts +++ b/www/utils/generated/oas-output/operations/admin/post_auth_[actor_type]_[auth_provider]_callback.ts @@ -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: diff --git a/www/utils/generated/oas-output/operations/admin/post_auth_[actor_type]_[auth_provider]_register.ts b/www/utils/generated/oas-output/operations/admin/post_auth_[actor_type]_[auth_provider]_register.ts index 144005a82f6ac..9e215f122013a 100644 --- a/www/utils/generated/oas-output/operations/admin/post_auth_[actor_type]_[auth_provider]_register.ts +++ b/www/utils/generated/oas-output/operations/admin/post_auth_[actor_type]_[auth_provider]_register.ts @@ -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: diff --git a/www/utils/generated/oas-output/operations/admin/post_auth_token_refresh.ts b/www/utils/generated/oas-output/operations/admin/post_auth_token_refresh.ts new file mode 100644 index 0000000000000..85050ee5c1208 --- /dev/null +++ b/www/utils/generated/oas-output/operations/admin/post_auth_token_refresh.ts @@ -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" + * +*/ + diff --git a/www/utils/generated/oas-output/operations/store/post_auth_[actor_type]_[auth_provider].ts b/www/utils/generated/oas-output/operations/store/post_auth_[actor_type]_[auth_provider].ts index a9729c7869fd7..af4159ef25703 100644 --- a/www/utils/generated/oas-output/operations/store/post_auth_[actor_type]_[auth_provider].ts +++ b/www/utils/generated/oas-output/operations/store/post_auth_[actor_type]_[auth_provider].ts @@ -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": diff --git a/www/utils/generated/oas-output/operations/store/post_auth_[actor_type]_[auth_provider]_callback.ts b/www/utils/generated/oas-output/operations/store/post_auth_[actor_type]_[auth_provider]_callback.ts index d6e3881329da7..eceb646de1c1f 100644 --- a/www/utils/generated/oas-output/operations/store/post_auth_[actor_type]_[auth_provider]_callback.ts +++ b/www/utils/generated/oas-output/operations/store/post_auth_[actor_type]_[auth_provider]_callback.ts @@ -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: diff --git a/www/utils/generated/oas-output/operations/store/post_auth_[actor_type]_[auth_provider]_register.ts b/www/utils/generated/oas-output/operations/store/post_auth_[actor_type]_[auth_provider]_register.ts index 9681b084b1be9..d94c59d5fef2c 100644 --- a/www/utils/generated/oas-output/operations/store/post_auth_[actor_type]_[auth_provider]_register.ts +++ b/www/utils/generated/oas-output/operations/store/post_auth_[actor_type]_[auth_provider]_register.ts @@ -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: diff --git a/www/utils/generated/oas-output/operations/store/post_auth_token_refresh.ts b/www/utils/generated/oas-output/operations/store/post_auth_token_refresh.ts new file mode 100644 index 0000000000000..7e05a56a99c4d --- /dev/null +++ b/www/utils/generated/oas-output/operations/store/post_auth_token_refresh.ts @@ -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" + * +*/ + diff --git a/www/utils/generated/oas-output/schemas/AuthCallbackResponse.ts b/www/utils/generated/oas-output/schemas/AuthCallbackResponse.ts new file mode 100644 index 0000000000000..7fc135dcea802 --- /dev/null +++ b/www/utils/generated/oas-output/schemas/AuthCallbackResponse.ts @@ -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. +*/ + diff --git a/www/utils/packages/docs-generator/src/commands/clean-oas.ts b/www/utils/packages/docs-generator/src/commands/clean-oas.ts index 1854614fb24ad..e5ed643b81c56 100644 --- a/www/utils/packages/docs-generator/src/commands/clean-oas.ts +++ b/www/utils/packages/docs-generator/src/commands/clean-oas.ts @@ -22,13 +22,14 @@ const OAS_PREFIX_REGEX = /@oas \[(?(get|post|delete))\] (?.+)/ 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)) {