@owlmeans/iam 0.1.10 → 0.1.14

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.
@@ -14,7 +14,7 @@ Provider-agnostic IAM abstraction. Defines `IamService` interface and related ty
14
14
  |--------|------|---------|
15
15
  | `IamService` | type | Unified IAM interface — all provisioning + authorization operations |
16
16
  | `IamClient` | type | Provisioned OIDC client `{ id?, clientId, secret?, name?, realm? }` |
17
- | `IamClientOptions` | type | `{ redirectUris? }` — optional `ensureClient` hardening; omit → backend keeps its wildcard default |
17
+ | `IamClientOptions` | type | `{ redirectUris? }` — explicit `ensureClient` hardening; omitting is a keycloak-only legacy shape (see below) |
18
18
  | `IamCredentialsPair` | type | `{ token: string; realm: string }` |
19
19
  | `IamPermissionArgs` | type | `{ permission?, resourceScoped?, title? }` — `permission` absent means unscoped resource name |
20
20
  | `IamResourceSpec` | type | `{ name: string; displayName?: string }` |
@@ -54,8 +54,12 @@ interface IamService extends InitializedService {
54
54
  // Get an admin { token, realm } pair for raw low-level calls (avoid unless necessary)
55
55
  getCredentialsPair: (entityId: string) => Promise<IamCredentialsPair>
56
56
 
57
+ // The tenant's public, fully-qualified OIDC issuer URL — the single value a relying party needs.
58
+ // Config-only (no remote call); throws IamClientError when the provider route is unconfigured.
59
+ getIssuerUrl: (entityId: string) => Promise<string>
60
+
57
61
  // Provision an OIDC client for a tenant and return its credentials.
58
- // options.redirectUris hardens the client (production/standalone); omitted → wildcard default.
62
+ // options.redirectUris hardens the client; always pass them (see "Issuer & redirect URIs").
59
63
  ensureClient: (entityId: string, clientId: string, options?: IamClientOptions) => Promise<IamClient>
60
64
 
61
65
  // Provision a named permission on a client resource; returns the resource name
@@ -92,6 +96,30 @@ await meta.update('oidcRealm', client.realm ?? fallbackEntityId)
92
96
  await meta.update('oidcRealm', (client as any)._realm)
93
97
  ```
94
98
 
99
+ ## Issuer & redirect URIs
100
+
101
+ **`getIssuerUrl(entityId)` is the only place an issuer URL may be composed.** Consumers pass the
102
+ result straight through as `OidcProviderDescriptor.discoveryUrl`; they must never rebuild it from a
103
+ host plus a base path. Each backend owns its own shape (keycloak `{iam-host}/realms/{entityId}`,
104
+ integrated `{provider-host}/{basePath}`), and an implementation must:
105
+
106
+ - resolve it from configuration only — no admin round-trip, so a consumer that just needs the issuer
107
+ never pays for or fails on a token grant;
108
+ - return exactly what the provider advertises as `issuer` (`openid-client` compares the two and fails
109
+ discovery on any difference — build it with the same `makeUrl(..., { base: true })` call
110
+ `@owlmeans/server-oidc-provider` uses);
111
+ - throw `IamClientError` when the provider's service route is missing, never fall back silently.
112
+
113
+ `getEntityAdminConfig` additionally carries the same value as `discoveryUrl`, so the admin provider
114
+ config is self-sufficient too.
115
+
116
+ **Always pass `redirectUris`.** Omitting them is a keycloak-only legacy default (`['*']`, which
117
+ Keycloak expands per-origin). The integrated provider does exact `redirect_uri` matching and
118
+ `oidc-provider` refuses to load a client whose `redirect_uris` are not absolute URIs — so
119
+ `iam-integrated.ensureClient` throws `IamClientError('redirect-uris')` on creation rather than
120
+ registering a client that can never complete a callback. An omitted list never widens an existing
121
+ hardened client.
122
+
95
123
  ## Selecting the IAM provider
96
124
 
97
125
  The platform wires the correct implementation via the `IAM_MODE` environment variable. The default is **`integrated`** (the internal IAM); `IAM_MODE=keycloak` is opt-in, used mainly for custom / standalone customer production setups. Do not read `IAM_MODE` directly from feature code — it belongs in the service-factory only (the platform exposes `resolveIamMode()` / `isIntegratedIam()` from `viable-common`):
@@ -99,10 +127,18 @@ The platform wires the correct implementation via the `IAM_MODE` environment var
99
127
  ```ts
100
128
  export const makeIamService = (mode = resolveIamMode()) => {
101
129
  if (mode === IAM_MODE_KEYCLOAK) return makeIamKeycloakService(VIABLE_IAM, { oidcProductAlias: OIDC_PRODUCT })
102
- return makeIamIntegratedService(VIABLE_IAM)
130
+ // Pass the consumer's OWN service alias + base path: the package defaults ('manager-api',
131
+ // '/oidc') are placeholders, and a mismatch makes every cfg.services[...] lookup miss.
132
+ return makeIamIntegratedService(VIABLE_IAM, {
133
+ providerServiceAlias: MANAGER_API, providerBasePath: IAM_PROVIDER_BASE_PATH,
134
+ })
103
135
  }
104
136
  ```
105
137
 
138
+ When a context hosts **more than one** `IamService` instance (the viable agent registers both
139
+ `viable-backend`'s and the agent library's), every instance must be constructed with the same
140
+ options — otherwise they disagree about the issuer.
141
+
106
142
  ## Rules
107
143
 
108
144
  - Always depend on `IamService` from `@owlmeans/iam`, not on `KeycloakApiService` directly.
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "package": "@owlmeans/iam",
4
- "version": "0.1.10",
5
- "generatedAt": "2026-06-17T09:37:28.202Z",
4
+ "version": "0.1.14",
5
+ "generatedAt": "2026-08-05T16:56:53.396Z",
6
6
  "canonicalRepo": "https://github.com/owlmeans/common",
7
7
  "entries": [
8
8
  {
package/build/types.d.ts CHANGED
@@ -14,10 +14,15 @@ export interface IamCredentialsPair {
14
14
  }
15
15
  export interface IamClientOptions {
16
16
  /**
17
- * Explicit allowed redirect URIs for the client. When omitted the backend keeps its
18
- * permissive default (wildcard `*`) for back-compat. Pass concrete origins to harden a
19
- * client — used for production/standalone clients whose callbacks are the production
20
- * generated host, an attached custom domain, and owner-registered self-host origins.
17
+ * Explicit allowed redirect URIs for the client. Pass the concrete callbacks a deployment
18
+ * may return to — the generated host, an attached custom domain, and owner-registered
19
+ * self-host origins.
20
+ *
21
+ * Omitting them is a **legacy keycloak-only** shape: Keycloak accepts a `*` wildcard, while
22
+ * the integrated provider does exact `redirect_uri` matching and rejects a wildcard outright
23
+ * (`oidc-provider` refuses a client whose `redirect_uris` are not absolute URIs). Backends
24
+ * that cannot honour a wildcard MUST throw `IamClientError` instead of registering an
25
+ * unusable client.
21
26
  */
22
27
  redirectUris?: string[];
23
28
  }
@@ -86,6 +91,19 @@ export interface IamUserUpdate {
86
91
  export interface IamService extends InitializedService {
87
92
  getEntityAdminConfig: (entityId: string) => Promise<OidcProviderConfig>;
88
93
  getCredentialsPair: (entityId: string) => Promise<IamCredentialsPair>;
94
+ /**
95
+ * The public, fully-qualified OIDC **issuer** URL a relying party of this entity must use for
96
+ * discovery — the single value a consumer needs (`OidcProviderDescriptor.discoveryUrl`). Each
97
+ * backend owns its own URL shape: keycloak `https://{iam-host}/realms/{entityId}`, integrated
98
+ * `https://{provider-host}/{basePath}`. Nothing outside an adapter may reassemble it.
99
+ *
100
+ * The returned string MUST equal, byte for byte, what the provider advertises as `issuer` in
101
+ * its discovery document: `openid-client` compares the two and fails the whole discovery when
102
+ * they differ. Implementations resolve it from configuration only — no remote admin call — and
103
+ * throw `IamClientError` when the provider's service route is not configured, so a
104
+ * misconfiguration is loud instead of yielding a silently wrong issuer.
105
+ */
106
+ getIssuerUrl: (entityId: string) => Promise<string>;
89
107
  ensureClient: (entityId: string, clientId: string, options?: IamClientOptions) => Promise<IamClient>;
90
108
  /**
91
109
  * Ensures a permission/resource exists in the entity's client.
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@owlmeans/iam",
3
- "version": "0.1.10",
3
+ "version": "0.1.14",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -22,17 +22,16 @@
22
22
  }
23
23
  },
24
24
  "dependencies": {
25
- "@owlmeans/auth": "^0.1.10",
26
- "@owlmeans/context": "^0.1.10",
27
- "@owlmeans/error": "^0.1.10",
28
- "@owlmeans/oidc": "^0.1.10"
25
+ "@owlmeans/auth": "^0.1.14",
26
+ "@owlmeans/context": "^0.1.14",
27
+ "@owlmeans/error": "^0.1.14",
28
+ "@owlmeans/oidc": "^0.1.14"
29
29
  },
30
30
  "devDependencies": {
31
31
  "@owlmeans/dep-config": "workspace:*",
32
- "@types/bun": "^1.3.0",
33
- "nodemon": "^3.1.11",
34
- "npm-check": "^6.0.1",
35
- "typescript": "^6.0.2"
32
+ "@types/bun": "^1.3.14",
33
+ "nodemon": "^3.1.14",
34
+ "typescript": "^6.0.3"
36
35
  },
37
36
  "publishConfig": {
38
37
  "access": "public"
package/src/types.ts CHANGED
@@ -17,10 +17,15 @@ export interface IamCredentialsPair {
17
17
 
18
18
  export interface IamClientOptions {
19
19
  /**
20
- * Explicit allowed redirect URIs for the client. When omitted the backend keeps its
21
- * permissive default (wildcard `*`) for back-compat. Pass concrete origins to harden a
22
- * client — used for production/standalone clients whose callbacks are the production
23
- * generated host, an attached custom domain, and owner-registered self-host origins.
20
+ * Explicit allowed redirect URIs for the client. Pass the concrete callbacks a deployment
21
+ * may return to — the generated host, an attached custom domain, and owner-registered
22
+ * self-host origins.
23
+ *
24
+ * Omitting them is a **legacy keycloak-only** shape: Keycloak accepts a `*` wildcard, while
25
+ * the integrated provider does exact `redirect_uri` matching and rejects a wildcard outright
26
+ * (`oidc-provider` refuses a client whose `redirect_uris` are not absolute URIs). Backends
27
+ * that cannot honour a wildcard MUST throw `IamClientError` instead of registering an
28
+ * unusable client.
24
29
  */
25
30
  redirectUris?: string[]
26
31
  }
