@absolutejs/auth 0.54.8 → 0.55.0

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.
Files changed (44) hide show
  1. package/README.md +19 -5
  2. package/dist/agents/config.d.ts +16 -0
  3. package/dist/agents/idJag.d.ts +49 -0
  4. package/dist/agents/inMemoryStores.d.ts +2 -1
  5. package/dist/agents/index.d.ts +5 -2
  6. package/dist/agents/index.js +1391 -66
  7. package/dist/agents/index.js.map +12 -8
  8. package/dist/agents/postgresStores.d.ts +280 -1
  9. package/dist/agents/registration.d.ts +162 -0
  10. package/dist/agents/registrationClient.d.ts +50 -0
  11. package/dist/agents/routes.d.ts +112 -1
  12. package/dist/agents/types.d.ts +59 -0
  13. package/dist/apikeys/routes.d.ts +2 -2
  14. package/dist/cli/migrate.js +57 -8
  15. package/dist/cli/migrate.js.map +4 -4
  16. package/dist/credentials/login.d.ts +4 -4
  17. package/dist/credentials/routes.d.ts +4 -4
  18. package/dist/index.d.ts +185 -2
  19. package/dist/index.js +1388 -102
  20. package/dist/index.js.map +15 -12
  21. package/dist/manifest.js +12 -6
  22. package/dist/manifest.js.map +4 -4
  23. package/dist/manifest.json +2 -2
  24. package/dist/mfa/routes.d.ts +2 -2
  25. package/dist/mfa/sms.d.ts +2 -2
  26. package/dist/oidc/clientAuth.d.ts +6 -2
  27. package/dist/oidc/config.d.ts +19 -5
  28. package/dist/oidc/keys.d.ts +7 -3
  29. package/dist/oidc/logout.d.ts +2 -2
  30. package/dist/oidc/routes.d.ts +13 -11
  31. package/dist/organizations/routes.d.ts +1 -1
  32. package/dist/portal/routes.d.ts +3 -3
  33. package/dist/roles/routes.d.ts +1 -1
  34. package/dist/routes/refresh.d.ts +1 -1
  35. package/dist/routes/revoke.d.ts +1 -1
  36. package/dist/routes/sessions.d.ts +3 -3
  37. package/dist/sso/discoveryRoute.d.ts +1 -1
  38. package/dist/sso/oidcRoutes.d.ts +2 -2
  39. package/dist/sso/samlRoutes.d.ts +4 -4
  40. package/docs/AGENT-AUTH.md +54 -0
  41. package/docs/MIGRATE-FROM-LUCIA.md +235 -0
  42. package/docs/OAUTH-PROVIDER-QUIRKS.md +150 -0
  43. package/docs/UI-COMPONENTS.md +226 -0
  44. package/package.json +7 -3
@@ -3,10 +3,10 @@
3
3
  "identity": {
4
4
  "accent": "#6366f1",
5
5
  "category": "auth",
6
- "description": "OAuth/OIDC sign-in for 60+ providers, email/password, magic links, passkeys, MFA, enterprise SSO/SCIM, organizations, roles, and API keys — one Elysia plugin backed by your Postgres database.",
6
+ "description": "OAuth/OIDC sign-in for people and AI agents, including open auth.md registration, scoped delegation, agent account linking, 60+ providers, passkeys, MFA, enterprise SSO/SCIM, organizations, roles, and API keys.",
7
7
  "docsUrl": "https://github.com/absolutejs/auth",
8
8
  "name": "@absolutejs/auth",
9
- "tagline": "Let people create accounts and sign in."
9
+ "tagline": "Let people and agents create accounts and sign in."
10
10
  },
