Skip to content

Commit 467e783

Browse files
authored
add support for passwordless (#326)
* add support for passwordless * add covector change file
1 parent d035a5b commit 467e783

File tree

6 files changed

+350
-5
lines changed

6 files changed

+350
-5
lines changed

.changes/main.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@simulacrum/auth0-simulator": minor:feat
3+
---
4+
5+
Add support for passwordless auth

packages/auth0/src/handlers/auth0-handlers.ts

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ export type Routes =
2424
| "/login/callback"
2525
| "/oauth/token"
2626
| "/v2/logout"
27-
| "/userinfo";
27+
| "/userinfo"
28+
| "/passwordless/start";
2829

2930
export type AuthSession = { username: string; nonce: string };
3031

@@ -266,5 +267,53 @@ export const createAuth0Handlers = (
266267

267268
res.status(200).json(userinfo);
268269
},
270+
271+
["/passwordless/start"]: async function (req, res, next) {
272+
logger.log({ "/passwordless/start": { body: req.body } });
273+
274+
try {
275+
const { client_id, connection, email, phone_number, send } = req.body;
276+
277+
// Validate required fields
278+
if (!client_id) {
279+
return res.status(400).json({ error: "client_id is required" });
280+
}
281+
282+
if (!connection || (connection !== "email" && connection !== "sms")) {
283+
return res.status(400).json({
284+
error: "connection must be 'email' or 'sms'",
285+
});
286+
}
287+
288+
if (connection === "email" && !email) {
289+
return res.status(400).json({
290+
error: "email is required when connection is 'email'",
291+
});
292+
}
293+
294+
if (connection === "sms" && !phone_number) {
295+
return res.status(400).json({
296+
error: "phone_number is required when connection is 'sms'",
297+
});
298+
}
299+
300+
// Return appropriate response based on connection type
301+
if (connection === "email") {
302+
res.status(200).json({
303+
_id: "000000000000000000000000",
304+
email: email,
305+
email_verified: false,
306+
});
307+
} else {
308+
res.status(200).json({
309+
_id: "000000000000000000000000",
310+
phone_number: phone_number,
311+
phone_verified: false,
312+
});
313+
}
314+
} catch (error) {
315+
next(error);
316+
}
317+
},
269318
};
270319
};

packages/auth0/src/handlers/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,11 @@ import { defaultErrorHandler } from "../middleware/error-handling.ts";
77
import { createAuth0Handlers } from "./auth0-handlers.ts";
88
import { createOpenIdHandlers } from "./openid-handlers.ts";
99
import path from "path";
10+
import { fileURLToPath } from "url";
1011
import { Auth0Configuration } from "../types.ts";
1112

13+
const __filename = fileURLToPath(import.meta.url);
14+
const __dirname = path.dirname(__filename);
1215
const publicDir = path.join(__dirname, "..", "views", "public");
1316
export const extendRouter =
1417
(config: Auth0Configuration, debug = false) =>
@@ -38,6 +41,7 @@ export const extendRouter =
3841
.post("/usernamepassword/login", auth0["/usernamepassword/login"])
3942
.post("/login/callback", auth0["/login/callback"])
4043
.post("/oauth/token", auth0["/oauth/token"])
44+
.post("/passwordless/start", auth0["/passwordless/start"])
4145
.get("/userinfo", auth0["/userinfo"])
4246
.get("/v2/logout", auth0["/v2/logout"])
4347
.get("/.well-known/jwks.json", openid["/.well-known/jwks.json"])

packages/auth0/src/handlers/oauth-handlers.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -189,18 +189,19 @@ const verifyUserExistsInStore = ({
189189
let username: string;
190190
let password: string | undefined;
191191

192-
if (grant_type === "password") {
192+
if (grant_type === "http://auth0.com/oauth/grant-type/passwordless/otp") {
193+
username = body.username;
194+
} else if (grant_type === "password") {
193195
username = body.username;
194196
password = body.password;
195197
} else {
196198
// specifically grant_type === 'authorization_code'
197199
// but naively using it to handle other cases at the moment
198200
assert(typeof code !== "undefined", "400::no code in /oauth/token");
199201
[nonce, username] = decodeBase64(code).split(":");
202+
assert(!!username, `400::no nonce in store for ${code}`);
200203
}
201204

202-
assert(!!username, `400::no nonce in store for ${code}`);
203-
204205
let user: Auth0User | undefined = personQuery((person) => {
205206
assert(!!person.email, `500::no email defined on person scenario`);
206207

packages/auth0/src/types.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ export type GrantType =
3838
| "password"
3939
| "client_credentials"
4040
| "authorization_code"
41-
| "refresh_token";
41+
| "refresh_token"
42+
| "http://auth0.com/oauth/grant-type/passwordless/otp";
4243

4344
export type ScopeConfig =
4445
| string

0 commit comments

Comments
 (0)