@@ -100,6 +105,20 @@ export interface IamService extends InitializedService {
100
105
  getEntityAdminConfig: (entityId: string) => Promise<OidcProviderConfig>
101
106
  getCredentialsPair: (entityId: string) => Promise<IamCredentialsPair>
102
107
 
108
+ /**
109
+ * The public, fully-qualified OIDC **issuer** URL a relying party of this entity must use for
110
+ * discovery — the single value a consumer needs (`OidcProviderDescriptor.discoveryUrl`). Each
111
+ * backend owns its own URL shape: keycloak `https://{iam-host}/realms/{entityId}`, integrated
112
+ * `https://{provider-host}/{basePath}`. Nothing outside an adapter may reassemble it.
113
+ *
114
+ * The returned string MUST equal, byte for byte, what the provider advertises as `issuer` in
115
+ * its discovery document: `openid-client` compares the two and fails the whole discovery when
116
+ * they differ. Implementations resolve it from configuration only — no remote admin call — and
117
+ * throw `IamClientError` when the provider's service route is not configured, so a
118
+ * misconfiguration is loud instead of yielding a silently wrong issuer.
119
+ */
120
+ getIssuerUrl: (entityId: string) => Promise<string>
121
+
103
122
  // --- Provisioning (agent → story development) ---
104
123
  ensureClient: (entityId: string, clientId: string, options?: IamClientOptions) => Promise<IamClient>
105
124