Medusa Multi-Factor Authentication API

Multi-factor authentication (MFA) adds an extra layer of security to admin accounts by requiring additional verification factors during login, such as a TOTP code or a recovery code. These API routes allow admin users to manage their MFA factors, challenges, and recovery codes.

Operations 5

POST /auth/mfa/challenges/{id}/verify Verify a Multi-Factor Authentication (MFA) Challenge #
GET /auth/mfa/factors List Multifactor Authentication (MFA) Factors #
POST /auth/mfa/factors Start Multi-Factor Authentication (MFA) Factor Enrollment #
POST /auth/mfa/factors/{id}/verify Verify and Enable a Multi-Factor Authentication (MFA) Factor #
POST /auth/mfa/recovery-codes Generate Multi-Factor Authentication (MFA) Recovery Codes #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/medusa-multi-factor-authentication-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

medusa-multi-factor-authentication-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  version: 2.19.0
  title: Medusa Admin Multi-Factor Authentication API
  license:
    name: MIT
    url: https://github.com/medusajs/medusa/blob/develop/LICENSE
  description: 'Multi-factor authentication (MFA) adds an extra layer of security to admin accounts by requiring additional verification factors during login, such as a TOTP code or a recovery code.

    These API routes allow admin users to manage their MFA factors, challenges, and recovery codes.

    '
servers:
- url: http://localhost:9000
- url: https://api.medusajs.com
tags:
- name: Multi-Factor Authentication
  description: 'Multi-factor authentication (MFA) adds an extra layer of security to admin accounts by requiring additional verification factors during login, such as a TOTP code or a recovery code.

    These API routes allow admin users to manage their MFA factors, challenges, and recovery codes.

    '
  externalDocs:
    description: Learn more about MFA in Medusa
    url: https://docs.medusajs.com/resources/commerce-modules/auth/mfa
