How to Create an Auth Provider Module

In this document, you’ll learn how to create an auth provider module and the methods you must implement in its main service.


1. Create Module Directory#

Start by creating a new directory for your module. For example, src/modules/my-auth.


2. Create the Auth Provider Service#

Create the file src/modules/my-auth/service.ts that holds the module's main service. It must extend the AbstractAuthModuleProvider class imported from @medusajs/framework/utils:

src/modules/my-auth/service.ts
1import { AbstractAuthModuleProvider } from "@medusajs/framework/utils"2
3class MyAuthProviderService extends AbstractAuthModuleProvider {4  // TODO implement methods5}6
7export default MyAuthProviderService

constructor#

The constructor allows you to access resources from the module's container using the first parameter, and the module's options using the second parameter.

If you're creating a client or establishing a connection with a third-party service, do it in the constructor.

Example

Code
1import { AbstractAuthModuleProvider } from "@medusajs/framework/utils"2import { Logger } from "@medusajs/framework/types"3
4type InjectedDependencies = {5  logger: Logger6}7
8type Options = {9  apiKey: string10}11
12class MyAuthProviderService extends AbstractAuthModuleProvider {13  static identifier = "my-auth"14  protected logger_: Logger15  protected options_: Options16  // assuming you're initializing a client17  protected client18
19  constructor (20    { logger }: InjectedDependencies,21    options: Options22  ) {23    super(...arguments)24
25    this.logger_ = logger26    this.options_ = options27
28    // assuming you're initializing a client29    this.client = new Client(options)30  }31
32  // ...33}34
35export default MyAuthProviderService

constructor#

validateOptions#

This method validates the options of the provider set in medusa-config.ts. Implementing this method is optional. It's useful if your provider requires custom validation.

If the options aren't valid, throw an error.

Example

Code
1class MyAuthProviderService extends AbstractAuthModuleProvider {2  static validateOptions(options: Record<any, any>) {3    if (!options.apiKey) {4      throw new MedusaError(5        MedusaError.Types.INVALID_DATA,6        "API key is required in the provider's options."7      )8    }9  }10  // ...11}

Parameters

optionsRecord<any, any>
The provider's options.

Returns

voidvoid
This method validates the options of the provider set in medusa-config.ts. Implementing this method is optional. It's useful if your provider requires custom validation. If the options aren't valid, throw an error.

authenticate#

This method authenticates the user.

The authentication happens either by directly authenticating or returning a redirect URL to continue the authentication with a third party provider.

Related Read: Learn about the different authentication flows in Medusa.

Example

For example, if your authentication provider doesn't require validating a callback:

Code
1import {2  AuthIdentityProviderService,3  AuthenticationInput,4  AuthenticationResponse5} from "@medusajs/framework/types"6// ...7
8class MyAuthProviderService extends AbstractAuthModuleProvider {9  // ...10  async authenticate(11    data: AuthenticationInput,12    authIdentityProviderService: AuthIdentityProviderService13  ): Promise<AuthenticationResponse> {14    const isAuthenticated = false15    // TODO perform custom logic to authenticate the user16    // for example, verifying a password17
18    if (!isAuthenticated) {19      // if the authentication didn't succeed, return20      // an object of the following format21      return {22        success: false,23        error: "Incorrect credentials"24      }25    }26
27    // authentication is successful, retrieve the identity28    const authIdentity = await authIdentityProviderService.retrieve({29      entity_id: data.body.email, // email or some ID30      provider: this.provider31    })32
33    return {34      success: true,35      authIdentity36    }37  }38}

If your authentication provider requires validating callback:

Code
1import {2  AuthIdentityProviderService,3  AuthenticationInput,4  AuthenticationResponse5} from "@medusajs/framework/types"6// ...7
8class MyAuthProviderService extends AbstractAuthModuleProvider {9  // ...10  async authenticate(11    data: AuthenticationInput,12    authIdentityProviderService: AuthIdentityProviderService13  ): Promise<AuthenticationResponse> {14    const isAuthenticated = false15    // TODO perform custom logic to authenticate the user16    // ...17
18    if (!isAuthenticated) {19      // if the authentication didn't succeed, return20      // an object of the following format21      return {22        success: false,23        error: "Incorrect credentials"24      }25    }26
27    return {28      success: true,29      location: "some-url.com"30    }31  }32}

Parameters

The details of the authentication request.
authIdentityProviderServiceAuthIdentityProviderService
The service used to retrieve or create an auth identity. It has two methods: create to create an auth identity, and retrieve to retrieve an auth identity. When you authenticate the user, you can create an auth identity using this service.

Returns

PromisePromise<AuthenticationResponse>
The authentication response.

register#

This method receives credentails to create a new auth identity. It performs any validation necessary before creating the auth identity.

For example, in the emailpass provider, this method ensures that the provided email doesn't exist before creating the auth identity.

This method is only used in a basic authentication flow, such as when using an email and password to register and authenticate a user.

Related Read: Learn about the different authentication flows in Medusa.

Example

Code
1import {2  AuthIdentityProviderService,3  AuthenticationInput,4  AuthenticationResponse5} from "@medusajs/framework/types"6import { MedusaError } from "@medusajs/framework/utils"7// ...8
9class MyAuthProviderService extends AbstractAuthModuleProvider {10  // ...11  async register(12    data: AuthenticationInput,13    authIdentityProviderService: AuthIdentityProviderService14  ): Promise<AuthenticationResponse> {15    try {16      await authIdentityService.retrieve({17        entity_id: data.body.email, // email or some ID18      })19
20      return {21        success: false,22        error: "Identity with email already exists",23      }24    } catch (error) {25      if (error.type === MedusaError.Types.NOT_FOUND) {26        const createdAuthIdentity = await authIdentityProviderService.create({27          entity_id: data.body.email, // email or some ID28          provider: this.provider,29          provider_metadata: {30            // can include password or any other relevant information31          }32        })33
34        return {35          success: true,36          authIdentity: createdAuthIdentity,37        }38      }39
40      return { success: false, error: error.message }41    }42  }43}

Parameters

The details of the authentication request.
authIdentityProviderServiceAuthIdentityProviderService
The service used to retrieve or create an auth identity. It has two methods: create to create an auth identity, and retrieve to retrieve an auth identity. When you authenticate the user, you can create an auth identity using this service.

Returns

PromisePromise<AuthenticationResponse>
The created authentication identity if no errors occur.

update#

This method is used to update an auth identity's details.

For example, the emailpass provider's implementation of this method updates a user's password.

Example

Code
1import {2  AuthIdentityProviderService,3  AuthenticationInput,4  AuthenticationResponse5} from "@medusajs/framework/types"6import { MedusaError } from "@medusajs/framework/utils"7// ...8
9class MyAuthProviderService extends AbstractAuthModuleProvider {10  // ...11  async update(12    data: Record<string, unknown>,13    authIdentityProviderService: AuthIdentityProviderService14  ): Promise<AuthenticationResponse> {15    try {16      const authIdentity = await authIdentityService.update(17        data.email, // email or some ID used to identify the auth identity18        {19          user: data.user // example20        }21      )22
23      return { success: true, authIdentity }24    } catch (error) {25      return { success: false, error: error.message }26    }27  }28}

Parameters

dataRecord<string, unknown>
Data relevant to identify the auth identity and what to update in it. For example, the emailpass provider expects in this object an email and password properties.
authIdentityProviderServiceAuthIdentityProviderService
The service used to retrieve or create an auth identity. It has two methods: create to create an auth identity, and retrieve to retrieve an auth identity. When you authenticate the user, you can create an auth identity using this service.

Returns

PromisePromise<AuthenticationResponse>
The updated authentication identity if no errors occur.

validateCallback#

This method validates the callback of an authentication request.

In an authentication flow that requires performing an action with a third-party service, such as login with a social account, the authenticate method is called first.

Then, the third-party service redirects to a frontend URL passing it a code query parameter. The frontend should then send a request to the Medusa application's validate callback API route, passing it the code. That route uses this method to verify the callback's code.

If the callback is verified successfully, the provider creates an auth identity for the user, or updates the auth identity's user information.

In the auth identity, use the following properties to store additional data:

  • provider_metadata: Store metadata useful for the provider, such as a password hash.
  • user_metadata: Store metadata of the user's details. For example, if the third-party service returns the user's information such as email or name, you store this data in this property.

Related Guide: Learn about the different authentication flows in Medusa.

Example

Code
1import {2  AuthIdentityProviderService,3  AuthenticationInput,4  AuthenticationResponse5} from "@medusajs/framework/types"6// ...7
8class MyAuthProviderService extends AbstractAuthModuleProvider {9  // ...10  async validateCallback(11    data: AuthenticationInput,12    authIdentityProviderService: AuthIdentityProviderService13  ): Promise<AuthenticationResponse> {14    const isAuthenticated = false15    // TODO perform custom logic to authenticate the user16    // ...17
18    if (!isAuthenticated) {19      // if the authentication didn't succeed, return20      // an object of the following format21      return {22        success: false,23        error: "Something went wrong"24      }25    }26
27    // authentication is successful, create an auth identity28    // if doesn't exist29    let authIdentity30
31    try {32      authIdentity = await authIdentityProviderService.retrieve({33        entity_id: data.body.email, // email or some ID34        provider: this.provider35      })36    } catch (e) {37      // The auth identity doesn't exist so create it38      authIdentity = await authIdentityProviderService.create({39        entity_id: data.body.email, // email or some ID40        provider: this.provider,41        provider_metadata: {42          // can include password or any other relevant information43        },44        user_metadata: {45          // can include data retrieved from the third-party service46        }47      })48    }49
50    return {51      success: true,52      authIdentity53    }54  }55}

Parameters

The details of the authentication request.
authIdentityProviderServiceAuthIdentityProviderService
The service used to retrieve or create an auth identity. It has two methods: create to create an auth identity, and retrieve to retrieve an auth identity. When you authenticate the user, you can create an auth identity using this service.

Returns

PromisePromise<AuthenticationResponse>
The authentication response.

3. Create Module Definition File#

Create the file src/modules/my-auth/index.ts with the following content:

src/modules/my-auth/index.ts
1import MyAuthProviderService from "./service"2import { 3  ModuleProvider, 4  Modules5} from "@medusajs/framework/utils"6
7export default ModuleProvider(Modules.AUTH, {8  services: [MyAuthProviderService],9})

This exports the module's definition, indicating that the MyAuthProviderService is the module's service.


4. Use Module#

To use your Auth Module Provider, add it to the providers array of the Auth Module in medusa-config.ts:

medusa-config.ts
1import { Modules } from "@medusajs/framework/utils"2
3// ...4
5module.exports = defineConfig({6  // ...7  modules: [8    {9      resolve: "@medusajs/medusa/auth",10      options: {11        providers: [12          {13            resolve: "./src/modules/my-auth",14            id: "my-auth",15            options: {16              // provider options...17            },18          },19        ],20      },21    },22  ]23})

5. Test it Out#

To test out your authentication provider, use any of the Authentication Routes, using your provider's ID as a path parameter.

For example, to get a registration token for an admin user, send a POST request to /auth/user/my-auth/register replacing my-auth with your authentication provider's ID:

Code
1curl -X POST http://localhost:9000/auth/user/my-auth/register2-H 'Content-Type: application/json' --data-raw '{3  "email": "Whitney_Schultz@gmail.com",4  "password": "supersecret"5}'

Change the request body to pass the data required for your authentication provider to register the user.

If registration is successful, the response will have a token property.

Was this page helpful?