{"_id":"@agdsoftware/sso-client","_rev":"3-b2dcc194d70c6dfe81542f66de739d41","name":"@agdsoftware/sso-client","dist-tags":{"latest":"1.1.1"},"versions":{"1.1.0":{"name":"@agdsoftware/sso-client","version":"1.1.0","keywords":["sso","keycloak","oidc","authorization","iam","agd"],"license":"UNLICENSED","_id":"@agdsoftware/sso-client@1.1.0","maintainers":[{"name":"agdmgv","email":"yazilimvebilisim@agd.org.tr"}],"homepage":"https://github.com/karademirmustafa/agd-sso/tree/main/packages/sso-client#readme","bugs":{"url":"https://github.com/karademirmustafa/agd-sso/issues"},"dist":{"shasum":"78ce7258dc59636d2c8adfb836fe21d52ead4ff2","tarball":"https://registry.npmjs.org/@agdsoftware/sso-client/-/sso-client-1.1.0.tgz","fileCount":43,"integrity":"sha512-17dSHiwNzQaFwfEVTYP347E5840qpDjop3/ozXTZ7ay7N4BrGBE38Ku86SUeKqeSEWXk+AS0HGlQ4cnTExHydQ==","signatures":[{"sig":"MEUCIEmfK+pJZrrxym7oJUE4gcbrIbSTuYiuFLcqUXG/09FBAiEA8K0KTrpISLYY+a3Y34PfUSDoo3mRENs1piMhZcwh/5s=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":168280},"main":"dist/cjs/index.js","type":"commonjs","_from":"file:/Users/karademir/yazilimvebilisimkomisyonu/52.Dönem/projeler/sso-yetkilendirme/dist-sdk/agdsoftware-sso-client-1.1.0.tgz","types":"dist/cjs/index.d.ts","module":"dist/esm/index.js","engines":{"node":">=20"},"exports":{".":{"types":"./dist/cjs/index.d.ts","import":"./dist/esm/index.js","require":"./dist/cjs/index.js"},"./oidc":{"types":"./dist/cjs/oidc.d.ts","import":"./dist/esm/oidc.js","require":"./dist/cjs/oidc.js"},"./server":{"types":"./dist/cjs/server.d.ts","import":"./dist/esm/server.js","require":"./dist/cjs/server.js"},"./package.json":"./package.json"},"scripts":{"test":"jest --passWithNoTests","build":"tsc -p tsconfig.json && tsc -p tsconfig.esm.json && node ../../scripts/dist-bicim-isareti.mjs .","clean":"rm -rf dist","typecheck":"tsc -p tsconfig.json --noEmit"},"_npmUser":{"name":"agdmgv","email":"yazilimvebilisim@agd.org.tr"},"_resolved":"/Users/karademir/yazilimvebilisimkomisyonu/52.Dönem/projeler/sso-yetkilendirme/dist-sdk/agdsoftware-sso-client-1.1.0.tgz","_integrity":"sha512-17dSHiwNzQaFwfEVTYP347E5840qpDjop3/ozXTZ7ay7N4BrGBE38Ku86SUeKqeSEWXk+AS0HGlQ4cnTExHydQ==","repository":{"url":"git+https://github.com/karademirmustafa/agd-sso.git","type":"git","directory":"packages/sso-client"},"_npmVersion":"11.8.0","description":"AGD SSO çekirdeği — evrensel yetki istemcisi, istemci tarafı yetki deposu, OIDC PKCE ve (sunucuda) token doğrulama","directories":{},"sideEffects":false,"_nodeVersion":"24.13.1","dependencies":{"jose":"^5.9.6"},"publishConfig":{"access":"public"},"typesVersions":{"*":{"oidc":["dist/cjs/oidc.d.ts"],"server":["dist/cjs/server.d.ts"]}},"//dependencies":"jose YALNIZ `@agdsoftware/sso-client/server` girişinde kullanılır; paket kökünü içe aktaran mobil/tarayıcı paketleri onu bundle'a almaz.","_hasShrinkwrap":false,"//typesVersions":"Alt yol tiplerini KLASİK (moduleResolution: node) çözümlemeye de tanıtır. NestJS şablonlarının varsayılanı budur; yalnız `exports` bırakmak, tüketicileri tsconfig değiştirmeye zorlardı.","devDependencies":{"typescript":"^5.5.4","@types/node":"^20.14.0"},"_npmOperationalInternal":{"tmp":"tmp/sso-client_1.1.0_1786336984128_0.9048908188894207","host":"s3://npm-registry-packages-npm-production"},"deprecated":"→ @agdsoftware/sso-sdk"},"1.1.1":{"name":"@agdsoftware/sso-client","version":"1.1.1","keywords":["sso","keycloak","oidc","oauth2","authorization","permissions","rbac","pkce","jwt","iam"],"license":"UNLICENSED","_id":"@agdsoftware/sso-client@1.1.1","maintainers":[{"name":"agdmgv","email":"yazilimvebilisim@agd.org.tr"}],"homepage":"https://github.com/karademirmustafa/agd-sso/tree/main/packages/sso-client#readme","bugs":{"url":"https://github.com/karademirmustafa/agd-sso/issues"},"dist":{"shasum":"8f305200fbcba69e6bb0d6ba9fde92f5387300ea","tarball":"https://registry.npmjs.org/@agdsoftware/sso-client/-/sso-client-1.1.1.tgz","fileCount":43,"integrity":"sha512-nnjsGz0bj04G38kf185HT1IcPp5O9W8Yq3d7ot1gipraZqspMEFnymbZsN2DjCLYQr5sxcZAr0m+8vZy2GCVTA==","signatures":[{"sig":"MEUCIBcPsaMCDBBcQg4JeW+HrnfyUSX8CY3sS+EjU+Wh5XA7AiEAjvCyGUvk/d8+6Q5UHsu0BpAEQNbi+IEEoLOwHoLglD0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":168451},"main":"dist/cjs/index.js","type":"commonjs","_from":"file:/Users/karademir/yazilimvebilisimkomisyonu/52.Dönem/projeler/sso-yetkilendirme/dist-sdk/agdsoftware-sso-client-1.1.1.tgz","types":"dist/cjs/index.d.ts","module":"dist/esm/index.js","engines":{"node":">=20"},"exports":{".":{"types":"./dist/cjs/index.d.ts","import":"./dist/esm/index.js","require":"./dist/cjs/index.js"},"./oidc":{"types":"./dist/cjs/oidc.d.ts","import":"./dist/esm/oidc.js","require":"./dist/cjs/oidc.js"},"./server":{"types":"./dist/cjs/server.d.ts","import":"./dist/esm/server.js","require":"./dist/cjs/server.js"},"./package.json":"./package.json"},"scripts":{"test":"jest --passWithNoTests","build":"tsc -p tsconfig.json && tsc -p tsconfig.esm.json && node ../../scripts/dist-bicim-isareti.mjs .","clean":"rm -rf dist","typecheck":"tsc -p tsconfig.json --noEmit"},"_npmUser":{"name":"agdmgv","email":"yazilimvebilisim@agd.org.tr"},"_resolved":"/Users/karademir/yazilimvebilisimkomisyonu/52.Dönem/projeler/sso-yetkilendirme/dist-sdk/agdsoftware-sso-client-1.1.1.tgz","_integrity":"sha512-nnjsGz0bj04G38kf185HT1IcPp5O9W8Yq3d7ot1gipraZqspMEFnymbZsN2DjCLYQr5sxcZAr0m+8vZy2GCVTA==","repository":{"url":"git+https://github.com/karademirmustafa/agd-sso.git","type":"git","directory":"packages/sso-client"},"_npmVersion":"11.8.0","description":"Keycloak/OIDC tabanlı merkezi yetkilendirme için çekirdek SDK — evrensel izin istemcisi, çerçeveden bağımsız yetki deposu, web ve mobil için PKCE, sunucuda JWT doğrulama.","directories":{},"sideEffects":false,"_nodeVersion":"24.13.1","dependencies":{"jose":"^5.9.6"},"publishConfig":{"access":"public"},"typesVersions":{"*":{"oidc":["dist/cjs/oidc.d.ts"],"server":["dist/cjs/server.d.ts"]}},"//dependencies":"jose YALNIZ `@agdsoftware/sso-client/server` girişinde kullanılır; paket kökünü içe aktaran mobil/tarayıcı paketleri onu bundle'a almaz.","_hasShrinkwrap":false,"//typesVersions":"Alt yol tiplerini KLASİK (moduleResolution: node) çözümlemeye de tanıtır. NestJS şablonlarının varsayılanı budur; yalnız `exports` bırakmak, tüketicileri tsconfig değiştirmeye zorlardı.","devDependencies":{"typescript":"^5.5.4","@types/node":"^20.14.0"},"_npmOperationalInternal":{"tmp":"tmp/sso-client_1.1.1_1786337633338_0.6375789903298266","host":"s3://npm-registry-packages-npm-production"},"deprecated":"→ @agdsoftware/sso-sdk"}},"time":{"created":"2026-08-10T04:43:03.927Z","modified":"2026-08-10T11:54:00.228Z","1.1.0":"2026-08-10T04:43:04.275Z","1.1.1":"2026-08-10T04:53:53.489Z"},"bugs":{"url":"https://github.com/karademirmustafa/agd-sso/issues"},"license":"UNLICENSED","homepage":"https://github.com/karademirmustafa/agd-sso/tree/main/packages/sso-client#readme","keywords":["sso","keycloak","oidc","oauth2","authorization","permissions","rbac","pkce","jwt","iam"],"repository":{"url":"git+https://github.com/karademirmustafa/agd-sso.git","type":"git","directory":"packages/sso-client"},"description":"Keycloak/OIDC tabanlı merkezi yetkilendirme için çekirdek SDK — evrensel izin istemcisi, çerçeveden bağımsız yetki deposu, web ve mobil için PKCE, sunucuda JWT doğrulama.","maintainers":[{"name":"agdmgv","email":"yazilimvebilisim@agd.org.tr"}],"readme":"# @agdsoftware/sso-client\n\nKimliği **Keycloak/OIDC**'den, yetkiyi **merkezi bir IAM servisinden** alan\nuygulamaların ortak çekirdeği — Node, tarayıcı ve React Native'de aynı paket.\n\n> **Tek cümle:** token *\"bu kişi kim\"* der, IAM *\"ne yapabilir\"* der.\n> İkisi ayrıdır ve ayrı kalmalıdır.\n\n## Girişler\n\n| Giriş | Ortam | İçerik |\n|---|---|---|\n| `@agdsoftware/sso-client` | evrensel | tipler, hatalar, `IamClient`, `AuthzStore`, `SsoSession`, kapsam yardımcıları |\n| `@agdsoftware/sso-client/server` | yalnız sunucu | `createTokenVerifier` (jose + JWKS) |\n| `@agdsoftware/sso-client/oidc` | tarayıcı + mobil | PKCE, keşif, çıkış adresi |\n\nKök giriş `fetch` dışında hiçbir şeye bağlı değildir. Bölünmenin sebebi tek\ncümle: **token'ı mobil taşır, sunucu doğrular.**\n\n## Kurulum\n\n```bash\npnpm add @agdsoftware/sso-client\n```\n\n## 30 saniyede bağlanma\n\n```ts\nimport { IamClient, bearerToken } from '@agdsoftware/sso-client';\n// Token doğrulama SUNUCUYA özgüdür (jose): paket kökü evrensel kalsın,\n// mobil/tarayıcı paketleri onu bundle'a almasın diye `/server` altındadır.\nimport { createTokenVerifier } from '@agdsoftware/sso-client/server';\n\nconst verify = createTokenVerifier({\n  issuer: process.env.SSO_ISSUER!,      // http://localhost:8080/realms/agd\n  audience: process.env.SSO_AUDIENCE!,  // SSO ekibinin verdiği audience\n});\n\nconst iam = new IamClient({ baseUrl: process.env.IAM_URL! }); // http://localhost:3001\n\n// istek başına\nconst token = bearerToken(req.headers.authorization);\nconst claims = await verify(token!);                   // 401 riski burada\nawait iam.assert(token!, groupId, 'ornek:kayit:onayla'); // 403 riski burada\n```\n\n`groupId` kullanıcının **aktif birimidir**; `iam.me(token)` ile listelenir ve\nkullanıcıya seçtirilir (birden fazla birimde görevli olabilir).\n\n## Express\n\n```ts\nimport { bearerToken, IamClient, ForbiddenError, SsoTokenError } from '@agdsoftware/sso-client';\nimport { createTokenVerifier } from '@agdsoftware/sso-client/server';\n\nconst verify = createTokenVerifier({ issuer: ISSUER, audience: AUDIENCE });\nconst iam = new IamClient({ baseUrl: IAM_URL });\n\nconst authenticate = async (req, res, next) => {\n  try {\n    const token = bearerToken(req.headers.authorization);\n    if (!token) throw new SsoTokenError('Token yok');\n    req.token = token;\n    req.user = await verify(token);\n    next();\n  } catch (error) {\n    next(error);\n  }\n};\n\nconst requirePermission = (permission: string) => async (req, res, next) => {\n  try {\n    // Bağlam birimi istemciden gelir ama YETKİ IAM'de doğrulanır:\n    // uydurulmuş bir groupId yalnız \"yetkin yok\" cevabı üretir.\n    await iam.assert(req.token, req.header('X-Organization-Group-Id'), permission);\n    next();\n  } catch (error) {\n    next(error);\n  }\n};\n\napp.get('/kayitlar', authenticate, requirePermission('ornek:kayit:goruntule'), handler);\n\n// Hataları HTTP durumuna çevir\napp.use((error, req, res, next) => {\n  if (error instanceof SsoTokenError) return res.status(401).json({ code: 'UNAUTHENTICATED' });\n  if (error instanceof ForbiddenError) return res.status(403).json({ code: 'FORBIDDEN' });\n  next(error);\n});\n```\n\n## NestJS\n\n```ts\n@Injectable()\nexport class SsoGuard implements CanActivate {\n  constructor(private readonly reflector: Reflector) {}\n\n  async canActivate(context: ExecutionContext): Promise<boolean> {\n    const req = context.switchToHttp().getRequest();\n    const token = bearerToken(req.headers.authorization);\n    if (!token) throw new UnauthorizedException();\n\n    req.user = await verify(token);          // SsoTokenError → 401\n    const permission = this.reflector.get<string>('permission', context.getHandler());\n    if (!permission) return true;\n\n    const decision = await iam.check(token, req.headers['x-organization-group-id'], permission);\n    if (!decision.allowed) throw new ForbiddenException({ reason: decision.reason });\n    return true;\n  }\n}\n\nexport const RequirePermission = (permission: string) => SetMetadata('permission', permission);\n```\n\n## Birden fazla izin bakacaksanız\n\nTek tek `check` yerine bir kez `effectivePermissions` alın — tek gidiş-dönüş:\n\n```ts\nconst effective = await iam.effectivePermissions(token, groupId);\nconst canApprove = effective.permissions.includes('ornek:kayit:onayla');\n```\n\nİstemci 30 sn yerel cache tutar (`cacheTtlMs` ile değiştirilir, `0` kapatır).\n\n## İl / ilçe filtrelemesi\n\n`iam.me(token)` her birim için **türü** ve türetilmiş **il/ilçe yolunu** verir:\n\n```jsonc\n{ \"path\": \"/İzmir/Konak/Eğitim\", \"unitType\": \"KOMISYON\",\n  \"il\": \"/İzmir\", \"ilce\": \"/İzmir/Konak\" }\n```\n\n`ilce` boşsa kullanıcı il seviyesindedir — \"tüm il\" demektir. Kendi kayıtlarınıza\nsahibi birimin `groupPath`'ini yazın ve listelemede bununla daraltın.\n\n## Kaynak (kayıt) bazlı yetki\n\nBir yetki tek tek kayıtlara kısıtlanabilir. Kısıtlı izin **genel sete girmez**:\n\n```ts\nconst effective = await iam.effectivePermissions(token, groupId);\nconst allowed = canAccessResource({\n  grants: effective.resourceGrants,\n  permission: 'ornek:kayit:guncelle',\n  resourceType: 'kayit',\n  resourceId: record.id,\n  recordGroupPath: record.groupPath,   // ZORUNLU\n  contextGroupPath: activeGroup.path,\n});\n```\n\n`recordGroupPath` kontrolü zorunludur: kaynaklar IAM için **opaktır**, kaydın\ngerçekten o birime ait olduğunu IAM doğrulayamaz.\n\n## Sık yapılan üç hata\n\n| Hata | Belirti | Çözüm |\n|---|---|---|\n| `issuer` tam eşleşmiyor | `unexpected \"iss\" claim value` | Token'daki `iss` ne ise birebir onu verin — `localhost` yerine `127.0.0.1` bile yeter |\n| `audience` doğrulanmıyor | Sessiz güvenlik açığı | Başka uygulamanın token'ı kabul edilir; SSO ekibinden audience isteyin |\n| Yetkiyi token'dan okumak | Süresi dolan yetki 5 dk yaşar | Karar daima `iam.check()` / `effectivePermissions()` |\n\n## İlgili\n\n`docs/INTEGRATION.md` (sözleşme) · `docs/TOKEN.md` (claim'ler) · `docs/CLIENTS.md` (istemci kaydı)\n","readmeFilename":"README.md"}