paths:
  /auth/mfa/challenges/{id}/verify:
    post:
      operationId: PostMfaChallengesIdVerify
      summary: Verify a Multi-Factor Authentication (MFA) Challenge
      x-sidebar-summary: Verify MFA Challenge
      description: 'Verify a multi-factor authentication (MFA) challenge issued during login. On success, this

        completes the authentication flow and returns a JWT token that can be used to authenticate

        subsequent requests.

        '
      externalDocs:
        description: Learn more about MFA in Medusa
        url: https://docs.medusajs.com/resources/commerce-modules/auth/mfa
      x-authenticated: false
      parameters:
      - name: id
        in: path
        description: The MFA challenge's ID.
        required: true
        schema:
          type: string
      requestBody:
        content:
          application/json:
            schema:
              type: object
              description: The details required to verify the MFA challenge.
              required:
              - method
              - code
              properties:
                method:
                  type: string
                  title: method
                  description: The MFA method used to verify the challenge (for example, `totp` or `recovery-code`).
                code:
                  type: string
                  title: code
                  description: The verification code generated by the chosen MFA method.
      x-codeSamples:
      - lang: JavaScript
        label: JS SDK
        source: "import Medusa from \"@medusajs/js-sdk\"\n\nexport const sdk = new Medusa({\n  baseUrl: import.meta.env.VITE_BACKEND_URL || \"/\",\n  debug: import.meta.env.DEV,\n  auth: {\n    type: \"session\",\n  },\n})\n\nconst result = await sdk.auth.login(\"user\", \"emailpass\", {\n  email: \"user@example.com\",\n  password: \"secret\"\n})\n\nif (typeof result === \"object\" && \"mfa_challenge\" in result) {\n  await sdk.auth.mfa.verifyChallenge(result.mfa_challenge.id, {\n    method: \"totp\",\n    code: \"123456\"\n  })\n}"
      - lang: Shell
        label: cURL
        source: "curl -X POST '{backend_url}/auth/mfa/challenges/{id}/verify' \\\n-H 'Content-Type: application/json' \\\n--data-raw '{\n  \"method\": \"{value}\",\n  \"code\": \"{value}\"\n}'"
      tags:
      - Multi-Factor Authentication
      responses:
        '200':
          description: OK
        '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'
      x-since: 2.15.3
  /auth/mfa/factors:
    get:
      operationId: GetMfaFactors
      summary: List Multifactor Authentication (MFA) Factors
      x-sidebar-summary: List MFA Factors
      description: 'Retrieve the list of multi-factor authentication (MFA) factors registered for the authenticated user,

        including both pending (not yet verified) and enabled factors.

        '
      x-authenticated: true
      parameters: []
      x-codeSamples:
      - lang: JavaScript
        label: JS SDK
        source: "import Medusa from \"@medusajs/js-sdk\"\n\nexport const sdk = new Medusa({\n  baseUrl: import.meta.env.VITE_BACKEND_URL || \"/\",\n  debug: import.meta.env.DEV,\n  auth: {\n    type: \"session\",\n  },\n})\n\nconst { mfa_factors } = await sdk.auth.mfa.list()"
      - lang: Shell
        label: cURL
        source: curl '{backend_url}/auth/mfa/factors'
      tags:
      - Multi-Factor Authentication
      responses:
        '200':
          description: OK
        '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'
      x-since: 2.15.3
    post:
      operationId: PostMfaFactors
      summary: Start Multi-Factor Authentication (MFA) Factor Enrollment
      x-sidebar-summary: Start MFA Factor Enrollment
      description: 'Start the enrollment of a new multi-factor authentication (MFA) factor for the authenticated

        user. The response contains the factor along with provider-specific setup data (such as a

        secret and an `otpauth_url` for TOTP) that can be used to display a QR code. The factor must

        then be verified via the verify endpoint before it can be used.

        '
      x-authenticated: true
      externalDocs:
        description: Learn more about MFA in Medusa
        url: https://docs.medusajs.com/resources/commerce-modules/auth/mfa
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
              description: The details of the MFA factor to enroll.
              required:
              - provider
              properties:
                provider:
                  type: string
                  title: provider
                  description: The ID of the MFA provider to enroll the factor with (for example, `totp`).
                label:
                  type: string
                  title: label
                  description: A human-readable label to identify the factor (for example, the name of the authenticator app or device).
                issuer:
                  type: string
                  title: issuer
                  description: The issuer name shown in authenticator apps for this factor. Defaults to the application name when omitted.
                metadata:
                  type: object
                  description: Additional provider-specific data to associate with the factor.
      x-codeSamples:
      - lang: JavaScript
        label: JS SDK
        source: "import Medusa from \"@medusajs/js-sdk\"\n\nexport const sdk = new Medusa({\n  baseUrl: import.meta.env.VITE_BACKEND_URL || \"/\",\n  debug: import.meta.env.DEV,\n  auth: {\n    type: \"session\",\n  },\n})\n\nconst setup = await sdk.auth.mfa.start({\n  provider: \"totp\",\n  label: \"Authenticator app\"\n})\n\n// Render setup.otpauth_url as a QR code or show setup.secret manually."
      - lang: Shell
        label: cURL
        source: "curl -X POST '{backend_url}/auth/mfa/factors' \\\n-H 'Content-Type: application/json' \\\n--data-raw '{\n  \"provider\": \"{value}\"\n}'"
      tags:
      - Multi-Factor Authentication
      responses:
        '200':
          description: OK
        '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'
      x-since: 2.15.3
  /auth/mfa/factors/{id}/verify:
    post:
      operationId: PostMfaFactorsIdVerify
      summary: Verify and Enable a Multi-Factor Authentication (MFA) Factor
      x-sidebar-summary: Verify and Enable MFA Factor
      description: 'Verify a pending multi-factor authentication (MFA) factor by submitting a code generated from

        it. A successful verification enables the factor, after which it can be used to verify MFA

        challenges during login.

        '
      x-authenticated: true
      externalDocs:
        description: Learn more about MFA in Medusa
        url: https://docs.medusajs.com/resources/commerce-modules/auth/mfa
      parameters:
      - name: id
        in: path
        description: The MFA factor's ID.
        required: true
        schema:
          type: string
      requestBody:
        content:
          application/json:
            schema:
              type: object
              description: The details required to verify and enable the MFA factor.
              required:
              - code
              properties:
                code:
                  type: string
                  title: code
                  description: The verification code generated by the MFA factor (for example, the current TOTP code from the authenticator app).
      x-codeSamples:
      - lang: JavaScript
        label: JS SDK
        source: "import Medusa from \"@medusajs/js-sdk\"\n\nexport const sdk = new Medusa({\n  baseUrl: import.meta.env.VITE_BACKEND_URL || \"/\",\n  debug: import.meta.env.DEV,\n  auth: {\n    type: \"session\",\n  },\n})\n\nconst { mfa_factor } = await sdk.auth.mfa.verify(\"authmfa_123\", {\n  code: \"123456\"\n})"
      - lang: Shell
        label: cURL
        source: "curl -X POST '{backend_url}/auth/mfa/factors/{id}/verify' \\\n-H 'Content-Type: application/json' \\\n--data-raw '{\n  \"code\": \"{value}\"\n}'"
      tags:
      - Multi-Factor Authentication
      responses:
        '200':
          description: OK
        '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'
      x-since: 2.15.3
  /auth/mfa/recovery-codes:
    post:
      operationId: PostMfaRecoveryCodes
      summary: Generate Multi-Factor Authentication (MFA) Recovery Codes
      x-sidebar-summary: Generate MFA Recovery Codes
      description: 'Generate a new set of single-use recovery codes for the authenticated user. Recovery codes can

        be used to verify MFA challenges when the user does not have access to their primary MFA

        factor. Generating new codes replaces any previously issued codes, so they should be stored in

        a safe place. At least one enabled MFA factor is required to generate recovery codes.

        '
      x-authenticated: true
      externalDocs:
        description: Learn more about MFA in Medusa
        url: https://docs.medusajs.com/resources/commerce-modules/auth/mfa
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
              description: The options to use when generating recovery codes.
              properties:
                count:
                  type: number
                  title: count
                  description: The number of recovery codes to generate. Must be between 1 and 50. Defaults to the provider's configured value when omitted.
      x-codeSamples:
      - lang: JavaScript
        label: JS SDK
        source: "import Medusa from \"@medusajs/js-sdk\"\n\nexport const sdk = new Medusa({\n  baseUrl: import.meta.env.VITE_BACKEND_URL || \"/\",\n  debug: import.meta.env.DEV,\n  auth: {\n    type: \"session\",\n  },\n})\n\nconst { recovery_codes } = await sdk.auth.mfa.generateRecoveryCodes()"
      - lang: Shell
        label: cURL
        source: curl -X POST '{backend_url}/auth/mfa/recovery-codes'
      tags:
      - Multi-Factor Authentication
      responses:
        '200':
          description: OK
        '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'
      x-since: 2.15.3
