Skip to content

Issue: userContext properties not accessible in Passwordless recipe email delivery override #996

Open
@danielshawellis

Description

@danielshawellis

Issue: userContext properties not accessible in Passwordless recipe email delivery override

Description

When passing custom properties in userContext from the client to the server using the Passwordless recipe, these properties are not directly accessible in the sendEmail override function.

The TypeScript type signature suggests userContext should be a simple key-value object, but actual logs show it contains only SuperTokens internal structures without the custom properties we set from the client.

Versions

  • supertokens-node: 21.1.0
  • supertokens-web-js: 0.14.0
  • Node.js: (running in Docker container)

Steps to Reproduce

Client-side configuration and code

// Client initialization in vue/src/services/supertokens.ts
SuperTokens.init({
  appInfo: {
    appName: window.location.host,
    apiDomain: window.location.origin,
    apiBasePath: "/node/auth"
  },
  recipeList: [
    Passwordless.init()
  ]
});

// Client usage in vue/src/composables/useAuth.ts
const sendPasswordlessCode = async (email: string) => {
  const response = await createCode({ 
    email, 
    userContext: { someUserContextProperty: "someValue" } 
  });
};

Server-side configuration and code

// Server initialization in node/src/services/supertokens.ts
supertokens.init({
  framework: "express",
  supertokens: {
    connectionURI: "http://supertokens:3567"
  },
  appInfo: {
    appName: DOMAIN,
    apiDomain: `https://${DOMAIN}`,
    websiteDomain: `https://${DOMAIN}`
  },
  recipeList: [
    Passwordless.init({
      flowType: "MAGIC_LINK",
      contactMethod: "EMAIL",
      emailDelivery: {
        override: (originalImplementation) => ({
          ...originalImplementation,
          sendEmail: async (input) => {
            console.log("input.userContext: ", input.userContext);
            return originalImplementation.sendEmail(input);
          }
        })
      }
    })
  ]
});

Expected TypeScript Type

const input: {
    type: "PASSWORDLESS_LOGIN";
    isFirstFactor: boolean;
    email: string;
    userInputCode?: string;
    urlWithLinkCode?: string;
    codeLifetime: number;
    preAuthSessionId: string;
    tenantId: string;
    userContext: UserContext; // Should contain our custom properties
}

Actual server logs

input.userContext:  {
  _default: {
    request: ExpressRequest {
      getFormData: [AsyncFunction (anonymous)],
      getJSONBody: [AsyncFunction (anonymous)],
      getBodyAsJSONOrFormData: [AsyncFunction (anonymous)],
      wrapperUsed: true,
      parsedJSONBody: [Object],
      parsedUrlEncodedFormData: undefined,
      getFormDataFromRequestBody: [AsyncFunction (anonymous)],
      getJSONFromRequestBody: [AsyncFunction (anonymous)],
      getKeyValueFromQuery: [Function (anonymous)],
      getMethod: [Function (anonymous)],
      getCookieValue: [Function (anonymous)],
      getHeaderValue: [Function (anonymous)],
      getOriginalURL: [Function (anonymous)],
      original: [IncomingMessage],
      request: [IncomingMessage]
    },
    keepCacheAlive: true,
    coreCallCache: {},
    globalCacheTag: 1746037333884
  }
}

Issue Summary

The custom property someUserContextProperty set on the client-side is completely missing in the server's input.userContext. Instead, we only see internal SuperTokens structures like _default with Express request information.

According to the TypeScript type definition, we should be able to directly access input.userContext.someUserContextProperty, but this value is not being passed through to the server-side override function.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions