@jskit-ai/auth-core 0.1.4
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/package.descriptor.mjs +95 -0
- package/package.json +51 -0
- package/src/client/authApi.js +1 -0
- package/src/client/index.js +2 -0
- package/src/client/providers/AccessCoreClientProvider.js +23 -0
- package/src/client/providers/FastifyAuthPolicyClientProvider.js +13 -0
- package/src/client/signOutFlow.js +1 -0
- package/src/server/inviteTokens.js +41 -0
- package/src/server/lib/actionContextContributor.js +36 -0
- package/src/server/lib/authPolicySupport.js +38 -0
- package/src/server/lib/errors.js +20 -0
- package/src/server/lib/index.js +3 -0
- package/src/server/lib/objectUtils.js +5 -0
- package/src/server/lib/plugin.js +247 -0
- package/src/server/lib/routeMeta.js +64 -0
- package/src/server/lib/routeVisibilityResolver.js +25 -0
- package/src/server/lib/tokens.js +3 -0
- package/src/server/membershipAccess.js +67 -0
- package/src/server/providers/AccessCoreServiceProvider.js +35 -0
- package/src/server/providers/FastifyAuthPolicyServiceProvider.js +124 -0
- package/src/server/utils.js +26 -0
- package/src/server/validators.js +183 -0
- package/src/shared/authApi.js +50 -0
- package/src/shared/authConstraints.js +13 -0
- package/src/shared/authMethods.js +170 -0
- package/src/shared/authPaths.js +24 -0
- package/src/shared/commands/authCommandValidators.js +255 -0
- package/src/shared/commands/authLoginOAuthCompleteCommand.js +68 -0
- package/src/shared/commands/authLoginOAuthStartCommand.js +72 -0
- package/src/shared/commands/authLoginOtpRequestCommand.js +56 -0
- package/src/shared/commands/authLoginOtpVerifyCommand.js +64 -0
- package/src/shared/commands/authLoginPasswordCommand.js +57 -0
- package/src/shared/commands/authLogoutCommand.js +23 -0
- package/src/shared/commands/authPasswordRecoveryCompleteCommand.js +67 -0
- package/src/shared/commands/authPasswordResetCommand.js +49 -0
- package/src/shared/commands/authPasswordResetRequestCommand.js +50 -0
- package/src/shared/commands/authRegisterCommand.js +57 -0
- package/src/shared/commands/authSessionReadCommand.js +26 -0
- package/src/shared/index.js +3 -0
- package/src/shared/inputNormalization.js +1 -0
- package/src/shared/inviteTokens.js +38 -0
- package/src/shared/oauthCallbackParams.js +5 -0
- package/src/shared/oauthProviders.js +66 -0
- package/src/shared/signOutFlow.js +28 -0
- package/test/actionContextContributor.test.js +44 -0
- package/test/authApi.test.js +47 -0
- package/test/authMethods.test.js +95 -0
- package/test/authPaths.test.js +17 -0
- package/test/commandValidators.test.js +33 -0
- package/test/plugin.test.js +250 -0
- package/test/providerRuntime.test.js +114 -0
- package/test/routeMeta.test.js +95 -0
- package/test/routeVisibilityResolver.test.js +34 -0
- package/test/serverUtils.test.js +28 -0
- package/test/signOutFlow.test.js +67 -0
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
import { Type } from "typebox";
|
|
2
|
+
import {
|
|
3
|
+
AUTH_ACCESS_TOKEN_MAX_LENGTH,
|
|
4
|
+
AUTH_EMAIL_MAX_LENGTH,
|
|
5
|
+
AUTH_EMAIL_MIN_LENGTH,
|
|
6
|
+
AUTH_EMAIL_PATTERN,
|
|
7
|
+
AUTH_LOGIN_PASSWORD_MAX_LENGTH,
|
|
8
|
+
AUTH_PASSWORD_MAX_LENGTH,
|
|
9
|
+
AUTH_PASSWORD_MIN_LENGTH,
|
|
10
|
+
AUTH_RECOVERY_TOKEN_MAX_LENGTH,
|
|
11
|
+
AUTH_REFRESH_TOKEN_MAX_LENGTH
|
|
12
|
+
} from "../authConstraints.js";
|
|
13
|
+
import { AUTH_METHOD_IDS, AUTH_METHOD_KINDS } from "../authMethods.js";
|
|
14
|
+
import { OAUTH_PROVIDER_ID_PATTERN } from "../oauthProviders.js";
|
|
15
|
+
|
|
16
|
+
const oauthProviderValidator = Object.freeze({
|
|
17
|
+
schema: Type.String({
|
|
18
|
+
minLength: 2,
|
|
19
|
+
maxLength: 32,
|
|
20
|
+
pattern: OAUTH_PROVIDER_ID_PATTERN
|
|
21
|
+
})
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
const authMethodIdValidator = Object.freeze({
|
|
25
|
+
schema: Type.String({
|
|
26
|
+
minLength: 3,
|
|
27
|
+
maxLength: 38,
|
|
28
|
+
pattern: `^(?:${AUTH_METHOD_IDS.join("|")}|oauth:${OAUTH_PROVIDER_ID_PATTERN.slice(1, -1)})$`
|
|
29
|
+
})
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
const authMethodKindValidator = Object.freeze({
|
|
33
|
+
schema: Type.Union(AUTH_METHOD_KINDS.map((kind) => Type.Literal(kind)))
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const OAUTH_RETURN_TO_PATTERN = "^(?:/(?!/).*$|https?://[^\\s]+)$";
|
|
37
|
+
|
|
38
|
+
const oauthReturnToValidator = Object.freeze({
|
|
39
|
+
schema: Type.String({
|
|
40
|
+
minLength: 1,
|
|
41
|
+
maxLength: 1024,
|
|
42
|
+
pattern: OAUTH_RETURN_TO_PATTERN
|
|
43
|
+
})
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
const authEmailValidator = Object.freeze({
|
|
47
|
+
schema: Type.String({
|
|
48
|
+
minLength: AUTH_EMAIL_MIN_LENGTH,
|
|
49
|
+
maxLength: AUTH_EMAIL_MAX_LENGTH,
|
|
50
|
+
pattern: AUTH_EMAIL_PATTERN
|
|
51
|
+
})
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
const authPasswordValidator = Object.freeze({
|
|
55
|
+
schema: Type.String({
|
|
56
|
+
minLength: AUTH_PASSWORD_MIN_LENGTH,
|
|
57
|
+
maxLength: AUTH_PASSWORD_MAX_LENGTH
|
|
58
|
+
})
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
const authLoginPasswordValidator = Object.freeze({
|
|
62
|
+
schema: Type.String({
|
|
63
|
+
minLength: 1,
|
|
64
|
+
maxLength: AUTH_LOGIN_PASSWORD_MAX_LENGTH
|
|
65
|
+
})
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
const authRecoveryTokenValidator = Object.freeze({
|
|
69
|
+
schema: Type.String({
|
|
70
|
+
minLength: 1,
|
|
71
|
+
maxLength: AUTH_RECOVERY_TOKEN_MAX_LENGTH
|
|
72
|
+
})
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
const authAccessTokenValidator = Object.freeze({
|
|
76
|
+
schema: Type.String({
|
|
77
|
+
minLength: 1,
|
|
78
|
+
maxLength: AUTH_ACCESS_TOKEN_MAX_LENGTH
|
|
79
|
+
})
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
const authRefreshTokenValidator = Object.freeze({
|
|
83
|
+
schema: Type.String({
|
|
84
|
+
minLength: 1,
|
|
85
|
+
maxLength: AUTH_REFRESH_TOKEN_MAX_LENGTH
|
|
86
|
+
})
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
const okResponseValidator = Object.freeze({
|
|
90
|
+
schema: Type.Object(
|
|
91
|
+
{
|
|
92
|
+
ok: Type.Boolean()
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
additionalProperties: false
|
|
96
|
+
}
|
|
97
|
+
)
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
const okMessageResponseValidator = Object.freeze({
|
|
101
|
+
schema: Type.Object(
|
|
102
|
+
{
|
|
103
|
+
ok: Type.Boolean(),
|
|
104
|
+
message: Type.String({ minLength: 1 })
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
additionalProperties: false
|
|
108
|
+
}
|
|
109
|
+
)
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
const registerResponseValidator = Object.freeze({
|
|
113
|
+
schema: Type.Object(
|
|
114
|
+
{
|
|
115
|
+
ok: Type.Boolean(),
|
|
116
|
+
requiresEmailConfirmation: Type.Boolean(),
|
|
117
|
+
username: Type.Optional(Type.String({ minLength: 1, maxLength: 120 })),
|
|
118
|
+
message: Type.Optional(Type.String({ minLength: 1 }))
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
additionalProperties: false
|
|
122
|
+
}
|
|
123
|
+
)
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
const loginResponseValidator = Object.freeze({
|
|
127
|
+
schema: Type.Object(
|
|
128
|
+
{
|
|
129
|
+
ok: Type.Boolean(),
|
|
130
|
+
username: Type.String({ minLength: 1, maxLength: 120 })
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
additionalProperties: false
|
|
134
|
+
}
|
|
135
|
+
)
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
const otpVerifyResponseValidator = Object.freeze({
|
|
139
|
+
schema: Type.Object(
|
|
140
|
+
{
|
|
141
|
+
ok: Type.Boolean(),
|
|
142
|
+
username: Type.String({ minLength: 1, maxLength: 120 }),
|
|
143
|
+
email: authEmailValidator.schema
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
additionalProperties: false
|
|
147
|
+
}
|
|
148
|
+
)
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
const oauthCompleteResponseValidator = Object.freeze({
|
|
152
|
+
schema: Type.Object(
|
|
153
|
+
{
|
|
154
|
+
ok: Type.Boolean(),
|
|
155
|
+
provider: oauthProviderValidator.schema,
|
|
156
|
+
username: Type.String({ minLength: 1, maxLength: 120 }),
|
|
157
|
+
email: authEmailValidator.schema
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
additionalProperties: false
|
|
161
|
+
}
|
|
162
|
+
)
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
const logoutResponseValidator = Object.freeze({
|
|
166
|
+
schema: Type.Object(
|
|
167
|
+
{
|
|
168
|
+
ok: Type.Boolean()
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
additionalProperties: false
|
|
172
|
+
}
|
|
173
|
+
)
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
const oauthProviderCatalogEntryValidator = Object.freeze({
|
|
177
|
+
schema: Type.Object(
|
|
178
|
+
{
|
|
179
|
+
id: oauthProviderValidator.schema,
|
|
180
|
+
label: Type.String({ minLength: 1, maxLength: 120 })
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
additionalProperties: false
|
|
184
|
+
}
|
|
185
|
+
)
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
const sessionResponseValidator = Object.freeze({
|
|
189
|
+
schema: Type.Object(
|
|
190
|
+
{
|
|
191
|
+
authenticated: Type.Boolean(),
|
|
192
|
+
username: Type.Optional(Type.String({ minLength: 1, maxLength: 120 })),
|
|
193
|
+
csrfToken: Type.String({ minLength: 1 }),
|
|
194
|
+
oauthProviders: Type.Array(oauthProviderCatalogEntryValidator.schema),
|
|
195
|
+
oauthDefaultProvider: Type.Union([oauthProviderValidator.schema, Type.Null()])
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
additionalProperties: false
|
|
199
|
+
}
|
|
200
|
+
)
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
const sessionUnavailableResponseValidator = Object.freeze({
|
|
204
|
+
schema: Type.Object(
|
|
205
|
+
{
|
|
206
|
+
error: Type.String({ minLength: 1 }),
|
|
207
|
+
csrfToken: Type.String({ minLength: 1 }),
|
|
208
|
+
oauthProviders: Type.Array(oauthProviderCatalogEntryValidator.schema),
|
|
209
|
+
oauthDefaultProvider: Type.Union([oauthProviderValidator.schema, Type.Null()])
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
additionalProperties: false
|
|
213
|
+
}
|
|
214
|
+
)
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
function createCommandMessages({
|
|
218
|
+
fields = {},
|
|
219
|
+
defaultMessage = "Invalid value."
|
|
220
|
+
} = {}) {
|
|
221
|
+
return Object.freeze({
|
|
222
|
+
apiValidation: "Validation failed.",
|
|
223
|
+
fields: Object.freeze({
|
|
224
|
+
...(fields && typeof fields === "object" ? fields : {})
|
|
225
|
+
}),
|
|
226
|
+
keywords: Object.freeze({
|
|
227
|
+
additionalProperties: "Unexpected field."
|
|
228
|
+
}),
|
|
229
|
+
default: String(defaultMessage || "Invalid value.")
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
export {
|
|
234
|
+
authEmailValidator,
|
|
235
|
+
authPasswordValidator,
|
|
236
|
+
authLoginPasswordValidator,
|
|
237
|
+
authRecoveryTokenValidator,
|
|
238
|
+
authAccessTokenValidator,
|
|
239
|
+
authRefreshTokenValidator,
|
|
240
|
+
oauthProviderValidator,
|
|
241
|
+
authMethodIdValidator,
|
|
242
|
+
authMethodKindValidator,
|
|
243
|
+
oauthReturnToValidator,
|
|
244
|
+
okResponseValidator,
|
|
245
|
+
okMessageResponseValidator,
|
|
246
|
+
registerResponseValidator,
|
|
247
|
+
loginResponseValidator,
|
|
248
|
+
otpVerifyResponseValidator,
|
|
249
|
+
oauthCompleteResponseValidator,
|
|
250
|
+
logoutResponseValidator,
|
|
251
|
+
oauthProviderCatalogEntryValidator,
|
|
252
|
+
sessionResponseValidator,
|
|
253
|
+
sessionUnavailableResponseValidator,
|
|
254
|
+
createCommandMessages
|
|
255
|
+
};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { Type } from "typebox";
|
|
2
|
+
import { normalizeObjectInput } from "../inputNormalization.js";
|
|
3
|
+
import {
|
|
4
|
+
authAccessTokenValidator,
|
|
5
|
+
authRecoveryTokenValidator,
|
|
6
|
+
authRefreshTokenValidator,
|
|
7
|
+
createCommandMessages,
|
|
8
|
+
oauthCompleteResponseValidator,
|
|
9
|
+
oauthProviderValidator
|
|
10
|
+
} from "./authCommandValidators.js";
|
|
11
|
+
|
|
12
|
+
const AUTH_LOGIN_OAUTH_COMPLETE_MESSAGES = createCommandMessages({
|
|
13
|
+
fields: {
|
|
14
|
+
provider: {
|
|
15
|
+
required: "OAuth provider is required.",
|
|
16
|
+
pattern: "OAuth provider id is invalid.",
|
|
17
|
+
default: "OAuth provider id is invalid."
|
|
18
|
+
},
|
|
19
|
+
code: {
|
|
20
|
+
default: "OAuth code is invalid."
|
|
21
|
+
},
|
|
22
|
+
accessToken: {
|
|
23
|
+
default: "Access token is invalid."
|
|
24
|
+
},
|
|
25
|
+
refreshToken: {
|
|
26
|
+
default: "Refresh token is invalid."
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const authLoginOAuthCompleteBodyValidator = Object.freeze({
|
|
32
|
+
schema: Type.Object(
|
|
33
|
+
{
|
|
34
|
+
provider: oauthProviderValidator.schema,
|
|
35
|
+
code: Type.Optional(authRecoveryTokenValidator.schema),
|
|
36
|
+
accessToken: Type.Optional(authAccessTokenValidator.schema),
|
|
37
|
+
refreshToken: Type.Optional(authRefreshTokenValidator.schema),
|
|
38
|
+
error: Type.Optional(Type.String({ minLength: 1, maxLength: 128 })),
|
|
39
|
+
errorDescription: Type.Optional(Type.String({ minLength: 1, maxLength: 1024 })),
|
|
40
|
+
error_code: Type.Optional(Type.String({ minLength: 1, maxLength: 128 })),
|
|
41
|
+
error_description: Type.Optional(Type.String({ minLength: 1, maxLength: 1024 }))
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
additionalProperties: false
|
|
45
|
+
}
|
|
46
|
+
),
|
|
47
|
+
normalize: normalizeObjectInput,
|
|
48
|
+
messages: AUTH_LOGIN_OAUTH_COMPLETE_MESSAGES
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
const authLoginOAuthCompleteCommand = Object.freeze({
|
|
52
|
+
command: "auth.login.oauth.complete",
|
|
53
|
+
operation: Object.freeze({
|
|
54
|
+
method: "POST",
|
|
55
|
+
bodyValidator: authLoginOAuthCompleteBodyValidator,
|
|
56
|
+
responseValidator: oauthCompleteResponseValidator,
|
|
57
|
+
messages: AUTH_LOGIN_OAUTH_COMPLETE_MESSAGES,
|
|
58
|
+
idempotent: false,
|
|
59
|
+
invalidates: Object.freeze(["auth.session.read"])
|
|
60
|
+
})
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
export {
|
|
64
|
+
authLoginOAuthCompleteBodyValidator,
|
|
65
|
+
oauthCompleteResponseValidator,
|
|
66
|
+
AUTH_LOGIN_OAUTH_COMPLETE_MESSAGES,
|
|
67
|
+
authLoginOAuthCompleteCommand
|
|
68
|
+
};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { Type } from "typebox";
|
|
2
|
+
import { normalizeObjectInput } from "../inputNormalization.js";
|
|
3
|
+
import {
|
|
4
|
+
createCommandMessages,
|
|
5
|
+
oauthProviderValidator,
|
|
6
|
+
oauthReturnToValidator
|
|
7
|
+
} from "./authCommandValidators.js";
|
|
8
|
+
|
|
9
|
+
const AUTH_LOGIN_OAUTH_START_MESSAGES = createCommandMessages({
|
|
10
|
+
fields: {
|
|
11
|
+
provider: {
|
|
12
|
+
required: "OAuth provider is required.",
|
|
13
|
+
pattern: "OAuth provider id is invalid.",
|
|
14
|
+
default: "OAuth provider id is invalid."
|
|
15
|
+
},
|
|
16
|
+
returnTo: {
|
|
17
|
+
pattern: "Return target must be an absolute path or URL.",
|
|
18
|
+
default: "Return target must be an absolute path or URL."
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const authLoginOAuthStartParamsValidator = Object.freeze({
|
|
24
|
+
schema: Type.Object(
|
|
25
|
+
{
|
|
26
|
+
provider: oauthProviderValidator.schema
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
additionalProperties: false
|
|
30
|
+
}
|
|
31
|
+
),
|
|
32
|
+
normalize: normalizeObjectInput,
|
|
33
|
+
messages: AUTH_LOGIN_OAUTH_START_MESSAGES
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const authLoginOAuthStartQueryValidator = Object.freeze({
|
|
37
|
+
schema: Type.Object(
|
|
38
|
+
{
|
|
39
|
+
returnTo: Type.Optional(oauthReturnToValidator.schema)
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
additionalProperties: false
|
|
43
|
+
}
|
|
44
|
+
),
|
|
45
|
+
normalize: normalizeObjectInput,
|
|
46
|
+
messages: AUTH_LOGIN_OAUTH_START_MESSAGES
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
const authLoginOAuthStartResponseValidator = Object.freeze({
|
|
50
|
+
schema: Type.Unknown()
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const authLoginOAuthStartCommand = Object.freeze({
|
|
54
|
+
command: "auth.login.oauth.start",
|
|
55
|
+
operation: Object.freeze({
|
|
56
|
+
method: "GET",
|
|
57
|
+
paramsValidator: authLoginOAuthStartParamsValidator,
|
|
58
|
+
queryValidator: authLoginOAuthStartQueryValidator,
|
|
59
|
+
responseValidator: authLoginOAuthStartResponseValidator,
|
|
60
|
+
messages: AUTH_LOGIN_OAUTH_START_MESSAGES,
|
|
61
|
+
idempotent: true,
|
|
62
|
+
invalidates: Object.freeze([])
|
|
63
|
+
})
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
export {
|
|
67
|
+
authLoginOAuthStartParamsValidator,
|
|
68
|
+
authLoginOAuthStartQueryValidator,
|
|
69
|
+
authLoginOAuthStartResponseValidator,
|
|
70
|
+
AUTH_LOGIN_OAUTH_START_MESSAGES,
|
|
71
|
+
authLoginOAuthStartCommand
|
|
72
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { Type } from "typebox";
|
|
2
|
+
import { normalizeObjectInput } from "../inputNormalization.js";
|
|
3
|
+
import {
|
|
4
|
+
authEmailValidator,
|
|
5
|
+
createCommandMessages,
|
|
6
|
+
oauthReturnToValidator,
|
|
7
|
+
okMessageResponseValidator
|
|
8
|
+
} from "./authCommandValidators.js";
|
|
9
|
+
|
|
10
|
+
const AUTH_LOGIN_OTP_REQUEST_MESSAGES = createCommandMessages({
|
|
11
|
+
fields: {
|
|
12
|
+
email: {
|
|
13
|
+
required: "Email is required.",
|
|
14
|
+
minLength: "Email is required.",
|
|
15
|
+
pattern: "Enter a valid email address.",
|
|
16
|
+
default: "Enter a valid email address."
|
|
17
|
+
},
|
|
18
|
+
returnTo: {
|
|
19
|
+
pattern: "Return target must be an absolute path or URL.",
|
|
20
|
+
default: "Return target must be an absolute path or URL."
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const authLoginOtpRequestBodyValidator = Object.freeze({
|
|
26
|
+
schema: Type.Object(
|
|
27
|
+
{
|
|
28
|
+
email: authEmailValidator.schema,
|
|
29
|
+
returnTo: Type.Optional(oauthReturnToValidator.schema)
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
additionalProperties: false
|
|
33
|
+
}
|
|
34
|
+
),
|
|
35
|
+
normalize: normalizeObjectInput,
|
|
36
|
+
messages: AUTH_LOGIN_OTP_REQUEST_MESSAGES
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const authLoginOtpRequestCommand = Object.freeze({
|
|
40
|
+
command: "auth.login.otp.request",
|
|
41
|
+
operation: Object.freeze({
|
|
42
|
+
method: "POST",
|
|
43
|
+
bodyValidator: authLoginOtpRequestBodyValidator,
|
|
44
|
+
responseValidator: okMessageResponseValidator,
|
|
45
|
+
messages: AUTH_LOGIN_OTP_REQUEST_MESSAGES,
|
|
46
|
+
idempotent: false,
|
|
47
|
+
invalidates: Object.freeze([])
|
|
48
|
+
})
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
export {
|
|
52
|
+
authLoginOtpRequestBodyValidator,
|
|
53
|
+
okMessageResponseValidator,
|
|
54
|
+
AUTH_LOGIN_OTP_REQUEST_MESSAGES,
|
|
55
|
+
authLoginOtpRequestCommand
|
|
56
|
+
};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { Type } from "typebox";
|
|
2
|
+
import { normalizeObjectInput } from "../inputNormalization.js";
|
|
3
|
+
import {
|
|
4
|
+
authEmailValidator,
|
|
5
|
+
authRecoveryTokenValidator,
|
|
6
|
+
createCommandMessages,
|
|
7
|
+
otpVerifyResponseValidator
|
|
8
|
+
} from "./authCommandValidators.js";
|
|
9
|
+
|
|
10
|
+
const AUTH_LOGIN_OTP_VERIFY_MESSAGES = createCommandMessages({
|
|
11
|
+
fields: {
|
|
12
|
+
email: {
|
|
13
|
+
pattern: "Enter a valid email address.",
|
|
14
|
+
default: "Enter a valid email address."
|
|
15
|
+
},
|
|
16
|
+
token: {
|
|
17
|
+
minLength: "One-time code is required.",
|
|
18
|
+
default: "One-time code is required."
|
|
19
|
+
},
|
|
20
|
+
tokenHash: {
|
|
21
|
+
default: "One-time token hash is invalid."
|
|
22
|
+
},
|
|
23
|
+
type: {
|
|
24
|
+
const: "Only email OTP verification is supported.",
|
|
25
|
+
default: "Only email OTP verification is supported."
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
const authLoginOtpVerifyBodyValidator = Object.freeze({
|
|
31
|
+
schema: Type.Object(
|
|
32
|
+
{
|
|
33
|
+
email: Type.Optional(authEmailValidator.schema),
|
|
34
|
+
token: Type.Optional(authRecoveryTokenValidator.schema),
|
|
35
|
+
tokenHash: Type.Optional(authRecoveryTokenValidator.schema),
|
|
36
|
+
type: Type.Optional(Type.Literal("email"))
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
additionalProperties: false,
|
|
40
|
+
minProperties: 1
|
|
41
|
+
}
|
|
42
|
+
),
|
|
43
|
+
normalize: normalizeObjectInput,
|
|
44
|
+
messages: AUTH_LOGIN_OTP_VERIFY_MESSAGES
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
const authLoginOtpVerifyCommand = Object.freeze({
|
|
48
|
+
command: "auth.login.otp.verify",
|
|
49
|
+
operation: Object.freeze({
|
|
50
|
+
method: "POST",
|
|
51
|
+
bodyValidator: authLoginOtpVerifyBodyValidator,
|
|
52
|
+
responseValidator: otpVerifyResponseValidator,
|
|
53
|
+
messages: AUTH_LOGIN_OTP_VERIFY_MESSAGES,
|
|
54
|
+
idempotent: false,
|
|
55
|
+
invalidates: Object.freeze(["auth.session.read"])
|
|
56
|
+
})
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
export {
|
|
60
|
+
authLoginOtpVerifyBodyValidator,
|
|
61
|
+
otpVerifyResponseValidator,
|
|
62
|
+
AUTH_LOGIN_OTP_VERIFY_MESSAGES,
|
|
63
|
+
authLoginOtpVerifyCommand
|
|
64
|
+
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { Type } from "typebox";
|
|
2
|
+
import { normalizeObjectInput } from "../inputNormalization.js";
|
|
3
|
+
import {
|
|
4
|
+
authEmailValidator,
|
|
5
|
+
authLoginPasswordValidator,
|
|
6
|
+
createCommandMessages,
|
|
7
|
+
loginResponseValidator
|
|
8
|
+
} from "./authCommandValidators.js";
|
|
9
|
+
|
|
10
|
+
const AUTH_LOGIN_PASSWORD_MESSAGES = createCommandMessages({
|
|
11
|
+
fields: {
|
|
12
|
+
email: {
|
|
13
|
+
required: "Email is required.",
|
|
14
|
+
minLength: "Email is required.",
|
|
15
|
+
pattern: "Enter a valid email address.",
|
|
16
|
+
default: "Enter a valid email address."
|
|
17
|
+
},
|
|
18
|
+
password: {
|
|
19
|
+
required: "Password is required.",
|
|
20
|
+
minLength: "Password is required.",
|
|
21
|
+
default: "Password is required."
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const authLoginPasswordBodyValidator = Object.freeze({
|
|
27
|
+
schema: Type.Object(
|
|
28
|
+
{
|
|
29
|
+
email: authEmailValidator.schema,
|
|
30
|
+
password: authLoginPasswordValidator.schema
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
additionalProperties: false
|
|
34
|
+
}
|
|
35
|
+
),
|
|
36
|
+
normalize: normalizeObjectInput,
|
|
37
|
+
messages: AUTH_LOGIN_PASSWORD_MESSAGES
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const authLoginPasswordCommand = Object.freeze({
|
|
41
|
+
command: "auth.login.password",
|
|
42
|
+
operation: Object.freeze({
|
|
43
|
+
method: "POST",
|
|
44
|
+
bodyValidator: authLoginPasswordBodyValidator,
|
|
45
|
+
responseValidator: loginResponseValidator,
|
|
46
|
+
messages: AUTH_LOGIN_PASSWORD_MESSAGES,
|
|
47
|
+
idempotent: false,
|
|
48
|
+
invalidates: Object.freeze(["auth.session.read"])
|
|
49
|
+
})
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
export {
|
|
53
|
+
authLoginPasswordBodyValidator,
|
|
54
|
+
loginResponseValidator,
|
|
55
|
+
AUTH_LOGIN_PASSWORD_MESSAGES,
|
|
56
|
+
authLoginPasswordCommand
|
|
57
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createCommandMessages,
|
|
3
|
+
logoutResponseValidator
|
|
4
|
+
} from "./authCommandValidators.js";
|
|
5
|
+
|
|
6
|
+
const AUTH_LOGOUT_MESSAGES = createCommandMessages();
|
|
7
|
+
|
|
8
|
+
const authLogoutCommand = Object.freeze({
|
|
9
|
+
command: "auth.logout",
|
|
10
|
+
operation: Object.freeze({
|
|
11
|
+
method: "POST",
|
|
12
|
+
responseValidator: logoutResponseValidator,
|
|
13
|
+
messages: AUTH_LOGOUT_MESSAGES,
|
|
14
|
+
idempotent: false,
|
|
15
|
+
invalidates: Object.freeze(["auth.session.read"])
|
|
16
|
+
})
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
export {
|
|
20
|
+
logoutResponseValidator,
|
|
21
|
+
AUTH_LOGOUT_MESSAGES,
|
|
22
|
+
authLogoutCommand
|
|
23
|
+
};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { Type } from "typebox";
|
|
2
|
+
import { normalizeObjectInput } from "../inputNormalization.js";
|
|
3
|
+
import {
|
|
4
|
+
authAccessTokenValidator,
|
|
5
|
+
authRecoveryTokenValidator,
|
|
6
|
+
authRefreshTokenValidator,
|
|
7
|
+
createCommandMessages,
|
|
8
|
+
okResponseValidator
|
|
9
|
+
} from "./authCommandValidators.js";
|
|
10
|
+
|
|
11
|
+
const AUTH_PASSWORD_RECOVERY_COMPLETE_MESSAGES = createCommandMessages({
|
|
12
|
+
fields: {
|
|
13
|
+
code: {
|
|
14
|
+
default: "Recovery code is invalid."
|
|
15
|
+
},
|
|
16
|
+
tokenHash: {
|
|
17
|
+
default: "Recovery token hash is invalid."
|
|
18
|
+
},
|
|
19
|
+
accessToken: {
|
|
20
|
+
default: "Access token is invalid."
|
|
21
|
+
},
|
|
22
|
+
refreshToken: {
|
|
23
|
+
default: "Refresh token is invalid."
|
|
24
|
+
},
|
|
25
|
+
type: {
|
|
26
|
+
const: "Only recovery links are supported.",
|
|
27
|
+
default: "Only recovery links are supported."
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
const authPasswordRecoveryCompleteBodyValidator = Object.freeze({
|
|
33
|
+
schema: Type.Object(
|
|
34
|
+
{
|
|
35
|
+
code: Type.Optional(authRecoveryTokenValidator.schema),
|
|
36
|
+
tokenHash: Type.Optional(authRecoveryTokenValidator.schema),
|
|
37
|
+
accessToken: Type.Optional(authAccessTokenValidator.schema),
|
|
38
|
+
refreshToken: Type.Optional(authRefreshTokenValidator.schema),
|
|
39
|
+
type: Type.Optional(Type.Literal("recovery"))
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
additionalProperties: false,
|
|
43
|
+
minProperties: 1
|
|
44
|
+
}
|
|
45
|
+
),
|
|
46
|
+
normalize: normalizeObjectInput,
|
|
47
|
+
messages: AUTH_PASSWORD_RECOVERY_COMPLETE_MESSAGES
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
const authPasswordRecoveryCompleteCommand = Object.freeze({
|
|
51
|
+
command: "auth.password.recovery.complete",
|
|
52
|
+
operation: Object.freeze({
|
|
53
|
+
method: "POST",
|
|
54
|
+
bodyValidator: authPasswordRecoveryCompleteBodyValidator,
|
|
55
|
+
responseValidator: okResponseValidator,
|
|
56
|
+
messages: AUTH_PASSWORD_RECOVERY_COMPLETE_MESSAGES,
|
|
57
|
+
idempotent: false,
|
|
58
|
+
invalidates: Object.freeze(["auth.session.read"])
|
|
59
|
+
})
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
export {
|
|
63
|
+
authPasswordRecoveryCompleteBodyValidator,
|
|
64
|
+
okResponseValidator,
|
|
65
|
+
AUTH_PASSWORD_RECOVERY_COMPLETE_MESSAGES,
|
|
66
|
+
authPasswordRecoveryCompleteCommand
|
|
67
|
+
};
|