11
11
  "implements": [
12
12
  {
@@ -138,10 +138,10 @@ export declare const mfaRoutes: <UserType>(config: MfaRouteProps<UserType>) => E
138
138
  response: {
139
139
  400: "Phone must be in E.164 format";
140
140
  401: "Authentication required";
141
- 501: "SMS MFA is not configured";
142
141
  200: {
143
142
  readonly phone: string;
144
143
  };
144
+ 501: "SMS MFA is not configured";
145
145
  422: {
146
146
  type: "validation";
147
147
  on: string;
@@ -169,6 +169,7 @@ export declare const mfaRoutes: <UserType>(config: MfaRouteProps<UserType>) => E
169
169
  200: {
170
170
  readonly status: "enrolled";
171
171
  };
172
+ 429: "Too many attempts";
172
173
  422: {
173
174
  type: "validation";
174
175
  on: string;
@@ -178,7 +179,6 @@ export declare const mfaRoutes: <UserType>(config: MfaRouteProps<UserType>) => E
178
179
  property?: string;
179
180
  expected?: string;
180
181
  };
181
- 429: "Too many attempts";
182
182
  };
183
183
  };
184
184
  };
package/dist/mfa/sms.d.ts CHANGED
@@ -40,10 +40,10 @@ export declare const mfaSmsRoutes: <UserType>({ authSessionStore, getUserId, mfa
40
40
  response: {
41
41
  400: "Phone must be in E.164 format";
42
42
  401: "Authentication required";
43
- 501: "SMS MFA is not configured";
44
43
  200: {
45
44
  readonly phone: string;
46
45
  };
46
+ 501: "SMS MFA is not configured";
47
47
  422: {
48
48
  type: "validation";
49
49
  on: string;
@@ -71,6 +71,7 @@ export declare const mfaSmsRoutes: <UserType>({ authSessionStore, getUserId, mfa
71
71
  200: {
72
72
  readonly status: "enrolled";
73
73
  };
74
+ 429: "Too many attempts";
74
75
  422: {
75
76
  type: "validation";
76
77
  on: string;
@@ -80,7 +81,6 @@ export declare const mfaSmsRoutes: <UserType>({ authSessionStore, getUserId, mfa
80
81
  property?: string;
81
82
  expected?: string;
82
83
  };
83
- 429: "Too many attempts";
84
84
  };
85
85
  };
86
86
  };
@@ -10,6 +10,10 @@ export declare const verifyJwtSignedByClient: ({ jwt, client }: {
10
10
  client: OAuthClient;
11
11
  jwt: string;
12
12
  }) => Promise<{
13
- header: any;
14
- payload: any;
13
+ header: {
14
+ [k: string]: any;
15
+ };
16
+ payload: {
17
+ [k: string]: any;
18
+ };
15
19
  } | undefined>;
@@ -4,7 +4,21 @@ import type { OnClientRegistered, OnClientRegistration } from './registration';
4
4
  import type { VciConfig } from './vci';
5
5
  import type { AuthorizationCodeStore, BackchannelAuthStore, ClientAssertionJtiStore, ClientRegistrationTokenStore, DeviceAuthorizationStore, InitialAccessTokenStore, LogoutDeliveryStore, OAuthClient, OAuthClientStore, OidcRefreshTokenStore, PushedAuthorizationRequestStore } from './types';
6
6
  export declare const DEFAULT_OIDC_ROUTE: RouteString;
7
+ export type PublicTokenGrantResult = {
8
+ body: Record<string, unknown>;
9
+ status: number;
10
+ };
7
11
  export type OidcProviderConfig<UserType> = {
12
+ /** Additional non-conflicting RFC 8414 metadata. Reserved core OAuth keys
13
+ * cannot be replaced. Used by profiles such as open agent registration. */
14
+ additionalDiscoveryMetadata?: Record<string, unknown>;
15
+ /** Public extension grants whose bearer material is carried in their body
16
+ * (for example an agent claim_token). They run before OAuth client auth. */
17
+ publicTokenGrantTypes?: string[];
18
+ handlePublicTokenGrant?: (context: {
19
+ body: Record<string, string | undefined>;
20
+ request: Request;
21
+ }) => Promise<PublicTokenGrantResult | undefined>;
8
22
  accessTokenTtlMs?: number | ((context: {
9
23
  scopes: string[];
10
24
  }) => number);
@@ -158,11 +172,11 @@ export declare const introspectToken: <UserType>({ config, hint, now, token }: {
158
172
  active: false;
159
173
  } | {
160
174
  active: true;
161
- client_id: any;
162
- exp: any;
163
- iat: any;
164
- scope: any;
165
- sub: any;
175
+ client_id: string;
176
+ exp: number;
177
+ iat: number;
178
+ scope: string;
179
+ sub: string;
166
180
  token_type: "access_token";
167
181
  } | {
168
182
  active: true;
@@ -5,7 +5,7 @@ export type SigningKey = {
5
5
  };
6
6
  export declare const generateSigningKey: () => Promise<SigningKey>;
7
7
  export declare const jwkThumbprint: (jwk: JsonWebKey) => Promise<string>;
8
- export declare const signJwt: (payload: Record<string, unknown>, signing: SigningKey) => Promise<string>;
8
+ export declare const signJwt: (payload: Record<string, unknown>, signing: SigningKey, typ?: string) => Promise<string>;
9
9
  export declare const toPublicJwk: (key: SigningKey) => {
10
10
  alg: string;
11
11
  crv: string | undefined;
@@ -16,6 +16,10 @@ export declare const toPublicJwk: (key: SigningKey) => {
16
16
  y: string | undefined;
17
17
  };
18
18
  export declare const verifyJwt: (token: string, publicJwk: JsonWebKey) => Promise<{
19
- header: any;
20
- payload: any;
19
+ header: {
20
+ [k: string]: any;
21
+ };
22
+ payload: {
23
+ [k: string]: any;
24
+ };
21
25
  } | undefined>;
@@ -8,8 +8,8 @@ export declare const verifyIdTokenHint: <UserType>({ config, idTokenHint }: {
8
8
  config: OidcProviderConfig<UserType>;
9
9
  idTokenHint: string;
10
10
  }) => Promise<{
11
- audClientId: any;
12
- sub: any;
11
+ audClientId: string;
12
+ sub: string;
13
13
  } | undefined>;
14
14
  type DeliveryFetch = (url: string, init: {
15
15
  body: string;
@@ -27,8 +27,8 @@ export declare const oidcProviderRoutes: <UserType>(config: OidcProviderConfig<U
27
27
  body: unknown;
28
28
  params: {};
29
29
  query: {
30
- client_id?: string | undefined;
31
30
  scope?: string | undefined;
31
+ client_id?: string | undefined;
32
32
  nonce?: string | undefined;
33
33
  claims?: string | undefined;
34
34
  request?: string | undefined;
@@ -63,15 +63,17 @@ export declare const oidcProviderRoutes: <UserType>(config: OidcProviderConfig<U
63
63
  [x: string]: {
64
64
  post: {
65
65
  body: {
66
+ grant_type?: string | undefined;
67
+ claim_token?: string | undefined;
68
+ scope?: string | undefined;
69
+ assertion?: string | undefined;
66
70
  resource?: string | undefined;
67
71
  client_id?: string | undefined;
68
- scope?: string | undefined;
69
72
  audience?: string | undefined;
70
73
  refresh_token?: string | undefined;
71
74
  device_code?: string | undefined;
72
75
  auth_req_id?: string | undefined;
73
76
  client_secret?: string | undefined;
74
- grant_type?: string | undefined;
75
77
  code?: string | undefined;
76
78
  redirect_uri?: string | undefined;
77
79
  client_assertion?: string | undefined;
@@ -102,9 +104,9 @@ export declare const oidcProviderRoutes: <UserType>(config: OidcProviderConfig<U
102
104
  [x: string]: {
103
105
  post: {
104
106
  body: {
107
+ scope?: string | undefined;
105
108
  resource?: string | undefined;
106
109
  client_id?: string | undefined;
107
- scope?: string | undefined;
108
110
  nonce?: string | undefined;
109
111
  audience?: string | undefined;
110
112
  claims?: string | undefined;
@@ -197,11 +199,11 @@ export declare const oidcProviderRoutes: <UserType>(config: OidcProviderConfig<U
197
199
  [x: string]: {
198
200
  post: {
199
201
  body: {
200
- client_id?: string | undefined;
201
202
  scope?: string | undefined;
203
+ client_id?: string | undefined;
202
204
  client_secret?: string | undefined;
203
- binding_message?: string | undefined;
204
205
  login_hint?: string | undefined;
206
+ binding_message?: string | undefined;
205
207
  };
206
208
  params: {};
207
209
  query: unknown;
@@ -226,8 +228,8 @@ export declare const oidcProviderRoutes: <UserType>(config: OidcProviderConfig<U
226
228
  [x: string]: {
227
229
  post: {
228
230
  body: {
229
- client_id?: string | undefined;
230
231
  scope?: string | undefined;
232
+ client_id?: string | undefined;
231
233
  client_secret?: string | undefined;
232
234
  };
233
235
  params: {};
@@ -329,8 +331,8 @@ export declare const oidcProviderRoutes: <UserType>(config: OidcProviderConfig<U
329
331
  [x: string]: {
330
332
  post: {
331
333
  body: {
332
- jwks?: any;
333
334
  scope?: string | undefined;
335
+ jwks?: any;
334
336
  backchannel_logout_uri?: string | undefined;
335
337
  client_name?: string | undefined;
336
338
  grant_types?: string[] | undefined;
@@ -389,8 +391,8 @@ export declare const oidcProviderRoutes: <UserType>(config: OidcProviderConfig<U
389
391
  ":clientId": {
390
392
  put: {
391
393
  body: {
392
- jwks?: any;
393
394
  scope?: string | undefined;
395
+ jwks?: any;
394
396
  backchannel_logout_uri?: string | undefined;
395
397
  client_name?: string | undefined;
396
398
  grant_types?: string[] | undefined;
@@ -526,7 +528,7 @@ export declare const oidcProviderRoutes: <UserType>(config: OidcProviderConfig<U
526
528
  query: unknown;
527
529
  headers: unknown;
528
530
  response: {
529
- 200: Record<string, string | boolean | string[]>;
531
+ 200: Record<string, unknown>;
530
532
  };
531
533
  };
532
534
  };
@@ -540,7 +542,7 @@ export declare const oidcProviderRoutes: <UserType>(config: OidcProviderConfig<U
540
542
  query: unknown;
541
543
  headers: unknown;
542
544
  response: {
543
- 200: Record<string, string | boolean | string[]>;
545
+ 200: Record<string, unknown>;
544
546
  };
545
547
  };
546
548
  };
@@ -162,10 +162,10 @@ export declare const organizationRoutes: <UserType>({ authSessionStore, canCreat
162
162
  response: {
163
163
  401: "Authentication required";
164
164
  403: "Cannot manage members";
165
- 404: "Invitation not found";
166
165
  200: {
167
166
  readonly revoked: string;
168
167
  };
168
+ 404: "Invitation not found";
169
169
  422: {
170
170
  type: "validation";
171
171
  on: string;
@@ -66,11 +66,11 @@ export declare const portalRoutes: ({ emit, onScimTokenCreated, onSsoConnectionC
66
66
  response: {
67
67
  401: "Invalid or expired setup link";
68
68
  403: "This setup link cannot configure SAML";
69
- 501: "SSO is not configured";
70
69
  200: {
71
70
  readonly configured: true;
72
71
  readonly type: "saml";
73
72
  };
73
+ 501: "SSO is not configured";
74
74
  422: {
75
75
  type: "validation";
76
76
  on: string;
@@ -103,11 +103,11 @@ export declare const portalRoutes: ({ emit, onScimTokenCreated, onSsoConnectionC
103
103
  response: {
104
104
  401: "Invalid or expired setup link";
105
105
  403: "This setup link cannot configure OIDC";
106
- 501: "SSO is not configured";
107
106
  200: {
108
107
  readonly configured: true;
109
108
  readonly type: "oidc";
110
109
  };
110
+ 501: "SSO is not configured";
111
111
  422: {
112
112
  type: "validation";
113
113
  on: string;
@@ -134,12 +134,12 @@ export declare const portalRoutes: ({ emit, onScimTokenCreated, onSsoConnectionC
134
134
  response: {
135
135
  401: "Invalid or expired setup link";
136
136
  403: "This setup link cannot configure SCIM";
137
- 501: "SCIM is not configured";
138
137
  200: {
139
138
  readonly baseUrl: `${string}/${string}`;
140
139
  readonly token: string;
141
140
  readonly tokenId: string;
142
141
  };
142
+ 501: "SCIM is not configured";
143
143
  };
144
144
  };
145
145
  };
@@ -66,10 +66,10 @@ export declare const roleRoutes: <UserType>({ authSessionStore, canManageRoles,
66
66
  response: {
67
67
  401: "Authentication required";
68
68
  403: "Cannot manage roles";
69
- 404: "Membership not found";
70
69
  200: {
71
70
  readonly roles: string[];
72
71
  };
72
+ 404: "Membership not found";
73
73
  422: {
74
74
  type: "validation";
75
75
  on: string;
@@ -37,8 +37,8 @@ export declare const refresh: <UserType>({ authSessionStore, clientProviders, re
37
37
  response: {
38
38
  400: "Cookies are missing" | "Invalid provider" | "No refresh token found";
39
39
  401: "Provider is required" | "Client provider not found" | "Client variant is required" | "Client variant not found" | "No auth provider found" | "No user session found";
40
- 501: "Provider is not refreshable";
41
40
  200: Response;
41
+ 501: "Provider is not refreshable";
42
42
  422: {
43
43
  type: "validation";
44
44
  on: string;
@@ -36,8 +36,8 @@ export declare const revoke: <UserType>({ authSessionStore, clientProviders, rev
36
36
  response: {
37
37
  400: "Cookies are missing" | "Invalid provider" | "Session has no access token to revoke";
38
38
  401: "Provider is required" | "Client provider not found" | "Client variant is required" | "Client variant not found" | "No auth provider found" | "No user session found";
39
- 501: "Provider does not support revocation";
40
39
  200: Response;
40
+ 501: "Provider does not support revocation";
41
41
  422: {
42
42
  type: "validation";
43
43
  on: string;
@@ -34,10 +34,10 @@ export declare const sessionRoutes: <UserType>({ authSessionStore, getUserId, se
34
34
  headers: unknown;
35
35
  response: {
36
36
  401: "Authentication required";
37
- 501: "Session management requires an authSessionStore";
38
37
  200: {
39
38
  readonly sessions: SessionSummary[];
40
39
  };
40
+ 501: "Session management requires an authSessionStore";
41
41
  422: {
42
42
  type: "validation";
43
43
  on: string;
@@ -63,11 +63,11 @@ export declare const sessionRoutes: <UserType>({ authSessionStore, getUserId, se
63
63
  response: {
64
64
  400: "Invalid session id";
65
65
  401: "Authentication required";
66
- 501: "Session management requires an authSessionStore";
67
- 404: "Session not found";
68
66
  200: {
69
67
  readonly revoked: `${string}-${string}-${string}-${string}-${string}`;
70
68
  };
69
+ 501: "Session management requires an authSessionStore";
70
+ 404: "Session not found";
71
71
  422: {
72
72
  type: "validation";
73
73
  on: string;
@@ -33,8 +33,8 @@ export declare const ssoDiscoveryRoute: ({ getOrganizationByEmailDomain, ssoConn
33
33
  headers: unknown;
34
34
  response: {
35
35
  400: "An \"email\" query parameter is required" | "A valid email address is required";
36
- 404: "No SSO organization is configured for this email domain" | "No SSO connection is configured for this organization";
37
36
  200: Response;
37
+ 404: "No SSO organization is configured for this email domain" | "No SSO connection is configured for this organization";
38
38
  422: {
39
39
  type: "validation";
40
40
  on: string;
@@ -33,8 +33,8 @@ export declare const oidcSsoRoutes: <UserType>({ authSessionStore, cookieSecure,
33
33
  query: unknown;
34
34
  headers: unknown;
35
35
  response: {
36
- 404: "No OIDC connection is configured for this organization";
37
36
  200: Response;
37
+ 404: "No OIDC connection is configured for this organization";
38
38
  422: {
39
39
  type: "validation";
40
40
  on: string;
@@ -61,8 +61,8 @@ export declare const oidcSsoRoutes: <UserType>({ authSessionStore, cookieSecure,
61
61
  headers: unknown;
62
62
  response: {
63
63
  400: "SSO session cookies are missing" | "Invalid SSO callback request" | "SSO organization mismatch" | "OIDC token response is missing an id_token";
64
- 404: "No OIDC connection is configured for this organization";
65
64
  200: Response;
65
+ 404: "No OIDC connection is configured for this organization";
66
66
  422: {
67
67
  type: "validation";
68
68
  on: string;
@@ -35,8 +35,8 @@ export declare const samlSsoRoutes: <UserType>({ authSessionStore, cookieSecure,
35
35
  query: unknown;
36
36
  headers: unknown;
37
37
  response: {
38
- 404: "No SAML connection is configured for this organization";
39
38
  200: Response;
39
+ 404: "No SAML connection is configured for this organization";
40
40
  422: {
41
41
  type: "validation";
42
42
  on: string;
@@ -62,8 +62,8 @@ export declare const samlSsoRoutes: <UserType>({ authSessionStore, cookieSecure,
62
62
  query: unknown;
63
63
  headers: unknown;
64
64
  response: {
65
- 404: "No SAML connection is configured for this organization";
66
65
  200: Response;
66
+ 404: "No SAML connection is configured for this organization";
67
67
  422: {
68
68
  type: "validation";
69
69
  on: string;
@@ -87,8 +87,8 @@ export declare const samlSsoRoutes: <UserType>({ authSessionStore, cookieSecure,
87
87
  query: unknown;
88
88
  headers: unknown;
89
89
  response: {
90
- 404: "No SAML connection is configured for this organization";
91
90
  200: Response;
91
+ 404: "No SAML connection is configured for this organization";
92
92
  422: {
93
93
  type: "validation";
94
94
  on: string;
@@ -141,9 +141,9 @@ export declare const samlSsoRoutes: <UserType>({ authSessionStore, cookieSecure,
141
141
  headers: unknown;
142
142
  response: {
143
143
  400: "Missing SAMLRequest or SAMLResponse" | "Invalid SAML LogoutRequest";
144
+ 200: Response;
144
145
  501: "SAML Single Logout is not configured";
145
146
  404: "No SAML connection is configured for this organization";
146
- 200: Response;
147
147
  422: {
148
148
  type: "validation";
149
149
  on: string;
@@ -0,0 +1,54 @@
1
+ # Agent authentication and registration
2
+
3
+ Absolute Auth implements agent registration inside `@absolutejs/auth`. There is
4
+ no separate `auth-md` package and no WorkOS service dependency. `/auth.md` is a
5
+ wire-compatible, generated companion document; OAuth metadata remains the
6
+ authoritative machine-readable contract.
7
+
8
+ ## Interoperability contract
9
+
10
+ The implementation composes existing standards wherever they already define the
11
+ behavior:
12
+
13
+ - RFC 9728 protected-resource discovery
14
+ - RFC 8414 authorization-server discovery
15
+ - RFC 7523 JWT bearer grants
16
+ - RFC 8628-style user-code polling semantics
17
+ - RFC 9396-compatible authorization details in agent delegations
18
+ - the auth.md v0.6 registration projection and ID-JAG assertion type
19
+
20
+ The auth.md claim grant currently has a WorkOS-namespaced URN because that is the
21
+ identifier in the open v0.6 wire profile. It is isolated behind
22
+ `AGENT_CLAIM_GRANT_TYPE`; it does not indicate a WorkOS backend dependency. A
23
+ future neutral identifier can be accepted alongside it without changing the
24
+ internal store, verifier, or client contracts.
25
+
26
+ Protocol inputs are normalized into provider-neutral Absolute types. Identity
27
+ verification, user resolution, stores, key management, and token revocation are
28
+ injected interfaces. Provider adapters can therefore be added without changing
29
+ routes or application authorization logic.
30
+
31
+ ## Security invariants
32
+
33
+ - The service owns the account-linking page. Agents never receive passwords,
34
+ MFA codes, or service session cookies.
35
+ - ID-JAG assertions are signature-, issuer-, audience-, client-, freshness-,
36
+ verification-, and replay-checked before identity resolution.
37
+ - A durable identity key includes issuer, subject, and client id. Different
38
+ agents acting for the same user cannot collapse into one registration.
39
+ - Claim and attempt tokens are stored only as hashes. User codes have bounded
40
+ attempts, short expirations, constant-time comparison, and atomic updates.
41
+ - Polling is rate-enforced and returns `slow_down` when the advertised interval
42
+ is ignored.
43
+ - Access tokens are opaque, scoped, short-lived, and looked up in a revocable
44
+ store. Anonymous pre-claim credentials must be revoked before ownership is
45
+ committed.
46
+ - Structured discovery never advertises an optional capability, such as
47
+ security-event delivery, unless the deployment actually implements it.
48
+
49
+ ## Deployment checklist
50
+
51
+ Use the Postgres identity-registration store in production, run the `agents`
52
+ migrations, keep signing keys in managed key storage, make anonymous-token
53
+ revocation idempotent, pin trusted assertion issuers and client ids, and apply
54
+ normal edge rate limits to identity, claim, completion, and token routes.