@owlmeans/server-auth-otp 0.1.6 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# @owlmeans/server-auth-otp
|
|
2
|
+
|
|
3
|
+
Email OTP `AuthPlugin` for OwlMeans servers — passwordless login via time-limited one-time codes.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
- `makeOtpPlugin(context)` — factory for the `AuthPlugin` that handles `OTP_AUTH_TYPE` authentication requests
|
|
8
|
+
- `OtpService` — issues email challenges and verifies submitted codes; backed by `@owlmeans/auth-otp`
|
|
9
|
+
- Integrates with `@owlmeans/server-auth` plugin registry — plugs in alongside other auth strategies
|
|
10
|
+
- Resolves identities through `@owlmeans/server-auth-identity` after OTP verification
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
bun add @owlmeans/server-auth-otp
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Usage
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
import { makeOtpPlugin, OTP_SERVICE } from '@owlmeans/server-auth-otp'
|
|
22
|
+
import { registerPlugin } from '@owlmeans/server-auth/manager/plugins'
|
|
23
|
+
|
|
24
|
+
// Register in a server context that already has an OtpService wired
|
|
25
|
+
registerPlugin(context, makeOtpPlugin(context))
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The OTP service must be backed by a transport (e.g. `@owlmeans/mailer` → `@owlmeans/server-mailer-mailgun`) that can deliver the one-time code.
|
|
29
|
+
|
|
30
|
+
<!-- owlmeans:agent-guidance:start -->
|
|
31
|
+
## Agent guidance
|
|
32
|
+
|
|
33
|
+
This package ships embedded Claude Code skills and GitHub Copilot instructions under
|
|
34
|
+
`agent-meta/`. After installing your `@owlmeans/*` packages, run the OwlMeans
|
|
35
|
+
agent-skills installer to place them into your project's native locations
|
|
36
|
+
(`.claude/skills/` and `.github/instructions/`):
|
|
37
|
+
|
|
38
|
+
```sh
|
|
39
|
+
npx @owlmeans/agent-skills
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
The embedded files are version-matched to this package release. Do not edit them
|
|
43
|
+
directly — they are regenerated on each publish. To contribute guidance edits,
|
|
44
|
+
open a PR against the source monorepo.
|
|
45
|
+
<!-- owlmeans:agent-guidance:end -->
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "How to use @owlmeans/server-auth-otp — email OTP AuthPlugin and OtpService. Use when wiring passwordless email login in an OwlMeans server context."
|
|
3
|
+
applyTo: "**/context.ts, **/app/auth/*, **/services/otp*"
|
|
4
|
+
---
|
|
5
|
+
<!-- AUTO-GENERATED — do not edit. Regenerate via sync-agent-meta. -->
|
|
6
|
+
|
|
7
|
+
# Using `@owlmeans/server-auth-otp`
|
|
8
|
+
|
|
9
|
+
Email OTP authentication plugin for the OwlMeans auth-manager plugin system. Relies on `@owlmeans/auth-otp` for the OTP service interface, a Redis resource for code storage, and a `MailerService` to send codes.
|
|
10
|
+
|
|
11
|
+
## Public API surface
|
|
12
|
+
|
|
13
|
+
| Symbol | Kind | Purpose |
|
|
14
|
+
|--------|------|---------|
|
|
15
|
+
| `makeOtpService(alias?)` | fn | Service factory — stores/verifies OTP codes |
|
|
16
|
+
| `appendOtpPlugin(context)` | fn | Registers the OTP `AuthPlugin` into the server-auth plugin registry |
|
|
17
|
+
| `OTP_AUTH_TYPE` | const | `'email-otp'` — the auth type string to pass in `init` requests |
|
|
18
|
+
| `OTP_RESOURCE` | const | Redis resource alias for code storage |
|
|
19
|
+
| `OTP_TTL_SECONDS` | const | Code TTL (600 s = 10 min) |
|
|
20
|
+
| `OTP_CODE_LENGTH` | const | 6 |
|
|
21
|
+
|
|
22
|
+
## Registration requirements
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
import { makeOtpService, appendOtpPlugin, OTP_RESOURCE } from '@owlmeans/server-auth-otp'
|
|
26
|
+
import { makeRedisResource } from '@owlmeans/redis-resource'
|
|
27
|
+
import { makeConsoleMailerService, CONSOLE_MAILER, MAILER_SERVICE } from '@owlmeans/mailer'
|
|
28
|
+
import { makeMailgunMailerService } from '@owlmeans/server-mailer-mailgun'
|
|
29
|
+
|
|
30
|
+
// 1. Register the Redis code-cache resource.
|
|
31
|
+
context.registerResource(makeRedisResource(OTP_RESOURCE))
|
|
32
|
+
|
|
33
|
+
// 2. Register a MailerService (console for dev/tests, Mailgun for prod).
|
|
34
|
+
context.registerService(makeConsoleMailerService(MAILER_SERVICE))
|
|
35
|
+
// or:
|
|
36
|
+
context.registerService(makeMailgunMailerService(MAILER_SERVICE))
|
|
37
|
+
|
|
38
|
+
// 3. Register the OTP service (reads from Redis + Mailer).
|
|
39
|
+
context.registerService(makeOtpService())
|
|
40
|
+
|
|
41
|
+
// 4. Register the OTP AuthPlugin into the auth-manager plugin registry.
|
|
42
|
+
appendOtpPlugin(context)
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Auth flow
|
|
46
|
+
|
|
47
|
+
**Init** — client sends `{ type: 'email-otp', userId: 'user@email.com' }`:
|
|
48
|
+
- OTP service generates a 6-digit code, stores it in Redis with 10 min TTL, emails it.
|
|
49
|
+
- Returns `{ challenge: email }` in a signed envelope.
|
|
50
|
+
|
|
51
|
+
**Authenticate** — client sends `{ challenge: <signed-envelope>, userId: email, credential: '123456', entityId: 'the-entity' }`:
|
|
52
|
+
- Envelope is opened → email is extracted.
|
|
53
|
+
- OTP service verifies the code (throws `AuthenFailed` if wrong or expired), then deletes it.
|
|
54
|
+
- `IdentityLinkingService` finds or creates the user profile scoped to `entityId`.
|
|
55
|
+
- Sets `credential.type = AuthenticationType.OneTimeToken` and returns the signed auth token.
|
|
56
|
+
|
|
57
|
+
## Config overrides (optional)
|
|
58
|
+
|
|
59
|
+
Pass `ctx.cfg.otp` to override defaults:
|
|
60
|
+
|
|
61
|
+
```ts
|
|
62
|
+
cfg.otp = {
|
|
63
|
+
mailerAlias: 'my-mailer', // default: MAILER_SERVICE ('mailer-service')
|
|
64
|
+
resourceAlias: 'my-otp-cache', // default: OTP_RESOURCE ('auth-otp-cache')
|
|
65
|
+
identityAlias: 'my-identity', // default: AUTH_IDENTITY_LINKING
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Rules
|
|
70
|
+
|
|
71
|
+
- Always register the Redis resource AND the mailer service BEFORE the OTP service.
|
|
72
|
+
- Call `appendOtpPlugin(context)` once per context — it adds to the shared plugin registry singleton.
|
|
73
|
+
- The `credential.entityId` in the authenticate request determines which entity the resulting identity profile is scoped to. Pass it from the OIDC interaction.
|
|
74
|
+
- Errors from this plugin are `AuthenFailed` (from `@owlmeans/auth`) — callers catch that, not raw `Error`.
|
|
75
|
+
- For tests, use `makeConsoleMailerService()` and read `svc.captured[n].text` to extract the code.
|
|
76
|
+
|
|
77
|
+
## Related instructions
|
|
78
|
+
|
|
79
|
+
- `@owlmeans/auth-otp` (common) — `OtpService` interface and constants
|
|
80
|
+
- `@owlmeans/mailer` (common) — `MailerService` interface, console transport
|
|
81
|
+
- `@owlmeans/server-mailer-mailgun` (common) — production Mailgun transport
|
|
82
|
+
- `@owlmeans/server-auth` (common) — auth-manager plugin system
|
|
83
|
+
- `auth-protocol` instructions — error hierarchy, identity read rules
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"package": "@owlmeans/server-auth-otp",
|
|
4
|
+
"version": "0.1.8",
|
|
5
|
+
"generatedAt": "2026-06-11T16:30:27.191Z",
|
|
6
|
+
"canonicalRepo": "https://github.com/owlmeans/common",
|
|
7
|
+
"entries": [
|
|
8
|
+
{
|
|
9
|
+
"kind": "instruction",
|
|
10
|
+
"name": "server-auth-otp",
|
|
11
|
+
"category": "package-specific",
|
|
12
|
+
"file": "instructions/server-auth-otp.instructions.md",
|
|
13
|
+
"canonicalPath": ".github/instructions/server-auth-otp.instructions.md"
|
|
14
|
+
}
|
|
15
|
+
]
|
|
16
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@owlmeans/server-auth-otp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -22,17 +22,17 @@
|
|
|
22
22
|
}
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@owlmeans/auth": "^0.1.
|
|
26
|
-
"@owlmeans/auth-otp": "^0.1.
|
|
27
|
-
"@owlmeans/basic-ids": "^0.1.
|
|
28
|
-
"@owlmeans/context": "^0.1.
|
|
29
|
-
"@owlmeans/mailer": "^0.1.
|
|
30
|
-
"@owlmeans/oidc": "^0.1.
|
|
31
|
-
"@owlmeans/redis-resource": "^0.1.
|
|
32
|
-
"@owlmeans/resource": "^0.1.
|
|
33
|
-
"@owlmeans/server-auth": "^0.1.
|
|
34
|
-
"@owlmeans/server-auth-identity": "^0.1.
|
|
35
|
-
"@owlmeans/server-context": "^0.1.
|
|
25
|
+
"@owlmeans/auth": "^0.1.8",
|
|
26
|
+
"@owlmeans/auth-otp": "^0.1.8",
|
|
27
|
+
"@owlmeans/basic-ids": "^0.1.8",
|
|
28
|
+
"@owlmeans/context": "^0.1.8",
|
|
29
|
+
"@owlmeans/mailer": "^0.1.8",
|
|
30
|
+
"@owlmeans/oidc": "^0.1.8",
|
|
31
|
+
"@owlmeans/redis-resource": "^0.1.8",
|
|
32
|
+
"@owlmeans/resource": "^0.1.8",
|
|
33
|
+
"@owlmeans/server-auth": "^0.1.8",
|
|
34
|
+
"@owlmeans/server-auth-identity": "^0.1.8",
|
|
35
|
+
"@owlmeans/server-context": "^0.1.8"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"@owlmeans/dep-config": "workspace:*",
|