Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug]: For third-party-login defect #10818

Closed
hans642 opened this issue Jan 4, 2025 · 4 comments
Closed

[Bug]: For third-party-login defect #10818

hans642 opened this issue Jan 4, 2025 · 4 comments

Comments

@hans642
Copy link

hans642 commented Jan 4, 2025

Package.json file

{
  "name": "medusa-starter-default",
  "version": "0.0.1",
  "description": "A starter for Medusa projects.",
  "author": "Medusa (https://medusajs.com)",
  "license": "MIT",
  "keywords": [
    "sqlite",
    "postgres",
    "typescript",
    "ecommerce",
    "headless",
    "medusa"
  ],
  "scripts": {
    "build": "medusa build",
    "seed": "medusa exec ./src/scripts/seed.ts",
    "start": "npx medusa db:migrate && medusa start",
    "dev": "medusa develop",
    "test:integration:http": "TEST_TYPE=integration:http NODE_OPTIONS=--experimental-vm-modules jest --silent=false --runInBand --forceExit",
    "test:integration:modules": "TEST_TYPE=integration:modules NODE_OPTIONS=--experimental-vm-modules jest --silent --runInBand --forceExit",
    "test:unit": "TEST_TYPE=unit NODE_OPTIONS=--experimental-vm-modules jest --silent --runInBand --forceExit"
  },
  "dependencies": {
    "@medusajs/admin-sdk": "latest",
    "@medusajs/cli": "latest",
    "@medusajs/framework": "latest",
    "@medusajs/medusa": "latest",
    "@mikro-orm/core": "5.9.7",
    "@mikro-orm/knex": "5.9.7",
    "@mikro-orm/migrations": "5.9.7",
    "@mikro-orm/postgresql": "5.9.7",
    "@paypal/checkout-server-sdk": "^1.0.3",
    "awilix": "^8.0.1",
    "liquidjs": "^10.17.0",
    "pg": "^8.13.0"
  },
  "devDependencies": {
    "@medusajs/test-utils": "latest",
    "@mikro-orm/cli": "5.9.7",
    "@swc/core": "1.5.7",
    "@swc/jest": "^0.2.36",
    "@types/jest": "^29.5.13",
    "@types/node": "^20.0.0",
    "@types/react": "^18.3.2",
    "@types/react-dom": "^18.2.25",
    "jest": "^29.7.0",
    "prop-types": "^15.8.1",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "ts-node": "^10.9.2",
    "typescript": "^5.6.2",
    "vite": "^5.2.11"
  },
  "engines": {
    "node": ">=20"
  }
}

Node.js version

v20.15.1

Database and its version

16.4

Operating system name and version

macOS 15.1

Browser name

Chrome

What happended?

Reference Document: https://docs.medusajs.com/resources/storefront-development/customers/third-party-login
In Step 2: Callback Page in Storefront

When call callback api

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

Then adds to the page the function createCustomer, Here not return google name, picture info only can createCustomer have a email.

For source code:
packages/medusa/src/api/auth/utils/generate-jwt-token.ts
import { AuthIdentityDTO } from "@medusajs/framework/types"
import { generateJwtToken } from "@medusajs/framework/utils"

export function generateJwtTokenForAuthIdentity(
  {
    authIdentity,
    actorType,
  }: { authIdentity: AuthIdentityDTO; actorType: string },
  {
    secret,
    expiresIn,
  }: { secret: string | undefined; expiresIn: string | undefined }
) {
  const entityIdKey = `${actorType}_id`
  const entityId = authIdentity?.app_metadata?.[entityIdKey] as
    | string
    | undefined

  return generateJwtToken(
    {
      actor_id: entityId ?? "",
      actor_type: actorType,
      auth_identity_id: authIdentity?.id ?? "",
      app_metadata: {
        [entityIdKey]: entityId,
      },
    },
    {
      secret,
      expiresIn,
    }
  )
}

Expected behavior

option1: return authIdentity info
option2: can let develop set metadata

Actual behavior

Can't got google callback info

Link to reproduction repo

medusa(v2)

@hans642
Copy link
Author

hans642 commented Jan 4, 2025

How can retrieve email from customer from "provider_identity" table?

@ranjithkumar8352
Copy link
Contributor

ranjithkumar8352 commented Jan 13, 2025

@hans642 Here's how I'm fetching user info for google auth:

  1. Create a custom route to get user info /store/customer/identity/route.ts
import type { MedusaRequest, MedusaResponse } from "@medusajs/framework/http";
import { jwtDecode } from "jwt-decode";
import { Modules } from "@medusajs/framework/utils";

type TokenOptions = {
  auth_identity_id: string;
};

export async function GET(
  req: MedusaRequest,
  res: MedusaResponse
): Promise<void> {
  const token = req.get("Authorization")?.replace("Bearer ", "").trim();

  if (!token) {
    res.sendStatus(401);
    return;
  }
  const decoded: TokenOptions = jwtDecode(token);
  const authId = decoded.auth_identity_id;
  if (!authId) {
    res.json(null);
    return;
  }
  const authModuleService = req.scope.resolve(Modules.AUTH);
  const identity = (await authModuleService.listProviderIdentities()).filter(
    (iden) => iden.auth_identity_id === authId
  );

  res.json(identity.length > 0 ? identity[0].user_metadata : null);
}

Call this API on the storefront after the initial callback,

getUserInfo function on the storefront

const getUserInfo = async (token: string) => {
    const headers = {
      authorization: `Bearer ${token}`,
    }
    const userInfo = await sdk.client
      .fetch<Record<string, string> | null>("/store/customer/identity", {
        headers,
      })
      .catch((err) => (console.log(err), null))
    return userInfo
  }

Storefront code.

let token = await sendCallback()
    if (!token) {
      alert("Failed to get token")
      // redirect to login page
      redirect("/account")
    }

    const userInfo = await getUserInfo(token)
    if (!userInfo) {
      alert("Failed to get user info")
      redirect("/account")
    }

    const shouldCreateCustomer =
      (decodeToken(token) as { actor_id: string }).actor_id === ""

    if (shouldCreateCustomer) {
      await createCustomer(token, userInfo)

      token = await refreshToken(token)
    }

    if (!token) {
      alert("Failed to refresh token")
      return
    }

    // use token to send authenticated requests

@hans642
Copy link
Author

hans642 commented Jan 13, 2025

Thank you @ranjithkumar8352
Here is my code:

1.Create a custom route to get user info /store/customer/auth/route.ts

export const GET = async (
  req: MedusaRequest,
  res: MedusaResponse
) => {
  const authModuleService = container.resolve(Modules.AUTH)
  const filter = {auth_identity_id: (req.query.auth_identity_id || '') as string}

  const info = await authModuleService.listProviderIdentities(filter)
  res.json(info?.[0])
}

2.use middleware check auth

export default defineMiddlewares({
  routes: [
    {
      matcher: "/store/custom/auth",
      middlewares: [authenticate("customer", ["session", "bearer"], {allowUnregistered: true})],
    },
  ],
})

3.Storefront code

  const retrieveCustomer = async (token: string, identity: string) => {
    return await fetch(`${BACKEND_URL}/store/custom/auth?auth_identity_id=${identity}`, {
      credentials: "include",
      method: "GET",
      headers: {
        "Content-Type": "application/json",
        "Authorization": `Bearer ${token}`,
        "x-publishable-api-key": PUBLISHABLE_API_KEY || "temp",
      },
    }).then((res) => res.json())
  }

@hans642
Copy link
Author

hans642 commented Jan 13, 2025

Solved, Close this ticket

@hans642 hans642 closed this as completed Jan 13, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants