feat(iam): provision authorized first-login users as medical assistants

This commit is contained in:
2026-09-10 12:15:15 +08:00
parent f8b6196205
commit 6325ba88ff
6 changed files with 297 additions and 4 deletions
@@ -115,6 +115,21 @@ final class IamOidcClient
['Authorization: Bearer ' . $this->config['application_token']]);
}
public function bind(string $subject, int $adminId): array
{
if ($subject === '' || strlen($subject) > 512 || $adminId <= 0) {
throw new RuntimeException('IAM binding input is invalid');
}
$key = hash('sha256', json_encode([$this->config['issuer'], $this->config['application_id'], $subject, $adminId], JSON_THROW_ON_ERROR));
return $this->request('POST', rtrim($this->config['api_url'], '/') . '/internal/v1/applications/'
. rawurlencode($this->config['application_id']) . '/bindings', [
'Authorization: Bearer ' . $this->config['application_token'],
'Content-Type: application/json', 'X-Request-ID: ' . bin2hex(random_bytes(16)),
'Idempotency-Key: zyt-provision-' . $key,
], json_encode(['employeeSubject' => $subject, 'externalAccountId' => (string) $adminId,
'verificationMethod' => 'oidc_verified_subject_local_creation'], JSON_THROW_ON_ERROR), [201]);
}
private function metadata(): array
{
if ($this->discovery !== null) {
@@ -160,7 +175,7 @@ final class IamOidcClient
}
}
private function request(string $method, string $url, array $headers = [], string $body = ''): array
private function request(string $method, string $url, array $headers = [], string $body = '', array $statuses = [200]): array
{
$this->endpoint($url);
$headers[] = 'Accept: application/json';
@@ -189,7 +204,7 @@ final class IamOidcClient
$result = ['status' => curl_getinfo($curl, CURLINFO_RESPONSE_CODE), 'body' => $ok === false ? false : $response];
curl_close($curl);
}
if (!is_array($result) || ($result['status'] ?? 0) !== 200 || !is_string($result['body'] ?? null) || strlen($result['body']) > 1048576) {
if (!is_array($result) || !in_array($result['status'] ?? 0, $statuses, true) || !is_string($result['body'] ?? null) || strlen($result['body']) > 1048576) {
throw new RuntimeException('IAM request failed');
}
try {