{"id":3434,"date":"2026-09-24T08:33:46","date_gmt":"2026-09-23T23:33:46","guid":{"rendered":"https:\/\/qol-kk.com\/wp2\/?p=3434"},"modified":"2026-09-24T08:33:46","modified_gmt":"2026-09-23T23:33:46","slug":"20260815-zenntest","status":"publish","type":"post","link":"https:\/\/qol-kk.com\/wp2\/blog\/2026\/09\/24\/20260815-zenntest\/","title":{"rendered":"\u6a19\u6e96 auth_user \u306f\u4e00\u5207\u5909\u66f4\u3057\u306a\u3044\u3002\u7d10\u4ed8\u3051\u306f\u5c02\u7528\u30c6\u30fc\u30d6\u30eb\u3067\u6301\u3064"},"content":{"rendered":"<p>\u500b\u4eba\u958b\u767a\u306e\u682a\u5f0f\u5206\u6790Web\u30a2\u30d7\u30ea\u3067\u3001\u8a8d\u8a3c\u57fa\u76e4\u3092\u5168\u9762\u7684\u306b\u5165\u308c\u66ff\u3048\u307e\u3057\u305f\u3002\u79fb\u884c\u5143\u306f\u300cDjango allauth + Simple JWT \u306e\u30e1\u30fc\u30eb\/\u30d1\u30b9\u30ef\u30fc\u30c9\u8a8d\u8a3c\u300d\u3001\u79fb\u884c\u5148\u306f\u300cAWS Cognito User Pool \u30d9\u30fc\u30b9\u306e OAuth 2.0 \/ OIDC\u300d\u3067\u3059\u3002\u3053\u306e\u8a18\u4e8b\u3067\u306f\u3001\u305d\u306e\u8a2d\u8a08\u3068\u5b9f\u88c5\u306e\u7d4c\u7def\u3092\u3001\u5b9f\u969b\u306e\u30b3\u30fc\u30c9\u69cb\u9020\u3068\u3068\u3082\u306b\u6b8b\u3057\u3066\u304a\u304d\u307e\u3059\u3002<\/p>\n<p>\u79fb\u884c\u306b\u3042\u305f\u3063\u3066\u6700\u521d\u306b\u5f15\u3044\u305f\u5236\u7d04\u306f\u3001\u6b21\u306e3\u3064\u3067\u3057\u305f\u3002<\/p>\n<ul>\n<li>\u65e2\u5b58\u30e6\u30fc\u30b6\u30fc\u306e\u30c7\u30fc\u30bf\uff08\u30dd\u30fc\u30c8\u30d5\u30a9\u30ea\u30aa\u30fb\u30c1\u30e3\u30c3\u30c8\u5c65\u6b74\uff09\u30921\u4ef6\u3082\u58ca\u3055\u306a\u3044<\/li>\n<li>\u65e2\u5b58\u30af\u30e9\u30a4\u30a2\u30f3\u30c8\uff08\u9759\u7684Bearer\u30ad\u30fc\u3067\u53e9\u304f\u7d4c\u8def\uff09\u3092\u6b62\u3081\u306a\u3044<\/li>\n<li>\u30d6\u30e9\u30a6\u30b6SPA \/ \u5916\u90e8LLM\u9023\u643a \/ \u65e2\u5b58\u30ad\u30fc\u30af\u30e9\u30a4\u30a2\u30f3\u30c8 \u306e3\u7d4c\u8def\u3092\u30011\u3064\u306e\u8a8d\u8a3c\u57fa\u76e4\u306b\u96c6\u7d04\u3059\u308b<\/li>\n<\/ul>\n<p>\u672c\u8a18\u4e8b\u306e\u4e3b\u5f79\u306f\u6d3e\u624b\u306a\u65b0\u6a5f\u80fd\u3067\u306f\u306a\u304f\u3001\u305f\u3063\u305f1\u3064\u306e\u5730\u5473\u306a\u8a2d\u8a08\u5224\u65ad\u3067\u3059\u3002\u3059\u306a\u308f\u3061 <strong>\u300cDjango\u6a19\u6e96\u306e <code>auth_user<\/code> \u306b\u306f\u4e00\u5207\u624b\u3092\u5165\u308c\u305a\u3001\u5225\u30c6\u30fc\u30d6\u30eb\u3067 Cognito \u306e <code>sub<\/code> \u3068 <code>user_id<\/code> \u3092\u7d10\u4ed8\u3051\u308b\u300d<\/strong> \u3053\u3068\u3002\u3053\u3053\u3092\u8d77\u70b9\u306b\u3001JIT\u30d7\u30ed\u30d3\u30b8\u30e7\u30cb\u30f3\u30b0\u3068DRF\u306e\u30cf\u30a4\u30d6\u30ea\u30c3\u30c9\u8a8d\u8a3c\u307e\u3067\u3001\u64ec\u4f3c\u30b3\u30fc\u30c9\u3092\u4ea4\u3048\u3066\u89e3\u8aac\u3057\u3066\u3044\u304d\u307e\u3059\u3002<\/p>\n<h2>\u306a\u305c\u79fb\u884c\u3057\u305f\u306e\u304b<\/h2>\n<p>\u304d\u3063\u304b\u3051\u306f\u6280\u8853\u7684\u306a\u7406\u60f3\u8ad6\u3067\u306f\u306a\u304f\u3001\u5916\u90e8\u8981\u56e0\u306e\u7a4d\u307f\u91cd\u306d\u3067\u3057\u305f\u3002<\/p>\n<ul>\n<li><strong>\u5916\u90e8LLM\u30b5\u30fc\u30d3\u30b9\u306e\u8981\u6c42<\/strong>\uff1a\u3042\u308bLLM\u30b5\u30fc\u30d3\u30b9\u306e Agent \/ Actions \u9023\u643a\u3092\u4f7f\u3046\u306b\u3042\u305f\u308a\u3001\u305d\u306e\u5229\u7528\u898f\u7d04\u304c OAuth \u8a8d\u8a3c\u7d4c\u8def\u3092\u8981\u6c42\u3057\u3066\u304d\u307e\u3057\u305f\u3002\u30e1\u30fc\u30eb\/\u30d1\u30b9\u30ef\u30fc\u30c9\uff0b\u81ea\u524dJWT\u306e\u307e\u307e\u3067\u306f\u63a5\u7d9a\u3067\u304d\u307e\u305b\u3093\u3002<\/li>\n<li><strong>\u96e2\u8131\u8005\u306e\u5373\u6642\u7121\u52b9\u5316<\/strong>\uff1a\u9000\u8077\u8005\u30fb\u96e2\u8131\u8005\u3092\u904b\u55b6\u5074\u304b\u3089\u5373\u5ea7\u306b\u7de0\u3081\u51fa\u3057\u305f\u3044\u3002\u81ea\u524d\u306e\u30c8\u30fc\u30af\u30f3\u767a\u884c\u3067\u306f\u3001\u5931\u52b9\u306e\u4e00\u5143\u7ba1\u7406\u304c\u3069\u3046\u3057\u3066\u3082\u7169\u96d1\u306b\u306a\u308a\u307e\u3059\u3002<\/li>\n<li><strong>\u7d4c\u8def\u306e\u96c6\u7d04<\/strong>\uff1a\u30d6\u30e9\u30a6\u30b6SPA\u30fb\u5916\u90e8LLM\u9023\u643a\u30fb\u65e2\u5b58\u30ad\u30fc\u30af\u30e9\u30a4\u30a2\u30f3\u30c8\u3092\u3001\u30d0\u30e9\u30d0\u30e9\u306e\u8a8d\u8a3c\u65b9\u5f0f\u3067\u306f\u306a\u304f1\u3064\u306e\u30de\u30cd\u30fc\u30b8\u30c9\u57fa\u76e4\u306b\u5bc4\u305b\u305f\u3044\u3002<\/li>\n<\/ul>\n<p>\u3053\u308c\u3089\u30921\u3064\u306e User Pool \u306b\u96c6\u7d04\u3067\u304d\u308c\u3070\u3001\u8a8d\u8a3c\u306e\u904b\u7528\uff08\u7121\u52b9\u5316\u30fb\u76e3\u67fb\u30fbIdP\u8ffd\u52a0\uff09\u304c Cognito \u5074\u3067\u5b8c\u7d50\u3057\u307e\u3059\u3002\u904b\u7528\u306e\u624b\u96e2\u308c\u306e\u826f\u3055\u3053\u305d\u3001\u4eca\u56de\u306e\u79fb\u884c\u306e\u672c\u5f53\u306e\u72d9\u3044\u3067\u3057\u305f\u3002<\/p>\n<h2>\u79fb\u884c\u524d \/ \u79fb\u884c\u5f8c\u306e\u69cb\u6210<\/h2>\n<p><strong>\u79fb\u884c\u524d<\/strong><\/p>\n<ul>\n<li>Django \u6a19\u6e96\u306e <code>User<\/code> \u30e2\u30c7\u30eb\uff08\u30ab\u30b9\u30bf\u30e0User\u306f\u4e0d\u63a1\u7528\uff09<\/li>\n<li>django-allauth + Simple JWT \u306e\u30e1\u30fc\u30eb\/\u30d1\u30b9\u30ef\u30fc\u30c9\u8a8d\u8a3c<\/li>\n<li>access 30\u5206 \/ refresh 7\u65e5 \/ rotation \u3042\u308a<\/li>\n<\/ul>\n<p><strong>\u79fb\u884c\u5f8c<\/strong><\/p>\n<ul>\n<li>AWS Cognito User Pool \u3092\u5358\u4e00\u306e\u8a8d\u8a3c\u57fa\u76e4\u306b<\/li>\n<li>\u96c6\u7d04\u3057\u305f3\u7d4c\u8def\uff1a\u2460\u30d6\u30e9\u30a6\u30b6SPA \u2461\u5916\u90e8LLM\u9023\u643a \u2462\u65e2\u5b58\u306e\u9759\u7684Bearer\u30ad\u30fc\u30af\u30e9\u30a4\u30a2\u30f3\u30c8<\/li>\n<li>\u30a4\u30f3\u30d5\u30e9\uff08User Pool \/ App Client \/ Google IdP \u9023\u643a\uff09\u306f Terraform \u7ba1\u7406<\/li>\n<li>\u30d0\u30c3\u30af\u30a8\u30f3\u30c9\u306e\u4e00\u90e8\u306f AWS Lambda \u4e0a\u3067\u7a3c\u50cd\uff08\u30b9\u30c6\u30fc\u30c8\u30ec\u30b9\u5b9f\u884c\uff09<\/li>\n<\/ul>\n<h2>\u8a2d\u8a08\u306e\u6838\uff1a\u6a19\u6e96User\u3092\u4e0d\u53ef\u4fb5\u306b\u3059\u308b<\/h2>\n<p>Cognito \u79fb\u884c\u3067\u307e\u305a\u60a9\u3080\u306e\u304c\u300cCognito \u306e <code>sub<\/code> \u3092\u3069\u3053\u306b\u6301\u305f\u305b\u308b\u304b\u300d\u3067\u3059\u3002\u7d20\u76f4\u306b\u601d\u3044\u3064\u304f\u306e\u306f\u3001\u6a19\u6e96\u306e <code>auth_user<\/code> \u306b <code>cognito_sub<\/code> \u5217\u3092\u8ffd\u52a0\u3057\u3066\u30ab\u30b9\u30bf\u30e0User\u30e2\u30c7\u30eb\u5316\u3059\u308b\u65b9\u6cd5\u3067\u3057\u3087\u3046\u3002<\/p>\n<p>\u3057\u304b\u3057\u3001<strong>\u904b\u7528\u4e2d\u306e\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u3067 <code>AUTH_USER_MODEL<\/code> \u3092\u5dee\u3057\u66ff\u3048\u305f\u308a\u3001\u6a19\u6e96\u30c6\u30fc\u30d6\u30eb\u306b\u30de\u30a4\u30b0\u30ec\u30fc\u30b7\u30e7\u30f3\u3092\u5f53\u3066\u305f\u308a\u3059\u308b\u306e\u306f\u3001\u79fb\u884c\u30ea\u30b9\u30af\u304c\u5927\u304d\u3059\u304e\u307e\u3059<\/strong>\u3002allauth \u3084\u30b5\u30fc\u30c9\u30d1\u30fc\u30c6\u30a3\u88fd\u30d1\u30c3\u30b1\u30fc\u30b8\u304c\u6a19\u6e96User\u3092\u524d\u63d0\u306b\u3057\u3066\u3044\u308b\u7b87\u6240\u306f\u591a\u304f\u3001\u5f71\u97ff\u7bc4\u56f2\u3092\u8aad\u307f\u5207\u308c\u307e\u305b\u3093\u3002<\/p>\n<p>\u305d\u3053\u3067\u63a1\u3063\u305f\u306e\u304c\u3001<strong>\u5225\u30c6\u30fc\u30d6\u30eb\u3067 1:1 \u306b\u7d10\u4ed8\u3051\u308b<\/strong> \u8a2d\u8a08\u3067\u3059\u3002<\/p>\n<pre class=\"lang:default decode:true\"># \u6a19\u6e96 auth_user \u306f\u4e00\u5207\u5909\u66f4\u3057\u306a\u3044\u3002\u7d10\u4ed8\u3051\u306f\u5c02\u7528\u30c6\u30fc\u30d6\u30eb\u3067\u6301\u3064\nclass ExternalIdentity(models.Model):\n    user = models.ForeignKey(\n        settings.AUTH_USER_MODEL,\n        on_delete=models.CASCADE,\n        related_name=\"external_identities\",\n    )\n    provider = models.CharField(max_length=32, default=\"cognito\")\n    subject = models.CharField(max_length=255, db_index=True)  # Cognito \u306e sub\n    email = models.EmailField()\n    last_signed_in_at = models.DateTimeField(null=True, blank=True)\n\n    class Meta:\n        # (provider, subject) \u3067\u4e00\u610f = sub \u306f\u57fa\u76e4\u5185\u3067\u4e00\u610f\n        unique_together = [(\"provider\", \"subject\")]<\/pre>\n<p>\u3053\u306e\u5f62\u306b\u3057\u305f\u7406\u7531\u306f2\u3064\u3042\u308a\u307e\u3059\u3002<\/p>\n<p><strong>1. \u6a19\u6e96\u30e2\u30c7\u30eb\u306e\u4e0d\u53ef\u4fb5\u5316<\/strong><\/p>\n<p><code>auth_user<\/code> \u306b\u30de\u30a4\u30b0\u30ec\u30fc\u30b7\u30e7\u30f3\u3092\u5f53\u3066\u307e\u305b\u3093\u3002\u65e2\u5b58\u306e\u30dd\u30fc\u30c8\u30d5\u30a9\u30ea\u30aa\u30fb\u30c1\u30e3\u30c3\u30c8\u5c65\u6b74\u304c\u53c2\u7167\u3059\u308b <code>user_id<\/code> \u306f\u305d\u306e\u307e\u307e\u751f\u304d\u7d9a\u3051\u307e\u3059\u3002\u79fb\u884c\u306e\u5931\u6557\u30dd\u30a4\u30f3\u30c8\u304c1\u3064\u4e38\u3054\u3068\u6d88\u3048\u308b\u308f\u3051\u3067\u3059\u3002<\/p>\n<p><strong>2. \u5c06\u6765\u306e\u8907\u6570IdP\u62e1\u5f35\u304c\u81ea\u7136<\/strong><\/p>\n<p>\u300c1\u30e6\u30fc\u30b6\u30fc\u306b\u8907\u6570\u306eIdP\uff08Cognito\u76f4\u30fbGoogle\u30fb\u5c06\u6765\u306e\u5225IdP\uff09\u300d\u3092\u5f8c\u304b\u3089\u8db3\u3057\u305f\u304f\u306a\u3063\u305f\u3068\u304d\u3001<code>ExternalIdentity<\/code> \u3092\u8907\u6570\u884c\u6301\u3066\u3070\u6e08\u307f\u307e\u3059\u3002\u3053\u3053\u3092 User \u306e\u5217\u3067\u306f\u306a\u304f\u5225\u30c6\u30fc\u30d6\u30eb\u306e\u884c\u3068\u3057\u3066\u8a2d\u8a08\u3057\u3066\u304a\u304f\u3068\u3001\u62e1\u5f35\u6642\u306b User \u30e2\u30c7\u30eb\u3092\u89e6\u3089\u305a\u306b\u6e08\u307f\u307e\u3059\u3002<\/p>\n<p>\u7d10\u4ed8\u3051\u306f\u6982\u5ff5\u7684\u306b\u306f <code>sub \u2194 user_id<\/code> \u306e 1:1 \u3067\u3059\u304c\u3001\u305d\u306e\u95a2\u9023\u3092\u300cUser \u306e\u5217\u300d\u3067\u306f\u306a\u304f\u300c\u5225\u30c6\u30fc\u30d6\u30eb\u306e\u884c\u300d\u3068\u3057\u3066\u6301\u3064\u3053\u3068\u3067\u3001User \u306e\u5f62\u3092\u5909\u3048\u305a\u306b\u8a8d\u8a3c\u306e\u90fd\u5408\u3092\u5438\u53ce\u3067\u304d\u308b\u3002\u3053\u308c\u304c\u4eca\u56de\u306e\u8a2d\u8a08\u306e\u3044\u3061\u3070\u3093\u306e\u52d8\u6240\u3067\u3059\u3002<\/p>\n<h2>JIT\u30d7\u30ed\u30d3\u30b8\u30e7\u30cb\u30f3\u30b0\uff1a\u65e2\u5b58\u30e6\u30fc\u30b6\u30fc\u3092\u58ca\u3055\u305a\u7d10\u4ed8\u3051\u308b<\/h2>\n<p>\u5225\u30c6\u30fc\u30d6\u30eb\u3092\u7528\u610f\u3057\u305f\u3060\u3051\u3067\u306f\u3001\u65e2\u5b58\u30e6\u30fc\u30b6\u30fc\u306f\u307e\u3060 Cognito \u306e <code>sub<\/code> \u3068\u7d50\u3073\u3064\u3044\u3066\u3044\u307e\u305b\u3093\u3002\u3053\u3053\u3067\u4f7f\u3046\u306e\u304c <strong>JIT\uff08Just-In-Time\uff09\u30d7\u30ed\u30d3\u30b8\u30e7\u30cb\u30f3\u30b0<\/strong> \u3067\u3059\u3002\u521d\u56de\u30ed\u30b0\u30a4\u30f3\u6642\u306b\u3001\u30c8\u30fc\u30af\u30f3\u306e claim \u304b\u3089\u300c\u89e3\u6c7a\u9806\u300d\u3092\u3042\u3089\u304b\u3058\u3081\u6c7a\u3081\u3066\u304a\u304f\u306e\u304c\u30dd\u30a4\u30f3\u30c8\u306b\u306a\u308a\u307e\u3059\u3002<\/p>\n<p><strong>\u89e3\u6c7a\u9806\uff1a\u2460 sub \u3067\u691c\u7d22 \u2192 \u2461 email \u3067\u30de\u30c3\u30c1\u30f3\u30b0 \u2192 \u2462 \u7121\u3051\u308c\u3070\u65b0\u898f\u4f5c\u6210<\/strong><\/p>\n<pre class=\"lang:default decode:true\">def resolve_user(claims):\n    sub = claims[\"sub\"]\n    email = (claims.get(\"email\") or \"\").lower()\n\n    # \u2460 sub \u3067\u65e2\u5b58\u30ea\u30f3\u30af\u3092\u691c\u7d22\uff082\u56de\u76ee\u4ee5\u964d\u306e\u30ed\u30b0\u30a4\u30f3\u306f\u3053\u3053\u3067\u5373\u30d2\u30c3\u30c8\uff09\n    identity = ExternalIdentity.objects.filter(\n        provider=\"cognito\", subject=sub\n    ).select_related(\"user\").first()\n    if identity:\n        return identity.user\n\n    # \u2461 email \u3067\u65e2\u5b58\u30e6\u30fc\u30b6\u30fc\u3068\u30de\u30c3\u30c1\u30f3\u30b0\uff08\u2190 \u79fb\u884c\u30e6\u30fc\u30b6\u30fc\u306e\u4fdd\u5168\u306f\u3053\u3053\uff09\n    user = User.objects.filter(email__iexact=email).first()\n\n    # \u2462 \u898b\u3064\u304b\u3089\u306a\u3051\u308c\u3070\u65b0\u898f\u4f5c\u6210\u3002Cognito \u7d4c\u7531\u3067\u306e\u307f\u30ed\u30b0\u30a4\u30f3\u53ef\u80fd\u306b\u3059\u308b\n    if user is None:\n        user = User(username=email, email=email)\n        user.set_unusable_password()  # \u30d1\u30b9\u30ef\u30fc\u30c9\u30ed\u30b0\u30a4\u30f3\u3092\u5c01\u3058\u308b\n        user.save()\n\n    # sub \u2194 user \u306e\u30ea\u30f3\u30af\u3092\u5f35\u308b\uff08\u6b21\u56de\u304b\u3089\u306f\u2460\u3067\u89e3\u6c7a\u3055\u308c\u308b\uff09\n    ExternalIdentity.objects.create(\n        provider=\"cognito\", subject=sub, email=email, user=user,\n    )\n    return user<\/pre>\n<p>\u809d\u306f <strong>\u2461\u306e email \u30de\u30c3\u30c1\u30f3\u30b0<\/strong> \u3067\u3059\u3002\u79fb\u884c\u524d\u304b\u3089\u5b58\u5728\u3059\u308b\u30e6\u30fc\u30b6\u30fc\u304c\u521d\u3081\u3066 Cognito \u3067\u30ed\u30b0\u30a4\u30f3\u3059\u308b\u3068\u3001\u2460\u3067\u306f\u307e\u3060\u30ea\u30f3\u30af\u304c\u7121\u3044\u305f\u3081\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3002\u3057\u304b\u3057\u2461\u3067\u65e2\u5b58\u306e <code>auth_user.email<\/code> \u3068\u7a81\u304d\u5408\u308f\u305b\u308c\u3070\u3001\u65e2\u5b58\u30e6\u30fc\u30b6\u30fc\u672c\u4eba\u3078\u81ea\u52d5\u7684\u306b\u7d10\u4ed8\u304d\u3001\u305d\u306e\u30e6\u30fc\u30b6\u30fc\u304c\u6301\u3064\u65e2\u5b58\u30c7\u30fc\u30bf\u304c\u305d\u306e\u307e\u307e\u5f15\u304d\u7d99\u304c\u308c\u307e\u3059\u30022\u56de\u76ee\u4ee5\u964d\u306f\u2460\u3067\u30d2\u30c3\u30c8\u3059\u308b\u306e\u3067\u3001email \u30de\u30c3\u30c1\u30f3\u30b0\u304c\u8d70\u308b\u306e\u306f\u5b9f\u8cea\u300c\u79fb\u884c\u6642\u306e1\u56de\u3060\u3051\u300d\u3067\u3059\u3002<\/p>\n<p>\u65b0\u898f\u4f5c\u6210\u6642\u306b <code>set_unusable_password()<\/code> \u3092\u547c\u3076\u306e\u306f\u3001<strong>Cognito \u7d4c\u7531\u4ee5\u5916\u306e\u30ed\u30b0\u30a4\u30f3\u7d4c\u8def\u3092\u585e\u3050<\/strong>\u305f\u3081\u3067\u3059\u3002\u30d1\u30b9\u30ef\u30fc\u30c9\u30cf\u30c3\u30b7\u30e5\u304c\u300c\u4f7f\u7528\u4e0d\u53ef\u300d\u72b6\u614b\u306b\u306a\u308a\u3001\u65e7\u6765\u306e\u30d1\u30b9\u30ef\u30fc\u30c9\u8a8d\u8a3c\u3067\u5165\u3089\u308c\u308b\u4f59\u5730\u3092\u6b8b\u3057\u307e\u305b\u3093\u3002<\/p>\n<p>&gt; \u26a0\ufe0f \u6ce8\u610f\uff1aemail \u30de\u30c3\u30c1\u30f3\u30b0\u306f\u300c\u540c\u3058 email = \u540c\u4e00\u4eba\u7269\u300d\u3092\u524d\u63d0\u306b\u3057\u3066\u3044\u307e\u3059\u3002\u3053\u308c\u3092\u5b89\u5168\u306b\u6210\u7acb\u3055\u305b\u308b\u306b\u306f\u3001\u5f8c\u8ff0\u306eJWT\u691c\u8a3c\u3067 <code>email_verified=false<\/code> \u306e\u30c8\u30fc\u30af\u30f3\u3092\u62d2\u5426\u3059\u308b\u3053\u3068\u304c\u5fc5\u9808\u3067\u3059\uff08\u672a\u691c\u8a3c\u30e1\u30fc\u30eb\u3092\u4f7f\u3063\u305f\u4e57\u3063\u53d6\u308a\u3092\u9632\u3050\u305f\u3081\uff09\u3002<\/p>\n<h2>DRF\u30cf\u30a4\u30d6\u30ea\u30c3\u30c9\u8a8d\u8a3c\uff1a\u4e00\u6c17\u306b\u7f6e\u304d\u63db\u3048\u306a\u3044<\/h2>\n<p>\u65e2\u5b58\u306e\u9759\u7684Bearer\u30ad\u30fc\u30af\u30e9\u30a4\u30a2\u30f3\u30c8\u3092\u6b62\u3081\u306a\u3044\u305f\u3081\u306b\u3001\u8a8d\u8a3c\u3092\u4e00\u62ec\u3067\u5207\u308a\u66ff\u3048\u308b\u306e\u3067\u306f\u306a\u304f\u3001<strong>DRF \u306e Authentication Class \u3092\u300c\u65b0\u65b9\u5f0f \u307e\u305f\u306f \u65e7\u65b9\u5f0f\u300d\u306e\u591a\u6bb5\u69cb\u6210<\/strong>\u306b\u3057\u307e\u3057\u305f\u3002DRF \u306f <code>DEFAULT_AUTHENTICATION_CLASSES<\/code> \u3092\u4e0a\u304b\u3089\u9806\u306b\u8a66\u3059\u306e\u3067\u3001\u305d\u306e\u6319\u52d5\u3092\u5229\u7528\u3057\u307e\u3059\u3002<\/p>\n<pre class=\"lang:default decode:true\">REST_FRAMEWORK = {\n    \"DEFAULT_AUTHENTICATION_CLASSES\": [\n        \"app.auth.CognitoJWTAuthentication\",     # \u65b0\u65b9\u5f0f\uff08\u512a\u5148\uff09\n        \"app.auth.StaticApiKeyAuthentication\",   # \u65e7\u65b9\u5f0f\uff08\u30d5\u30a9\u30fc\u30eb\u30d0\u30c3\u30af\uff09\n    ],\n}<\/pre>\n<p>\u632f\u308a\u5206\u3051\u306f <strong>\u30c8\u30fc\u30af\u30f3\u306e\u30d7\u30ec\u30d5\u30a3\u30c3\u30af\u30b9<\/strong> \u3067\u884c\u3044\u307e\u3059\u3002\u30b5\u30fc\u30d3\u30b9\u56fa\u6709\u30d7\u30ec\u30d5\u30a3\u30c3\u30af\u30b9\u4ed8\u304d\u306e\u9759\u7684\u30ad\u30fc\uff08\u4f8b\uff1a<code>svc_key_...<\/code>\uff09\u306fJWT\u691c\u8a3c\u306b\u56de\u3055\u305a\u3001JWT\u306fJWT\u691c\u8a3c\u306b\u56de\u3059\u3002\u3053\u3046\u3059\u308c\u3070\u65e7\u30af\u30e9\u30a4\u30a2\u30f3\u30c8\u306f\u7121\u6539\u4fee\u306e\u307e\u307e\u52d5\u304d\u7d9a\u3051\u307e\u3059\u3002<\/p>\n<pre class=\"lang:default decode:true\">class CognitoJWTAuthentication(BaseAuthentication):\n    def authenticate(self, request):\n        token = _extract_bearer(request)\n        if token is None:\n            return None\n        # \u9759\u7684\u30ad\u30fc\u306f\u3053\u306e\u8a8d\u8a3c\u306e\u5bfe\u8c61\u5916\uff08\u6b21\u306e\u30af\u30e9\u30b9\u306b\u59d4\u306d\u308b\uff09\n        if token.startswith(\"svc_key_\"):\n            return None\n        claims = verify_jwt(token)          # JWKS \u691c\u8a3c\uff08\u5f8c\u8ff0\uff09\n        user = resolve_user(claims)         # JIT \u30d7\u30ed\u30d3\u30b8\u30e7\u30cb\u30f3\u30b0\n        return (user, claims)\n\n\nclass StaticApiKeyAuthentication(BaseAuthentication):\n    def authenticate(self, request):\n        token = _extract_bearer(request)\n        if token is None:\n            return None\n        # \u30d7\u30ec\u30d5\u30a3\u30c3\u30af\u30b9\u304c\u5408\u308f\u306a\u3051\u308c\u3070\u300c\u3053\u306e\u30af\u30e9\u30b9\u306f\u95a2\u77e5\u3057\u306a\u3044\u300d\n        if not token.startswith(\"svc_key_\"):\n            return None\n        user = lookup_static_api_key(token)  # \u65e2\u5b58\u306e\u30ad\u30fc\u2192\u30e6\u30fc\u30b6\u30fc\u89e3\u6c7a\n        if user is None:\n            raise AuthenticationFailed(\"invalid api key\")\n        return (user, None)\n\n\ndef _extract_bearer(request):\n    header = get_authorization_header(request).decode(\"utf-8\", \"ignore\")\n    if not header.startswith(\"Bearer \"):\n        return None\n    return header[len(\"Bearer \"):].strip()<\/pre>\n<p><code>authenticate<\/code> \u304c <code>None<\/code> \u3092\u8fd4\u3059\u3068\u3001DRF \u306f\u6b21\u306e\u8a8d\u8a3c\u30af\u30e9\u30b9\u3092\u8a66\u3057\u307e\u3059\u3002\u3064\u307e\u308a\u300c\u81ea\u5206\u306e\u62c5\u5f53\u3067\u306a\u3044\u30c8\u30fc\u30af\u30f3\u306f <code>None<\/code> \u3092\u8fd4\u3059\u300d\u3068\u3044\u3046\u898f\u7d04\u3092\u5b88\u308b\u3060\u3051\u3067\u3001\u8907\u6570\u65b9\u5f0f\u3092\u304d\u308c\u3044\u306b\u5171\u5b58\u3055\u305b\u3089\u308c\u307e\u3059\u3002\u79fb\u884c\u304c\u5b8c\u4e86\u3057\u3066\u65e7\u7d4c\u8def\u3092\u7573\u3080\u6bb5\u306b\u306a\u3063\u305f\u3089\u3001<code>StaticApiKeyAuthentication<\/code> \u3092\u5916\u3059\u3060\u3051\u3067\u6e08\u307f\u307e\u3059\u3002\u3053\u306e\u300c\u5f8c\u3067\u5916\u3059\u3060\u3051\u300d\u3067\u623b\u305b\u308b\u72b6\u614b\u3092\u4f5c\u308c\u308b\u3053\u3068\u304c\u3001\u591a\u6bb5\u69cb\u6210\u306e\u4e00\u756a\u306e\u30e1\u30ea\u30c3\u30c8\u3067\u3059\u3002<\/p>\n<h2>App Client \u306f SPA\u7528\u3068\u5916\u90e8\u9023\u643a\u7528\u3067\u5206\u3051\u308b<\/h2>\n<p>Cognito \u306e App Client \u306f\u3001<strong>\u7528\u9014\u3054\u3068\u306b\u5206\u3051\u308b\u306e\u304c\u539f\u5247<\/strong>\u3067\u3059\u3002\u4eca\u56de\u306f\u5c11\u306a\u304f\u3068\u30822\u3064\u306b\u5206\u3051\u307e\u3057\u305f\u3002<\/p>\n<table>\n<thead>\n<tr>\n<th>\u7528\u9014<\/th>\n<th>\u30af\u30e9\u30a4\u30a2\u30f3\u30c8\u7a2e\u5225<\/th>\n<th>secret<\/th>\n<th>\u8a8d\u53ef\u30d5\u30ed\u30fc<\/th>\n<th>callback URL<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>\u30d6\u30e9\u30a6\u30b6SPA<\/td>\n<td>public client<\/td>\n<td>\u306a\u3057<\/td>\n<td>Authorization Code + <strong>PKCE<\/strong> \u5fc5\u9808<\/td>\n<td><code>https:\/\/app.example.com\/callback<\/code><\/td>\n<\/tr>\n<tr>\n<td>\u5916\u90e8LLM\u9023\u643a<\/td>\n<td>confidential client<\/td>\n<td>\u3042\u308a<\/td>\n<td>Authorization Code\uff08server-to-server\uff09<\/td>\n<td>\u9023\u643a\u30b5\u30fc\u30d3\u30b9\u5074\u306eURL<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>\u5206\u3051\u308b\u7406\u7531\u306f\u6b21\u306e\u901a\u308a\u3067\u3059\u3002<\/p>\n<ul>\n<li><strong>secret \u6f0f\u6d29\u9632\u6b62<\/strong>\uff1aSPA \u306f\u30d6\u30e9\u30a6\u30b6\u306b\u914d\u3089\u308c\u308b\u30b3\u30fc\u30c9\u306a\u306e\u3067\u3001secret \u3092\u5b89\u5168\u306b\u96a0\u305b\u307e\u305b\u3093\u3002public client \u306b\u3057\u3066 PKCE \u3067\u5b88\u308a\u307e\u3059\u3002secret \u3092\u6301\u3064\u306e\u306f\u3001\u79d8\u533f\u3067\u304d\u308b\u30b5\u30fc\u30d0\u30fc\u5074\uff08\u5916\u90e8\u9023\u643a\uff09\u3060\u3051\u306b\u9650\u5b9a\u3057\u307e\u3059\u3002<\/li>\n<li><strong>callback URL \u306e\u5206\u96e2<\/strong>\uff1a\u7d4c\u8def\u3054\u3068\u306b\u623b\u308a\u5148\u304c\u307e\u3063\u305f\u304f\u7570\u306a\u308a\u307e\u3059\u30021\u3064\u306e App Client \u306b\u6df7\u5728\u3055\u305b\u308b\u3068\u3001\u30ea\u30c0\u30a4\u30ec\u30af\u30c8\u5148\u306e\u8a31\u53ef\u30ea\u30b9\u30c8\u304c\u7de9\u304f\u306a\u308a\u3001\u4e8b\u6545\u306e\u3082\u3068\u306b\u306a\u308a\u307e\u3059\u3002<\/li>\n<li><strong>\u30e9\u30a4\u30d5\u30b5\u30a4\u30af\u30eb\/\u76e3\u67fb\u306e\u72ec\u7acb<\/strong>\uff1a\u5916\u90e8\u9023\u643a\u306e secret \u3092\u30ed\u30fc\u30c6\u30fc\u30b7\u30e7\u30f3\u3057\u305f\u3044\u3001\u7279\u5b9a\u7d4c\u8def\u3060\u3051\u6b62\u3081\u305f\u3044\u3001\u3068\u3044\u3063\u305f\u64cd\u4f5c\u3092\u4e92\u3044\u306b\u5f71\u97ff\u3055\u305b\u305a\u306b\u884c\u3048\u307e\u3059\u3002<\/li>\n<\/ul>\n<p>\u306a\u304a\u3001<strong>App Client \u3092\u5f8c\u304b\u3089\u5206\u5272\u3059\u308b\u306e\u306f\u610f\u5916\u3068\u9762\u5012<\/strong>\u3067\u3059\u3002\u6700\u521d\u304b\u3089\u7528\u9014\u5225\u306b\u5206\u3051\u3066\u304a\u304f\u3053\u3068\u3092\u5f37\u304f\u304a\u3059\u3059\u3081\u3057\u307e\u3059\u3002<\/p>\n<h2>JWT\u691c\u8a3c\u3068JWKS\u30ad\u30e3\u30c3\u30b7\u30e5<\/h2>\n<p>JWT\uff08RS256\uff09\u306e\u691c\u8a3c\u3067\u306f\u3001\u7f72\u540d\u691c\u8a3c\u306b\u52a0\u3048\u3066 <strong>claim \u3092\u660e\u793a\u7684\u306b\u30c1\u30a7\u30c3\u30af<\/strong>\u3057\u307e\u3059\u3002<\/p>\n<ul>\n<li><code>iss<\/code>\uff08issuer\uff09\u304c\u671f\u5f85\u5024\u3068<strong>\u5b8c\u5168\u4e00\u81f4<\/strong>\u3059\u308b\u3053\u3068<\/li>\n<li><code>token_use == \"access\"<\/code> \u3067\u3042\u308b\u3053\u3068<\/li>\n<li><code>client_id<\/code> \u304c<strong>\u8a31\u53ef\u30ea\u30b9\u30c8<\/strong>\u306b\u542b\u307e\u308c\u308b\u3053\u3068<\/li>\n<li>\u6709\u52b9\u671f\u9650\uff08<code>exp<\/code>\uff09\u304c\u5207\u308c\u3066\u3044\u306a\u3044\u3053\u3068<\/li>\n<li><code>email_verified == false<\/code> \u306e\u30c8\u30fc\u30af\u30f3\u306f<strong>\u62d2\u5426<\/strong>\u3059\u308b\u3053\u3068\uff08\u524d\u8ff0\u306e\u30e1\u30fc\u30eb\u4e57\u3063\u53d6\u308a\u9632\u6b62\uff09<\/li>\n<\/ul>\n<p>\u7f72\u540d\u9375\u306f Cognito \u306e JWKS \u30a8\u30f3\u30c9\u30dd\u30a4\u30f3\u30c8\u304b\u3089\u53d6\u5f97\u3057\u307e\u3059\u3002\u9375\u306f\u30ed\u30fc\u30c6\u30fc\u30b7\u30e7\u30f3\u3055\u308c\u308b\u306e\u3067\u3001<strong>TTL\u30ad\u30e3\u30c3\u30b7\u30e5 + kid\u4e0d\u4e00\u81f4\u6642\u306e\u5f37\u5236\u518d\u53d6\u5f97<\/strong> \u3067\u8ffd\u5f93\u3055\u305b\u307e\u3059\u3002<\/p>\n<pre class=\"lang:default decode:true\">_JWKS = {\"keys\": None, \"fetched_at\": 0}\n_TTL = 3600  # 1h\n\ndef _get_key(kid, force=False):\n    if force or _JWKS[\"keys\"] is None or _now() - _JWKS[\"fetched_at\"] &gt; _TTL:\n        _JWKS[\"keys\"] = fetch_jwks(JWKS_URL)   # HTTP GET\n        _JWKS[\"fetched_at\"] = _now()\n    key = _find_by_kid(_JWKS[\"keys\"], kid)\n    if key is None and not force:\n        # kid \u304c\u898b\u3064\u304b\u3089\u306a\u3044 = \u9375\u30ed\u30fc\u30c6\u30fc\u30b7\u30e7\u30f3\u3092\u7591\u3044\u3001\u4e00\u5ea6\u3060\u3051\u5f37\u5236\u518d\u53d6\u5f97\n        return _get_key(kid, force=True)\n    return key\n\ndef verify_jwt(token):\n    kid = jwt.get_unverified_header(token)[\"kid\"]\n    key = _get_key(kid)\n    if key is None:\n        raise AuthenticationFailed(\"signing key not found\")\n\n    claims = jwt.decode(\n        token, key, algorithms=[\"RS256\"],\n        options={\"require\": [\"exp\", \"iss\"]},\n    )\n    if claims.get(\"iss\") != EXPECTED_ISSUER:\n        raise AuthenticationFailed(\"bad issuer\")\n    if claims.get(\"token_use\") != \"access\":\n        raise AuthenticationFailed(\"bad token_use\")\n    if claims.get(\"client_id\") not in ALLOWED_CLIENT_IDS:\n        raise AuthenticationFailed(\"client_id not allowed\")\n    if claims.get(\"email_verified\") is False:\n        raise AuthenticationFailed(\"email not verified\")\n    return claims<\/pre>\n<p><strong>Lambda \u306e\u3088\u3046\u306a\u30b9\u30c6\u30fc\u30c8\u30ec\u30b9\u5b9f\u884c\u3067\u3082\u3001\u3053\u306e\u30ad\u30e3\u30c3\u30b7\u30e5\u306f\u304d\u3061\u3093\u3068\u52b9\u304d\u307e\u3059\u3002<\/strong> Lambda \u306f\u30ea\u30af\u30a8\u30b9\u30c8\u3054\u3068\u306b\u30bc\u30ed\u304b\u3089\u8d77\u52d5\u3059\u308b\u308f\u3051\u3067\u306f\u306a\u304f\u3001\u5b9f\u884c\u30b3\u30f3\u30c6\u30ca\u304c\u4e00\u5b9a\u6642\u9593\u518d\u5229\u7528\u3055\u308c\u307e\u3059\u3002\u305d\u306e\u751f\u5b58\u671f\u9593\u4e2d\u306f\u30e2\u30b8\u30e5\u30fc\u30eb\u30b9\u30b3\u30fc\u30d7\u306e <code>_JWKS<\/code> \u304c\u751f\u304d\u6b8b\u308b\u305f\u3081\u30012\u56de\u76ee\u4ee5\u964d\u306e\u30ea\u30af\u30a8\u30b9\u30c8\u306f\u30ed\u30fc\u30ab\u30eb\u30e1\u30e2\u30ea\u30ad\u30e3\u30c3\u30b7\u30e5\u306b\u30d2\u30c3\u30c8\u3057\u307e\u3059\u3002\u9375\u30ed\u30fc\u30c6\u30fc\u30b7\u30e7\u30f3\u306f kid \u4e0d\u4e00\u81f4\u3092\u30c8\u30ea\u30ac\u306b\u518d\u53d6\u5f97\u3055\u308c\u308b\u306e\u3067\u3001<strong>Redis \u7b49\u306e\u5916\u90e8\u30ad\u30e3\u30c3\u30b7\u30e5\u306f\u5f53\u9762\u4e0d\u8981<\/strong>\u3001\u3068\u3044\u3046\u5224\u65ad\u306b\u3057\u307e\u3057\u305f\u3002<\/p>\n<h2>\u96e2\u8131\u8005\u306e\u5373\u6642\u7121\u52b9\u5316<\/h2>\n<p>\u96c6\u7d04\u306e\u6069\u6075\u304c\u6700\u3082\u308f\u304b\u308a\u3084\u3059\u304f\u51fa\u308b\u306e\u304c\u3001\u3053\u306e\u7121\u52b9\u5316\u306e\u30b7\u30fc\u30f3\u3067\u3059\u3002<\/p>\n<ul>\n<li>Cognito \u5074\u3067\u30e6\u30fc\u30b6\u30fc\u3092 <strong><code>Disable user<\/code><\/strong> \u2192 \u65b0\u898f\u30ed\u30b0\u30a4\u30f3\u304c\u5373\u5ea7\u306b\u4e0d\u53ef\u306b\u306a\u308a\u307e\u3059\uff08\u305f\u3060\u3057\u65e2\u767a\u884c\u306e access token \u306f\u6700\u95771h\u6b8b\u308a\u307e\u3059\uff09<\/li>\n<li><strong><code>Sign out user<\/code><\/strong> \u2192 refresh token \u3082\u7121\u52b9\u5316\u3055\u308c\u3001\u30c8\u30fc\u30af\u30f3\u66f4\u65b0\u304c\u6b62\u307e\u308a\u307e\u3059<\/li>\n<li>\u3053\u308c\u3089\u306f <strong>\u5168\u5229\u7528\u7d4c\u8def\uff08SPA \/ \u5916\u90e8\u9023\u643a \/ Cognito\u767a\u884c\u30c8\u30fc\u30af\u30f3\u7d4c\u8def\uff09\u306b\u540c\u6642\u306b\u52b9\u304d\u307e\u3059<\/strong><\/li>\n<\/ul>\n<p>\u81ea\u524d\u3067\u30c8\u30fc\u30af\u30f3\u3092\u767a\u884c\u3057\u3066\u3044\u305f\u9803\u306f\u3001\u5931\u52b9\u3092\u30a2\u30d7\u30ea\u5074\u3067\u7ba1\u7406\u3059\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3057\u305f\u3002\u57fa\u76e4\u306b\u5bc4\u305b\u305f\u3053\u3068\u3067\u3001\u300cCognito\u5074\u306e1\u64cd\u4f5c\u3067\u7de0\u3081\u51fa\u3059\u300d\u304c\u305d\u306e\u307e\u307e\u6210\u7acb\u3057\u307e\u3059\u3002<\/p>\n<h2>\u6bb5\u968e\u79fb\u884c\u30d5\u30a7\u30fc\u30ba<\/h2>\n<p>\u4e00\u6c17\u306b\u3084\u3089\u305a\u3001\u6b21\u306e\u9806\u3067\u9032\u3081\u307e\u3057\u305f\u3002\u5404\u6bb5\u3067\u300c\u58ca\u308c\u3066\u3044\u306a\u3044\u3053\u3068\u300d\u3092\u78ba\u8a8d\u3057\u3066\u304b\u3089\u6b21\u3078\u9032\u3080\u3001\u3053\u308c\u304c\u6700\u5927\u306e\u8981\u70b9\u3067\u3059\u3002<\/p>\n<ol>\n<li><strong>\u30a4\u30f3\u30d5\u30e9\u6e96\u5099<\/strong> \u2014 Terraform \u3067 User Pool \/ App Client(\u00d72) \/ Google IdP \u9023\u643a\u3092\u5b9a\u7fa9<\/li>\n<li><strong>\u30d0\u30c3\u30af\u30a8\u30f3\u30c9\u8a8d\u8a3c\u5c64<\/strong> \u2014 JWT\u691c\u8a3c\u30fbJIT\u30d7\u30ed\u30d3\u30b8\u30e7\u30cb\u30f3\u30b0\u30fbDRF\u30cf\u30a4\u30d6\u30ea\u30c3\u30c9\u8a8d\u8a3c\u3092\u5b9f\u88c5\uff08\u3053\u306e\u6642\u70b9\u3067\u306f\u65e7\u8a8d\u8a3c\u3082\u751f\u304d\u3066\u3044\u308b\uff09<\/li>\n<li><strong>\u30d5\u30ed\u30f3\u30c8\u6539\u4fee<\/strong> \u2014 SPA \u3092 Amplify Auth \u306b\u8f09\u305b\u66ff\u3048\u3001PKCE \u306e Authorization Code \u30d5\u30ed\u30fc\u3078<\/li>\n<li><strong>\u65e7\u8a8d\u8a3c\u306e\u5ec3\u6b62<\/strong> \u2014 \u65e7\u30a8\u30f3\u30c9\u30dd\u30a4\u30f3\u30c8\u3092 <strong>410 Gone<\/strong> \u3067\u660e\u793a\u7684\u306b\u7573\u307f\u3001\u5916\u90e8LLM\u9023\u643a\u3092 confidential client \u3067\u63a5\u7d9a<\/li>\n<\/ol>\n<p>\u65e7\u8a8d\u8a3c\u3092\u5358\u306b\u6d88\u3059\u306e\u3067\u306f\u306a\u304f <strong>410 Gone<\/strong> \u3092\u8fd4\u3059\u306e\u306f\u3001\u65e7\u30af\u30e9\u30a4\u30a2\u30f3\u30c8\u304c\u300c\u610f\u56f3\u7684\u306b\u5ec3\u6b62\u3055\u308c\u305f\u300d\u3068\u5224\u5225\u3067\u304d\u308b\u3088\u3046\u306b\u3059\u308b\u305f\u3081\u3067\u3059\u3002404 \u3060\u3068\u300c\u4e00\u6642\u7684\u306a\u969c\u5bb3\u300d\u3068\u533a\u5225\u304c\u3064\u304d\u307e\u305b\u3093\u3002<\/p>\n<h2>\u78ba\u8a8d\u65b9\u6cd5<\/h2>\n<p>\u79fb\u884c\u5f8c\u306f\u3001\u6b21\u306e\u89b3\u70b9\u30671\u3064\u305a\u3064\u52d5\u4f5c\u3092\u78ba\u8a8d\u3057\u307e\u3057\u305f\u3002<\/p>\n<ul>\n<li><strong>\u65e2\u5b58\u30e6\u30fc\u30b6\u30fc\u306e\u4fdd\u5168<\/strong>\uff1a\u79fb\u884c\u524d\u30e6\u30fc\u30b6\u30fc\u3067 Cognito \u30ed\u30b0\u30a4\u30f3 \u2192 <code>ExternalIdentity<\/code> \u306b\u884c\u304c1\u4ef6\u4f5c\u3089\u308c\u3001\u65e2\u5b58\u306e\u30dd\u30fc\u30c8\u30d5\u30a9\u30ea\u30aa\/\u5c65\u6b74\u304c\u305d\u306e\u307e\u307e\u898b\u3048\u308b\u3053\u3068\u3092\u78ba\u8a8d\uff08\u2461\u306e email \u30de\u30c3\u30c1\u30f3\u30b0\u304c\u50cd\u3044\u305f\u8a3c\u62e0\uff09<\/li>\n<li><strong>2\u56de\u76ee\u30ed\u30b0\u30a4\u30f3<\/strong>\uff1a\u540c\u3058\u30e6\u30fc\u30b6\u30fc\u3067\u518d\u30ed\u30b0\u30a4\u30f3 \u2192 \u65b0\u898f\u884c\u304c\u5897\u3048\u305a\u3001\u2460\u306e sub \u691c\u7d22\u3067\u30d2\u30c3\u30c8\u3059\u308b\u3053\u3068\u3092\u78ba\u8a8d<\/li>\n<li><strong>\u65e7\u30af\u30e9\u30a4\u30a2\u30f3\u30c8<\/strong>\uff1a<code>svc_key_...<\/code> \u306e\u9759\u7684\u30ad\u30fc\u3067\u5f93\u6765\u3069\u304a\u308a\u53e9\u3051\u308b\u3053\u3068\uff08\u7121\u6539\u4fee\u3067200\u304c\u8fd4\u308b\uff09<\/li>\n<li><strong>\u9375\u30ed\u30fc\u30c6\u30fc\u30b7\u30e7\u30f3<\/strong>\uff1a\u53e4\u3044 kid \u306e\u30c8\u30fc\u30af\u30f3\u3067\u53e9\u304d\u3001JWKS\u5f37\u5236\u518d\u53d6\u5f97\u304c\u8d70\u3063\u3066\u691c\u8a3c\u304c\u901a\u308b\u3053\u3068<\/li>\n<li><strong>\u7121\u52b9\u5316<\/strong>\uff1a<code>Disable user<\/code> \u76f4\u5f8c\u306b\u65b0\u898f\u30ed\u30b0\u30a4\u30f3\u304c\u5f3e\u304b\u308c\u3001<code>Sign out user<\/code> \u3067 refresh \u304c\u6b62\u307e\u308b\u3053\u3068<\/li>\n<\/ul>\n<h2>\u6ce8\u610f\u70b9<\/h2>\n<p>\u6700\u5f8c\u306b\u3001\u5b9f\u88c5\u3057\u306a\u304c\u3089\u300c\u3053\u3053\u306f\u4e8b\u6545\u308a\u3084\u3059\u3044\u300d\u3068\u611f\u3058\u305f\u30dd\u30a4\u30f3\u30c8\u3092\u6319\u3052\u3066\u304a\u304d\u307e\u3059\u3002<\/p>\n<ul>\n<li><strong>email \u30de\u30c3\u30c1\u30f3\u30b0\u306f <code>email_verified<\/code> \u691c\u8a3c\u3068\u30bb\u30c3\u30c8\u3067<\/strong>\u3002\u672a\u691c\u8a3c\u30e1\u30fc\u30eb\u3092\u8a31\u3059\u3068\u3001\u4ed6\u4eba\u306e email \u3092\u9a19\u3063\u305f\u30a2\u30ab\u30a6\u30f3\u30c8\u3067\u65e2\u5b58\u30e6\u30fc\u30b6\u30fc\u306b\u7d10\u4ed8\u3044\u3066\u3057\u307e\u3044\u307e\u3059\u3002<\/li>\n<li><strong>Cognito \u306e access token \u306b email claim \u304c\u8f09\u308b\u304b\u306f\u8a2d\u5b9a\u6b21\u7b2c<\/strong>\u3002\u8f09\u3089\u306a\u3044\u69cb\u6210\u306a\u3089 id token \/ userinfo \u3067\u89e3\u6c7a\u3059\u308b\u306a\u3069\u3001\u7d4c\u8def\u3092\u660e\u793a\u7684\u306b\u8a2d\u8a08\u3059\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002<\/li>\n<li><strong>\u9759\u7684\u30ad\u30fc\u306e\u30d7\u30ec\u30d5\u30a3\u30c3\u30af\u30b9\u5206\u5c90\u306f\u300c\u66ab\u5b9a\u306e\u6a4b\u300d<\/strong>\u3002\u79fb\u884c\u5b8c\u4e86\u5f8c\u306f\u65e7\u8a8d\u8a3c\u30af\u30e9\u30b9\u3092\u5916\u3057\u3001\u5358\u4e00\u65b9\u5f0f\u306b\u623b\u3059\u3053\u3068\u3092\u30b4\u30fc\u30eb\u306b\u7f6e\u304d\u307e\u3059\u3002<\/li>\n<li><strong>App Client \u3092\u5f8c\u304b\u3089\u5206\u5272\u3059\u308b\u306e\u306f\u9762\u5012<\/strong>\u3002\u7e70\u308a\u8fd4\u3057\u306b\u306a\u308a\u307e\u3059\u304c\u3001\u6700\u521d\u304b\u3089\u7528\u9014\u5225\u306b\u5206\u3051\u3066\u304a\u304d\u307e\u3057\u3087\u3046\u3002<\/li>\n<\/ul>\n<h2>\u307e\u3068\u3081<\/h2>\n<p>\u30de\u30cd\u30fc\u30b8\u30c9\u8a8d\u8a3c\u3078\u306e\u79fb\u884c\u3067\u4e00\u756a\u6016\u3044\u306e\u306f\u3001\u300c\u8a8d\u8a3c\u3092\u5909\u3048\u305f\u3064\u3082\u308a\u304c\u3001\u65e2\u5b58\u30e6\u30fc\u30b6\u30fc\u306e\u30c7\u30fc\u30bf\u3054\u3068\u58ca\u3059\u300d\u3053\u3068\u3067\u3059\u3002\u4eca\u56de\u306e\u8a2d\u8a08\u306f\u3001\u305d\u308c\u3092\u6b21\u306e3\u70b9\u3067\u56de\u907f\u3057\u307e\u3057\u305f\u3002<\/p>\n<ol>\n<li><strong>\u6a19\u6e96User\u3092\u4e0d\u53ef\u4fb5\u5316<\/strong> \u2014 <code>sub \u2194 user_id<\/code> \u3092\u5225\u30c6\u30fc\u30d6\u30eb\u306b\u9003\u304c\u3057\u3001<code>auth_user<\/code> \u306b\u30de\u30a4\u30b0\u30ec\u30fc\u30b7\u30e7\u30f3\u3092\u5f53\u3066\u306a\u3044<\/li>\n<li><strong>JIT\u30d7\u30ed\u30d3\u30b8\u30e7\u30cb\u30f3\u30b0<\/strong> \u2014 sub \u2192 email \u2192 \u65b0\u898f\u4f5c\u6210 \u306e\u89e3\u6c7a\u9806\u3067\u3001\u65e2\u5b58\u30e6\u30fc\u30b6\u30fc\u3092\u81ea\u52d5\u4fdd\u5168<\/li>\n<li><strong>DRF\u30cf\u30a4\u30d6\u30ea\u30c3\u30c9\u8a8d\u8a3c<\/strong> \u2014 \u30d7\u30ec\u30d5\u30a3\u30c3\u30af\u30b9\u5206\u5c90\u3067\u65b0\u65e7\u3092\u5171\u5b58\u3055\u305b\u3001\u7121\u505c\u6b62\u3067\u6bb5\u968e\u79fb\u884c<\/li>\n<\/ol>\n<p>\u300c\u8a8d\u8a3c\u57fa\u76e4\u3092\u5dee\u3057\u66ff\u3048\u308b\u300d\u3068\u3044\u3046\u4e00\u898b\u5927\u304c\u304b\u308a\u306a\u5909\u66f4\u3082\u3001<strong>\u58ca\u3057\u3066\u306f\u3044\u3051\u306a\u3044\u5883\u754c\uff08\u6a19\u6e96User\u30fb\u65e2\u5b58\u30c7\u30fc\u30bf\u30fb\u65e2\u5b58\u30af\u30e9\u30a4\u30a2\u30f3\u30c8\uff09\u3092\u5148\u306b\u6c7a\u3081\u3066\u304b\u3089\u8a2d\u8a08\u3059\u308c\u3070\u3001\u5730\u5473\u306a\u5225\u30c6\u30fc\u30d6\u30eb1\u679a\u3067\u5b89\u5168\u306b\u7740\u5730\u3067\u304d\u308b<\/strong>\u3002\u3053\u308c\u304c\u4eca\u56de\u3044\u3061\u3070\u3093\u306e\u5b66\u3073\u3067\u3057\u305f\u3002\u540c\u3058\u3088\u3046\u306b\u904b\u7528\u4e2d\u306e\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u3067\u8a8d\u8a3c\u3092\u8f09\u305b\u66ff\u3048\u308b\u65b9\u306e\u53c2\u8003\u306b\u306a\u308c\u3070\u5e78\u3044\u3067\u3059\u3002<\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u500b\u4eba\u958b\u767a\u306e\u682a\u5f0f\u5206\u6790Web\u30a2\u30d7\u30ea\u3067\u3001\u8a8d\u8a3c\u57fa\u76e4\u3092\u5168\u9762\u7684\u306b\u5165\u308c\u66ff\u3048\u307e\u3057\u305f\u3002\u79fb\u884c\u5143\u306f\u300cDjango allauth + Simple JWT \u306e\u30e1\u30fc\u30eb\/\u30d1\u30b9\u30ef\u30fc\u30c9\u8a8d\u8a3c\u300d\u3001\u79fb\u884c\u5148\u306f\u300cAWS Cognito User Pool \u30d9\u30fc\u30b9\u306e OAuth 2\u2026<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"sns_share_botton_hide":"","vkExUnit_sns_title":"","_vk_print_noindex":"","sitemap_hide":"","_veu_custom_css":"","veu_display_promotion_alert":"","vkexunit_cta_each_option":"","_lightning_design_setting":[],"_jetpack_hide_featured_image":false,"_jetpack_featured_image_duplicate_dismissed":0,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"jetpack_post_was_ever_published":false},"categories":[75],"tags":[278,499,1176,814,1081,967,562,1094,964,154,340,895],"class_list":["post-3434","post","type-post","status-publish","format-standard","hentry","category-code-of-serverside","tag-auth","tag-aws","tag-cognito","tag-django","tag-lambda","tag-spa","tag-562","tag-1094","tag-964","tag-154","tag-340","tag-895"],"veu_head_title_object":{"title":"","add_site_title":""},"jetpack_publicize_connections":[],"jetpack-related-posts":[],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/qol-kk.com\/wp2\/wp-json\/wp\/v2\/posts\/3434","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/qol-kk.com\/wp2\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/qol-kk.com\/wp2\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/qol-kk.com\/wp2\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/qol-kk.com\/wp2\/wp-json\/wp\/v2\/comments?post=3434"}],"version-history":[{"count":1,"href":"https:\/\/qol-kk.com\/wp2\/wp-json\/wp\/v2\/posts\/3434\/revisions"}],"predecessor-version":[{"id":3435,"href":"https:\/\/qol-kk.com\/wp2\/wp-json\/wp\/v2\/posts\/3434\/revisions\/3435"}],"wp:attachment":[{"href":"https:\/\/qol-kk.com\/wp2\/wp-json\/wp\/v2\/media?parent=3434"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/qol-kk.com\/wp2\/wp-json\/wp\/v2\/categories?post=3434"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/qol-kk.com\/wp2\/wp-json\/wp\/v2\/tags?post=3434"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}