{"version":3,"file":"oauth-handlers.mjs","names":["user: Auth0User | undefined","nonce: string | undefined","refreshToken: RefreshToken","context: RuleContext<Partial<AccessTokenPayload>, IdTokenData>","userData: RuleUser","idTokenData: IdTokenData","username: string","password: string | undefined","decodeBase64"],"sources":["../../src/handlers/oauth-handlers.ts"],"sourcesContent":["import { assert } from \"assert-ts\";\nimport { decode, decode as decodeBase64 } from \"base64-url\";\nimport { epochTime, expiresAt } from \"../auth/date.ts\";\nimport { createJsonWebToken } from \"../auth/jwt.ts\";\nimport { createRulesRunner } from \"../rules/rules-runner.ts\";\nimport { deriveScope, createPersonQuery } from \"./utils.ts\";\n\nimport type { Request } from \"express\";\nimport type { RuleContext, RuleUser } from \"../rules/types.ts\";\nimport type {\n  ScopeConfig,\n  AccessTokenPayload,\n  GrantType,\n  IdTokenData,\n  RefreshToken,\n} from \"../types.ts\";\nimport {\n  createRefreshToken,\n  issueRefreshToken,\n} from \"../auth/refresh-token.ts\";\nimport { type ExtendedSimulationStore } from \"../store/index.ts\";\nimport { type Auth0User } from \"../store/entities.ts\";\n\nexport const createTokens = async ({\n  body,\n  iss,\n  clientID,\n  audience,\n  rulesDirectory,\n  scope: scopeConfig,\n  simulationStore,\n}: {\n  body: Request[\"body\"];\n  iss: string;\n  clientID: string;\n  audience: string;\n  rulesDirectory: string | undefined;\n  scope: ScopeConfig;\n  simulationStore: ExtendedSimulationStore;\n}) => {\n  let { grant_type }: { grant_type: GrantType } = body;\n  let scope = deriveScope({ scopeConfig, clientID, audience });\n\n  let accessToken = getBaseAccessToken({ iss, grant_type, scope, audience });\n  let user: Auth0User | undefined;\n  let nonce: string | undefined;\n\n  if (grant_type === \"client_credentials\") {\n    return { access_token: createJsonWebToken(accessToken) };\n  }\n  // TODO: check refresh_token expiry date\n  else if (grant_type === \"refresh_token\") {\n    let { refresh_token: refreshTokenValue } = body;\n    let refreshToken: RefreshToken = JSON.parse(decode(refreshTokenValue));\n\n    let findUser = createPersonQuery(simulationStore);\n\n    user = findUser((person) => person.id === refreshToken.user.id);\n\n    nonce = refreshToken.nonce;\n    assert(!!nonce, `400::No nonce in request`);\n  } else {\n    let result = verifyUserExistsInStore({\n      simulationStore,\n      body,\n      grant_type,\n    });\n\n    user = result.user;\n    nonce = result.nonce;\n  }\n\n  assert(!!user, \"500::No user found\");\n\n  let { idTokenData, userData } = getIdToken({\n    body,\n    iss,\n    user,\n    clientID,\n    nonce,\n  });\n\n  let context: RuleContext<Partial<AccessTokenPayload>, IdTokenData> = {\n    clientID,\n    accessToken: { scope, sub: idTokenData.sub },\n    idToken: idTokenData,\n  };\n\n  let rulesRunner = createRulesRunner(rulesDirectory);\n  // the rules mutate the values\n  await rulesRunner(userData, context);\n\n  return {\n    access_token: createJsonWebToken({\n      ...accessToken,\n      ...context.accessToken,\n      ...(scope.split(\" \").includes(\"email\") ? { email: user.email } : {}),\n    }),\n    id_token: createJsonWebToken({\n      ...userData,\n      ...context.idToken,\n    }),\n    refresh_token: issueRefreshToken(scope, grant_type)\n      ? createRefreshToken({\n          exp: idTokenData.exp,\n          rotations: 0,\n          scope,\n          user,\n          nonce,\n        })\n      : undefined,\n  };\n};\n\nexport const getIdToken = ({\n  body,\n  iss,\n  user,\n  clientID,\n  nonce,\n}: {\n  body: Request[\"body\"];\n  iss: string;\n  user: Auth0User;\n  clientID: string;\n  nonce: string | undefined;\n}) => {\n  let userData: RuleUser = {\n    name: body?.name ?? user.name,\n    email: body?.email ?? user.email,\n    email_verified: true,\n    user_id: body?.id ?? user.id,\n    nickname: body?.nickname,\n    picture: body?.picture ?? user.picture,\n    identities: body?.identities,\n  };\n\n  assert(!!user.email, \"500::User in store requires an email\");\n\n  let idTokenData: IdTokenData = {\n    alg: \"RS256\",\n    typ: \"JWT\",\n    iss,\n    exp: expiresAt(),\n    iat: epochTime(),\n    email: user.email,\n    aud: clientID,\n    sub: user.id,\n  };\n\n  if (typeof nonce !== \"undefined\") {\n    idTokenData.nonce = nonce;\n  }\n\n  return { userData, idTokenData };\n};\n\nexport const getBaseAccessToken = ({\n  iss,\n  grant_type,\n  scope,\n  audience,\n}: {\n  iss: string;\n  grant_type: string;\n  scope: string;\n  audience: string;\n}): Partial<AccessTokenPayload> => ({\n  iss,\n  exp: expiresAt(),\n  iat: epochTime(),\n  aud: audience,\n  gty: grant_type,\n  scope,\n});\n\nconst verifyUserExistsInStore = ({\n  simulationStore,\n  body,\n  grant_type,\n}: {\n  simulationStore: ExtendedSimulationStore;\n  body: Request[\"body\"];\n  grant_type: string;\n}) => {\n  let { code } = body;\n  let personQuery = createPersonQuery(simulationStore);\n  let nonce: string | undefined;\n  let username: string;\n  let password: string | undefined;\n\n  if (grant_type === \"http://auth0.com/oauth/grant-type/passwordless/otp\") {\n    username = body.username;\n  } else if (grant_type === \"password\") {\n    username = body.username;\n    password = body.password;\n  } else {\n    // specifically grant_type === 'authorization_code'\n    // but naively using it to handle other cases at the moment\n    assert(typeof code !== \"undefined\", \"400::no code in /oauth/token\");\n    [nonce, username] = decodeBase64(code).split(\":\");\n    assert(!!username, `400::no nonce in store for ${code}`);\n  }\n\n  let user: Auth0User | undefined = personQuery((person) => {\n    assert(!!person.email, `500::no email defined on person scenario`);\n\n    let valid = person.email.toLowerCase() === username.toLowerCase();\n\n    if (typeof password === \"undefined\") {\n      return valid;\n    } else {\n      return valid && password === person.password;\n    }\n  });\n\n  assert(!!user, \"401::Unauthorized\");\n\n  return { user, nonce };\n};\n"],"mappings":"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"}