components:
  examples:
    invalid_data_error:
      summary: Invalid Data Error
      value:
        message: first_name must be a string
        type: invalid_data
    not_allowed_error:
      summary: Not Allowed Error
      value:
        message: Discount must be set to dynamic
        type: not_allowed
    database_error:
      summary: Database Error
      value:
        code: api_error
        message: An error occured while hashing password
        type: database_error
    default_error:
      summary: Default Error
      value:
        code: unknown_error
        message: An unknown error occurred.
        type: unknown_error
    invalid_argument_error:
      summary: Invalid Argument Error
      value:
        message: cart.total must be defined
        type: unexpected_state
    unexpected_state_error:
      summary: Unexpected State Error
      value:
        message: cart.total must be defined
        type: unexpected_state
  schemas:
    Error:
      title: Response Error
      type: object
      properties:
        code:
          type: string
          description: A slug code to indicate the type of the error.
          enum:
          - invalid_state_error
          - invalid_request_error
          - api_error
          - unknown_error
        message:
          type: string
          description: Description of the error that occurred.
          example: first_name must be a string
        type:
          type: string
          description: A slug indicating the type of the error.
          enum:
          - QueryRunnerAlreadyReleasedError
          - TransactionAlreadyStartedError
          - TransactionNotStartedError
          - conflict
          - unauthorized
          - payment_authorization_error
          - duplicate_error
          - not_allowed
          - invalid_data
          - not_found
          - database_error
          - unexpected_state
          - invalid_argument
          - unknown_error
  responses:
    invalid_request_error:
      description: Invalid Request Error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            code: invalid_request_error
            message: Discount with code TEST already exists.
            type: duplicate_error
    unauthorized:
      description: User is not authorized. Must log in first
      content:
        text/plain:
          schema:
            type: string
            default: Unauthorized
            example: Unauthorized
    400_error:
      description: Client Error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          examples:
            not_allowed:
              $ref: '#/components/examples/not_allowed_error'
            invalid_data:
              $ref: '#/components/examples/invalid_data_error'
    500_error:
      description: Server Error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          examples:
            database:
              $ref: '#/components/examples/database_error'
            unexpected_state:
              $ref: '#/components/examples/unexpected_state_error'
            invalid_argument:
              $ref: '#/components/examples/invalid_argument_error'
            default_error:
              $ref: '#/components/examples/default_error'
    invalid_state_error:
      description: Invalid State Error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            code: unknown_error
            message: The request conflicted with another request. You may retry the request with the provided Idempotency-Key.
            type: QueryRunnerAlreadyReleasedError
    not_found_error:
      description: Not Found Error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            message: Entity with id 1 was not found
            type: not_found
  securitySchemes:
    api_token:
      type: http
      x-displayName: API Token
      scheme: basic
    jwt_token:
      type: http
      x-displayName: JWT Token
      scheme: bearer
    cookie_auth:
      type: apiKey
      in: cookie
      name: connect.sid
      x-displayName: Cookie Session ID
    reset_password:
      type: http
      x-displayName: Reset Password Token
      scheme: bearer
      x-is-auth: false