{"id":3193,"date":"2025-03-24T08:46:41","date_gmt":"2025-03-23T23:46:41","guid":{"rendered":"https:\/\/dexall.co.jp\/articles\/?p=3193"},"modified":"2025-03-24T08:47:12","modified_gmt":"2025-03-23T23:47:12","slug":"%e3%80%90%e4%bf%9d%e5%ad%98%e7%89%88%e3%80%91laravel-sanctum%e3%81%a7%e4%bd%9c%e3%82%8b%e6%9c%80%e5%bc%b7%e3%81%aeapi%e8%aa%8d%e8%a8%bc%e3%82%b7%e3%82%b9%e3%83%86%e3%83%a0-%e5%b0%8e%e5%85%a5%e3%81%8b","status":"publish","type":"post","link":"https:\/\/dexall.co.jp\/articles\/?p=3193","title":{"rendered":"\u3010\u4fdd\u5b58\u7248\u3011Laravel Sanctum\u3067\u4f5c\u308b\u6700\u5f37\u306eAPI\u8a8d\u8a3c\u30b7\u30b9\u30c6\u30e0 -\u5c0e\u5165\u304b\u3089\u5b9f\u88c5\u307e\u3067\u5b8c\u5168\u89e3\u8aac"},"content":{"rendered":"\n<div class=\"toc\"><br \/>\n<b>Warning<\/b>:  Undefined array key \"is_admin\" in <b>\/home\/xs392991\/dexall.co.jp\/public_html\/articles\/wp-content\/themes\/sango-theme\/library\/gutenberg\/dist\/classes\/Toc.php<\/b> on line <b>116<\/b><br \/>\n<br \/>\n<b>Warning<\/b>:  Undefined array key \"is_category_top\" in <b>\/home\/xs392991\/dexall.co.jp\/public_html\/articles\/wp-content\/themes\/sango-theme\/library\/gutenberg\/dist\/classes\/Toc.php<\/b> on line <b>121<\/b><br \/>\n<br \/>\n<b>Warning<\/b>:  Undefined array key \"is_top\" in <b>\/home\/xs392991\/dexall.co.jp\/public_html\/articles\/wp-content\/themes\/sango-theme\/library\/gutenberg\/dist\/classes\/Toc.php<\/b> on line <b>128<\/b><br \/>\n    <div id=\"toc_container\" class=\"sgb-toc--bullets js-smooth-scroll\" data-dialog-title=\"\u76ee\u6b21\">\n      <p class=\"toc_title\">\u76ee\u6b21 <\/p>\n      <ul class=\"toc_list\">  <li class=\"first\">    <a href=\"#i-0\">Laravel Sanctum\u3068\u306f\uff1f\u6700\u65b0\u306e\u8a8d\u8a3c\u30b7\u30b9\u30c6\u30e0\u3092\u8a73\u3057\u304f\u89e3\u8aac<\/a>    <ul class=\"menu_level_1\">      <li class=\"first\">        <a href=\"#i-1\">\u30e2\u30c0\u30f3\u306aAPI\u8a8d\u8a3c\u306e\u8ab2\u984c\u3092\u89e3\u6c7a\u3059\u308bSanctum\u306e\u7279\u5fb4<\/a>      <\/li>      <li class=\"last\">        <a href=\"#i-2\">\u5f93\u6765\u306e\u30d1\u30b9\u30dd\u30fc\u30c8\u3068\u306e\u6c7a\u5b9a\u7684\u306a\u9055\u3044\u3068\u9078\u629e\u57fa\u6e96<\/a>      <\/li>    <\/ul>  <\/li>  <li>    <a href=\"#i-3\">Laravel Sanctum\u306e\u30bb\u30c3\u30c8\u30a2\u30c3\u30d7\u65b9\u6cd5\u3092\u5fb9\u5e95\u89e3\u8aac<\/a>    <ul class=\"menu_level_1\">      <li class=\"first\">        <a href=\"#i-4\">\u5fc5\u8981\u306a\u74b0\u5883\u8981\u4ef6\u3068\u4f9d\u5b58\u95a2\u4fc2\u306e\u78ba\u8a8d<\/a>      <\/li>      <li>        <a href=\"#i-5\">Composer \u3067\u306e Sanctum \u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u3068\u521d\u671f\u8a2d\u5b9a<\/a>      <\/li>      <li class=\"last\">        <a href=\"#i-6\">\u30de\u30a4\u30b0\u30ec\u30fc\u30b7\u30e7\u30f3\u306e\u5b9f\u884c\u3068\u8a2d\u5b9a\u30d5\u30a1\u30a4\u30eb\u306e\u30ab\u30b9\u30bf\u30de\u30a4\u30ba<\/a>      <\/li>    <\/ul>  <\/li>  <li>    <a href=\"#i-7\">\u5b9f\u8df5\u7684\u306aAPI\u8a8d\u8a3c\u306e\u5b9f\u88c5\u624b\u9806<\/a>    <ul class=\"menu_level_1\">      <li class=\"first\">        <a href=\"#i-8\">\u6a29\u9650\u30d9\u30fc\u30b9\u8a8d\u8a3c\u306e\u57fa\u672c\u5b9f\u88c5\u65b9\u6cd5<\/a>      <\/li>      <li>        <a href=\"#i-9\">\u30e6\u30fc\u30b6\u30fc\u767b\u9332\u30fb\u30ed\u30b0\u30a4\u30f3API\u306e\u30a8\u30f3\u30c9\u30dd\u30a4\u30f3\u30c8\u4f5c\u6210<\/a>      <\/li>      <li class=\"last\">        <a href=\"#i-10\">\u30bb\u30ad\u30e5\u30a2\u306a\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u7ba1\u7406\u3068\u30d9\u30b9\u30c8\u30d7\u30e9\u30af\u30c6\u30a3\u30b9<\/a>      <\/li>    <\/ul>  <\/li>  <li>    <a href=\"#i-11\">SPA\u3068\u30e2\u30d0\u30a4\u30eb\u30a2\u30d7\u30ea\u306e\u8a8d\u8a3c\u5bfe\u5fdc<\/a>    <ul class=\"menu_level_1\">      <li class=\"first\">        <a href=\"#i-12\">CORS\u306e\u8a2d\u5b9a\u3068CSRF\u4fdd\u8b77\u306e\u5b9f\u88c5<\/a>      <\/li>      <li>        <a href=\"#i-13\">Vue\u3068React\u3068\u306e\u9023\u643a\u65b9\u6cd5<\/a>      <\/li>      <li class=\"last\">        <a href=\"#i-14\">\u30e2\u30d0\u30a4\u30eb\u30a2\u30d7\u30ea\u3067\u306e\u8a8d\u8a3c\u306e\u5b9f\u88c5\u4f8b<\/a>      <\/li>    <\/ul>  <\/li>  <li>    <a href=\"#i-15\">\u5b9f\u969b\u306e\u904b\u7528\u306b\u5411\u3051\u305f\u91cd\u8981\u306a\u8a2d\u5b9a\u3068\u6ce8\u610f\u70b9<\/a>    <ul class=\"menu_level_1\">      <li class=\"first\">        <a href=\"#i-16\">\u672c\u756a\u74b0\u5883\u3067\u306e\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u8a2d\u5b9a<\/a>      <\/li>      <li>        <a href=\"#i-17\">\u30d1\u30d5\u30a9\u30fc\u30de\u30f3\u30b9\u6700\u9069\u5316\u306e\u305f\u3081\u306e\u30ad\u30e3\u30c3\u30b7\u30e5\u6226\u7565<\/a>      <\/li>      <li class=\"last\">        <a href=\"#i-18\">\u30c8\u30e9\u30d6\u30eb\u30b7\u30e5\u30fc\u30c6\u30a3\u30f3\u30b0\u3068\u4e00\u822c\u7684\u306a\u554f\u984c\u306e\u89e3\u6c7a\u65b9\u6cd5<\/a>      <\/li>    <\/ul>  <\/li>  <li class=\"last\">    <a href=\"#i-19\">Laravel Sanctum\u3092\u4f7f\u3063\u305f\u8a8d\u8a3c\u30b7\u30b9\u30c6\u30e0\u306e\u767a\u5c55\u7684\u306a\u4f7f\u3044\u65b9<\/a>    <ul class=\"menu_level_1\">      <li class=\"first\">        <a href=\"#i-20\">\u30de\u30eb\u30c1\u30c7\u30d0\u30a4\u30b9\u5bfe\u5fdc\u306e\u5b9f\u88c5\u65b9\u6cd5<\/a>      <\/li>      <li>        <a href=\"#i-21\">\u30c8\u30fc\u30af\u30f3\u306e\u6709\u52b9\u671f\u9650\u3068\u81ea\u52d5\u66f4\u65b0\u306e\u5b9f\u88c5<\/a>      <\/li>      <li class=\"last\">        <a href=\"#i-22\">\u30ab\u30b9\u30bf\u30e0\u30ac\u30fc\u30c9\u3068\u30dd\u30ea\u30b7\u30fc\u306e\u6d3b\u7528\u65b9\u6cd5<\/a>      <\/li>    <\/ul>  <\/li><\/ul>\n      <a href=\"#\" class=\"sgb-toc-button js-toc-button\" rel=\"nofollow\" data-open-dialog=\"true\"><i class=\"fa fa-list\"><\/i><span class=\"sgb-toc-button__text\">\u76ee\u6b21\u3078<\/span><\/a>\n    <\/div><\/div><h2 class=\"wp-block-heading\" id=\"i-0\">Laravel Sanctum\u3068\u306f\uff1f\u6700\u65b0\u306e\u8a8d\u8a3c\u30b7\u30b9\u30c6\u30e0\u3092\u8a73\u3057\u304f\u89e3\u8aac<\/h2>\n\n\n\n<p>Laravel Sanctum\u306f\u3001SPA\u3084\u30e2\u30d0\u30a4\u30eb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3001API\u30c8\u30fc\u30af\u30f3\u30d9\u30fc\u30b9\u306e\u8a8d\u8a3c\u3092\u7c21\u5358\u306b\u5b9f\u88c5\u3067\u304d\u308bLaravel\u306e\u516c\u5f0f\u30d1\u30c3\u30b1\u30fc\u30b8\u3067\u3059\u3002\u30b7\u30f3\u30d7\u30eb\u3067\u8efd\u91cf\u306a\u8a8d\u8a3c\u30b7\u30b9\u30c6\u30e0\u3067\u3042\u308a\u306a\u304c\u3089\u3001\u30e2\u30c0\u30f3\u306aWeb\u958b\u767a\u306b\u5fc5\u8981\u306a\u6a5f\u80fd\u3092\u5b8c\u5099\u3057\u3066\u3044\u307e\u3059\u3002<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-1\">\u30e2\u30c0\u30f3\u306aAPI\u8a8d\u8a3c\u306e\u8ab2\u984c\u3092\u89e3\u6c7a\u3059\u308bSanctum\u306e\u7279\u5fb4<\/h3>\n\n\n\n<p>\u73fe\u4ee3\u306eWeb\u958b\u767a\u3067\u306f\u3001\u4ee5\u4e0b\u306e\u3088\u3046\u306a\u8a8d\u8a3c\u306b\u95a2\u3059\u308b\u8ab2\u984c\u304c\u5b58\u5728\u3057\u307e\u3059\uff1a<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u8907\u6570\u30d7\u30e9\u30c3\u30c8\u30d5\u30a9\u30fc\u30e0\u3078\u306e\u5bfe\u5fdc<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Web\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\uff08SPA\uff09<\/li>\n\n\n\n<li>\u30e2\u30d0\u30a4\u30eb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3<\/li>\n\n\n\n<li>\u30b5\u30fc\u30c9\u30d1\u30fc\u30c6\u30a3API\u30af\u30e9\u30a4\u30a2\u30f3\u30c8<\/li>\n<\/ul>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u8981\u4ef6\u306e\u8907\u96d1\u5316<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u30af\u30ed\u30b9\u30b5\u30a4\u30c8\u30ea\u30af\u30a8\u30b9\u30c8\u30d5\u30a9\u30fc\u30b8\u30a7\u30ea\uff08CSRF\uff09\u5bfe\u7b56<\/li>\n\n\n\n<li>\u30af\u30ed\u30b9\u30aa\u30ea\u30b8\u30f3\u30ea\u30bd\u30fc\u30b9\u5171\u6709\uff08CORS\uff09\u306e\u9069\u5207\u306a\u8a2d\u5b9a<\/li>\n\n\n\n<li>\u30c8\u30fc\u30af\u30f3\u306e\u5b89\u5168\u306a\u7ba1\u7406<\/li>\n<\/ul>\n\n\n\n<p>Sanctum\u306f\u3001\u3053\u308c\u3089\u306e\u8ab2\u984c\u306b\u5bfe\u3057\u3066\u4ee5\u4e0b\u306e\u7279\u5fb4\u3067\u89e3\u6c7a\u3092\u63d0\u4f9b\u3057\u307e\u3059\uff1a<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>2\u3064\u306e\u8a8d\u8a3c\u30b7\u30b9\u30c6\u30e0\u306e\u7d71\u5408<\/strong><\/li>\n\n\n\n<li>\u30c8\u30fc\u30af\u30f3\u30d9\u30fc\u30b9\u306eAPI\u8a8d\u8a3c<\/li>\n\n\n\n<li>SPA\u306e\u305f\u3081\u306e\u30af\u30c3\u30ad\u30fc\u30d9\u30fc\u30b9\u30bb\u30c3\u30b7\u30e7\u30f3\u8a8d\u8a3c<\/li>\n\n\n\n<li><strong>\u30b7\u30f3\u30d7\u30eb\u306a\u5b9f\u88c5<\/strong><\/li>\n<\/ul>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">  \/\/ \u30c8\u30fc\u30af\u30f3\u767a\u884c\u306e\u4f8b\n  $token = $user-&gt;createToken('token-name');\n\n  \/\/ API\u8a8d\u8a3c\u306e\u4f8b\n  Route::middleware('auth:sanctum')-&gt;get('\/user', function (Request $request) {\n      return $request-&gt;user();\n  });<\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>\u67d4\u8edf\u306a\u30c8\u30fc\u30af\u30f3\u7ba1\u7406<\/strong><\/li>\n\n\n\n<li>\u8907\u6570\u30c7\u30d0\u30a4\u30b9\u3067\u306e\u540c\u6642\u30ed\u30b0\u30a4\u30f3\u5bfe\u5fdc<\/li>\n\n\n\n<li>\u30c8\u30fc\u30af\u30f3\u3078\u306e\u6a29\u9650\u4ed8\u4e0e\u6a5f\u80fd<\/li>\n\n\n\n<li>\u30c8\u30fc\u30af\u30f3\u306e\u6709\u52b9\u671f\u9650\u8a2d\u5b9a<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-2\">\u5f93\u6765\u306e\u30d1\u30b9\u30dd\u30fc\u30c8\u3068\u306e\u6c7a\u5b9a\u7684\u306a\u9055\u3044\u3068\u9078\u629e\u57fa\u6e96<\/h3>\n\n\n\n<p>Laravel Passport\u3068\u6bd4\u8f03\u3057\u305f\u969b\u306e\u4e3b\u306a\u9055\u3044\u306f\u4ee5\u4e0b\u306e\u901a\u308a\u3067\u3059\uff1a<\/p>\n\n\n<div id=\"id-6d16ecc7-f6c7-4b60-bd78-5141f5bae516\">\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>\u6a5f\u80fd<\/th><th>Sanctum<\/th><th>Passport<\/th><\/tr><\/thead><tbody><tr><td>\u30a2\u30fc\u30ad\u30c6\u30af\u30c1\u30e3<\/td><td>\u8efd\u91cf\u30fb\u30b7\u30f3\u30d7\u30eb<\/td><td>OAuth2\u5b8c\u5168\u6e96\u62e0<\/td><\/tr><tr><td>\u30bb\u30c3\u30c8\u30a2\u30c3\u30d7<\/td><td>\u6700\u5c0f\u9650\u306e\u8a2d\u5b9a<\/td><td>\u6bd4\u8f03\u7684\u8907\u96d1<\/td><\/tr><tr><td>\u7528\u9014<\/td><td>SPA\u3068API\u306e\u7d71\u5408\u8a8d\u8a3c<\/td><td>\u672c\u683c\u7684\u306aOAuth2\u30b5\u30fc\u30d0\u30fc<\/td><\/tr><tr><td>\u30d1\u30d5\u30a9\u30fc\u30de\u30f3\u30b9<\/td><td>\u9ad8\u901f<\/td><td>\u3084\u3084\u91cd\u3044<\/td><\/tr><tr><td>\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9<\/td><td>\u6700\u5c0f\u9650\u306e\u30c6\u30fc\u30d6\u30eb<\/td><td>\u8907\u6570\u30c6\u30fc\u30d6\u30eb\u304c\u5fc5\u8981<\/td><\/tr><\/tbody><\/table><\/figure>\n<\/div>\n\n\n<p>\u9078\u629e\u57fa\u6e96\u306e\u30dd\u30a4\u30f3\u30c8\uff1a<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Sanctum\u3092\u9078\u3076\u3079\u304d\u5834\u5408<\/strong>\uff1a<\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u30b7\u30f3\u30d7\u30eb\u306aAPI\u8a8d\u8a3c\u304c\u5fc5\u8981<\/li>\n\n\n\n<li>SPA\u3068API\u306e\u7d71\u5408\u8a8d\u8a3c\u3092\u5b9f\u88c5\u3057\u305f\u3044<\/li>\n\n\n\n<li>\u30d1\u30d5\u30a9\u30fc\u30de\u30f3\u30b9\u3092\u91cd\u8996\u3059\u308b<\/li>\n\n\n\n<li>\u958b\u767a\u901f\u5ea6\u3092\u512a\u5148\u3059\u308b<\/li>\n<\/ul>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Passport\u3092\u9078\u3076\u3079\u304d\u5834\u5408<\/strong>\uff1a<\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>OAuth2\u306e\u5b8c\u5168\u306a\u6a5f\u80fd\u304c\u5fc5\u8981<\/li>\n\n\n\n<li>\u30b5\u30fc\u30c9\u30d1\u30fc\u30c6\u30a3\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3078\u306e\u8a8d\u8a3c\u63d0\u4f9b<\/li>\n\n\n\n<li>\u65e2\u5b58\u306eOAuth2\u30b7\u30b9\u30c6\u30e0\u3068\u306e\u7d71\u5408<\/li>\n<\/ul>\n\n\n\n<p>\u307e\u3068\u3081\u308b\u3068\u3001Laravel Sanctum\u306f\u3001\u30e2\u30c0\u30f3\u306aWeb\u958b\u767a\u306b\u304a\u3051\u308b\u8a8d\u8a3c\u306e\u8ab2\u984c\u3092\u3001\u30b7\u30f3\u30d7\u30eb\u3055\u3068\u9ad8\u6a5f\u80fd\u6027\u306e\u30d0\u30e9\u30f3\u30b9\u3092\u53d6\u308a\u306a\u304c\u3089\u89e3\u6c7a\u3059\u308b\u512a\u308c\u305f\u30bd\u30ea\u30e5\u30fc\u30b7\u30e7\u30f3\u3067\u3059\u3002\u7279\u306bSPA\u3084\u30e2\u30d0\u30a4\u30eb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3068\u306e\u9023\u643a\u3092\u524d\u63d0\u3068\u3057\u305f\u958b\u767a\u3067\u306f\u3001\u305d\u306e\u771f\u4fa1\u3092\u767a\u63ee\u3057\u307e\u3059\u3002<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"i-3\">Laravel Sanctum\u306e\u30bb\u30c3\u30c8\u30a2\u30c3\u30d7\u65b9\u6cd5\u3092\u5fb9\u5e95\u89e3\u8aac<\/h2>\n\n\n\n<p>Laravel Sanctum\u306e\u5c0e\u5165\u306f\u3001\u9069\u5207\u306a\u624b\u9806\u3067\u884c\u3046\u3053\u3068\u3067\u3001\u5b89\u5168\u3067\u78ba\u5b9f\u306a\u30bb\u30c3\u30c8\u30a2\u30c3\u30d7\u304c\u53ef\u80fd\u3067\u3059\u3002\u3053\u3053\u3067\u306f\u3001\u74b0\u5883\u8981\u4ef6\u306e\u78ba\u8a8d\u304b\u3089\u521d\u671f\u8a2d\u5b9a\u307e\u3067\u3001\u6bb5\u968e\u7684\u306b\u89e3\u8aac\u3057\u307e\u3059\u3002<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-4\">\u5fc5\u8981\u306a\u74b0\u5883\u8981\u4ef6\u3068\u4f9d\u5b58\u95a2\u4fc2\u306e\u78ba\u8a8d<\/h3>\n\n\n\n<p>Sanctum\u3092\u5c0e\u5165\u3059\u308b\u524d\u306b\u3001\u4ee5\u4e0b\u306e\u8981\u4ef6\u3092\u6e80\u305f\u3057\u3066\u3044\u308b\u304b\u78ba\u8a8d\u3057\u307e\u3057\u3087\u3046\uff1a<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u5fc5\u9808\u8981\u4ef6<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>PHP 7.3\u4ee5\u4e0a<\/li>\n\n\n\n<li>Laravel 8.0\u4ee5\u4e0a<\/li>\n\n\n\n<li>\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\uff08MySQL 5.7+, PostgreSQL 9.6+\u7b49\uff09<\/li>\n<\/ul>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u63a8\u5968\u74b0\u5883\u8a2d\u5b9a<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">   \/\/ php.ini \u306e\u63a8\u5968\u8a2d\u5b9a\n   session.cookie_httponly = 1\n   session.cookie_secure = 1\n   session.cookie_samesite = \"Lax\"<\/pre>\n\n\n\n<ol start=\"3\" class=\"wp-block-list\">\n<li><strong>\u30d5\u30ed\u30f3\u30c8\u30a8\u30f3\u30c9\u8981\u4ef6\uff08SPA\u5229\u7528\u6642\uff09<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>CORS\u306e\u8a2d\u5b9a\u304c\u53ef\u80fd\u306a\u30b5\u30fc\u30d0\u30fc\u74b0\u5883<\/li>\n\n\n\n<li>\u30bb\u30c3\u30b7\u30e7\u30f3\u30af\u30c3\u30ad\u30fc\u3092\u51e6\u7406\u3067\u304d\u308b\u30af\u30e9\u30a4\u30a2\u30f3\u30c8<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-5\">Composer \u3067\u306e Sanctum \u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u3068\u521d\u671f\u8a2d\u5b9a<\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u30d1\u30c3\u30b1\u30fc\u30b8\u306e\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">   composer require laravel\/sanctum<\/pre>\n\n\n\n<ol start=\"2\" class=\"wp-block-list\">\n<li><strong>Sanctum\u306e\u8a2d\u5b9a\u30d5\u30a1\u30a4\u30eb\u3068\u30de\u30a4\u30b0\u30ec\u30fc\u30b7\u30e7\u30f3\u30d5\u30a1\u30a4\u30eb\u306e\u516c\u958b<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">   php artisan vendor:publish --provider=\"Laravel\\Sanctum\\SanctumServiceProvider\"<\/pre>\n\n\n\n<ol start=\"3\" class=\"wp-block-list\">\n<li><strong>\u5fc5\u8981\u306a\u30df\u30c9\u30eb\u30a6\u30a7\u30a2\u306e\u767b\u9332<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">   \/\/ app\/Http\/Kernel.php\n\n   protected $middlewareGroups = [\n       'web' =&gt; [\n           \/\/ ...\n       ],\n\n       'api' =&gt; [\n           \\Laravel\\Sanctum\\Http\\Middleware\\EnsureFrontendRequestsAreStateful::class,\n           'throttle:api',\n           \\Illuminate\\Routing\\Middleware\\SubstituteBindings::class,\n       ],\n   ];<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-6\">\u30de\u30a4\u30b0\u30ec\u30fc\u30b7\u30e7\u30f3\u306e\u5b9f\u884c\u3068\u8a2d\u5b9a\u30d5\u30a1\u30a4\u30eb\u306e\u30ab\u30b9\u30bf\u30de\u30a4\u30ba<\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u30de\u30a4\u30b0\u30ec\u30fc\u30b7\u30e7\u30f3\u306e\u5b9f\u884c<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">   php artisan migrate<\/pre>\n\n\n\n<p>\u3053\u308c\u306b\u3088\u308a\u3001\u4ee5\u4e0b\u306e\u30c6\u30fc\u30d6\u30eb\u304c\u4f5c\u6210\u3055\u308c\u307e\u3059\uff1a<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>personal_access_tokens<\/code>: API\u30c8\u30fc\u30af\u30f3\u306e\u7ba1\u7406\u7528\u30c6\u30fc\u30d6\u30eb<\/li>\n<\/ul>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u8a2d\u5b9a\u30d5\u30a1\u30a4\u30eb\u306e\u30ab\u30b9\u30bf\u30de\u30a4\u30ba<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">   \/\/ config\/sanctum.php\n\n   return [\n       'stateful' =&gt; explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(\n           '%s%s',\n           'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1',\n           env('APP_URL') ? ','.parse_url(env('APP_URL'), PHP_URL_HOST) : ''\n       ))),\n\n       'guard' =&gt; ['web'],\n\n       'expiration' =&gt; null,  \/\/ \u30c8\u30fc\u30af\u30f3\u306e\u6709\u52b9\u671f\u9650\uff08\u5206\uff09\n\n       'middleware' =&gt; [\n           'verify_csrf_token' =&gt; App\\Http\\Middleware\\VerifyCsrfToken::class,\n           'encrypt_cookies' =&gt; App\\Http\\Middleware\\EncryptCookies::class,\n       ],\n   ];<\/pre>\n\n\n\n<ol start=\"3\" class=\"wp-block-list\">\n<li><strong>\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u8a2d\u5b9a\u306e\u8abf\u6574<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">   \/\/ config\/cors.php\n\n   return [\n       'paths' =&gt; ['api\/*', 'sanctum\/csrf-cookie'],\n       'allowed_methods' =&gt; ['*'],\n       'allowed_origins' =&gt; ['*'],\n       'allowed_origins_patterns' =&gt; [],\n       'allowed_headers' =&gt; ['*'],\n       'exposed_headers' =&gt; [],\n       'max_age' =&gt; 0,\n       'supports_credentials' =&gt; true,  \/\/ \u91cd\u8981: SPA\u3067\u5fc5\u9808\n   ];<\/pre>\n\n\n\n<p>\u30bb\u30c3\u30c8\u30a2\u30c3\u30d7\u5b8c\u4e86\u5f8c\u306e\u52d5\u4f5c\u78ba\u8a8d\uff1a<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ routes\/api.php\nRoute::middleware('auth:sanctum')-&gt;get('\/user', function (Request $request) {\n    return $request-&gt;user();\n});\n\n\/\/ \u30c6\u30b9\u30c8\u7528\u30b3\u30de\u30f3\u30c9\nphp artisan test<\/pre>\n\n\n\n<p>\u3053\u308c\u3067Laravel Sanctum\u306e\u57fa\u672c\u7684\u306a\u30bb\u30c3\u30c8\u30a2\u30c3\u30d7\u306f\u5b8c\u4e86\u3067\u3059\u3002\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u305f\u5834\u5408\u306f\u3001\u4ee5\u4e0b\u306e\u70b9\u3092\u78ba\u8a8d\u3057\u3066\u304f\u3060\u3055\u3044\uff1a<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u63a5\u7d9a\u8a2d\u5b9a\u306e\u78ba\u8a8d<\/li>\n\n\n\n<li>\u30de\u30a4\u30b0\u30ec\u30fc\u30b7\u30e7\u30f3\u306e\u5b9f\u884c\u72b6\u614b<\/li>\n\n\n\n<li>\u74b0\u5883\u5909\u6570\uff08.env\uff09\u306e\u8a2d\u5b9a<\/li>\n\n\n\n<li>CORS\u306e\u8a2d\u5b9a\uff08SPA\u5229\u7528\u6642\uff09<\/li>\n\n\n\n<li>\u30df\u30c9\u30eb\u30a6\u30a7\u30a2\u306e\u767b\u9332\u72b6\u614b<\/li>\n<\/ul>\n\n\n\n<p>\u30bb\u30c3\u30c8\u30a2\u30c3\u30d7\u304c\u5b8c\u4e86\u3057\u305f\u3089\u3001\u6b21\u306e\u30b9\u30c6\u30c3\u30d7\u3068\u3057\u3066\u30e6\u30fc\u30b6\u30fc\u8a8d\u8a3c\u306e\u5b9f\u88c5\u306b\u9032\u3080\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"i-7\">\u5b9f\u8df5\u7684\u306aAPI\u8a8d\u8a3c\u306e\u5b9f\u88c5\u624b\u9806<\/h2>\n\n\n\n<p>Laravel Sanctum\u3092\u4f7f\u7528\u3057\u305fAPI\u8a8d\u8a3c\u306e\u5b9f\u88c5\u306b\u3064\u3044\u3066\u3001\u5b9f\u8df5\u7684\u306a\u624b\u9806\u3068\u30d9\u30b9\u30c8\u30d7\u30e9\u30af\u30c6\u30a3\u30b9\u3092\u89e3\u8aac\u3057\u307e\u3059\u3002<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-8\">\u6a29\u9650\u30d9\u30fc\u30b9\u8a8d\u8a3c\u306e\u57fa\u672c\u5b9f\u88c5\u65b9\u6cd5<\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>User\u30e2\u30c7\u30eb\u306e\u6e96\u5099<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">   \/\/ app\/Models\/User.php\n   use Laravel\\Sanctum\\HasApiTokens;\n\n   class User extends Authenticatable\n   {\n       use HasApiTokens, HasFactory, Notifiable;\n\n       \/\/ \u30c8\u30fc\u30af\u30f3\u306b\u4ed8\u4e0e\u3067\u304d\u308b\u6a29\u9650\u306e\u5b9a\u7fa9\n       public static $tokenAbilities = [\n           'read',\n           'write',\n           'delete'\n       ];\n   }<\/pre>\n\n\n\n<ol start=\"2\" class=\"wp-block-list\">\n<li><strong>\u30c8\u30fc\u30af\u30f3\u767a\u884c\u51e6\u7406\u306e\u5b9f\u88c5<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">   \/\/ app\/Http\/Controllers\/Auth\/TokenController.php\n   class TokenController extends Controller\n   {\n       public function createToken(Request $request)\n       {\n           $request-&gt;validate([\n               'token_name' =&gt; 'required|string',\n               'abilities' =&gt; 'array|in:' . implode(',', User::$tokenAbilities)\n           ]);\n\n           $token = $request-&gt;user()-&gt;createToken(\n               $request-&gt;token_name,\n               $request-&gt;abilities ?? ['*']\n           );\n\n           return response()-&gt;json([\n               'token' =&gt; $token-&gt;plainTextToken,\n               'expires_at' =&gt; now()-&gt;addDays(config('sanctum.expiration_days'))\n           ]);\n       }\n\n       public function revokeToken(Request $request)\n       {\n           \/\/ \u73fe\u5728\u306e\u30c8\u30fc\u30af\u30f3\u3092\u7121\u52b9\u5316\n           $request-&gt;user()-&gt;currentAccessToken()-&gt;delete();\n\n           return response()-&gt;json(['message' =&gt; 'Token revoked successfully']);\n       }\n   }<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-9\">\u30e6\u30fc\u30b6\u30fc\u767b\u9332\u30fb\u30ed\u30b0\u30a4\u30f3API\u306e\u30a8\u30f3\u30c9\u30dd\u30a4\u30f3\u30c8\u4f5c\u6210<\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u30e6\u30fc\u30b6\u30fc\u767b\u9332API<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">   \/\/ app\/Http\/Controllers\/Auth\/RegisterController.php\n   class RegisterController extends Controller\n   {\n       public function register(Request $request)\n       {\n           $validated = $request-&gt;validate([\n               'name' =&gt; 'required|string|max:255',\n               'email' =&gt; 'required|string|email|max:255|unique:users',\n               'password' =&gt; 'required|string|min:8|confirmed'\n           ]);\n\n           $user = User::create([\n               'name' =&gt; $validated['name'],\n               'email' =&gt; $validated['email'],\n               'password' =&gt; Hash::make($validated['password'])\n           ]);\n\n           $token = $user-&gt;createToken('auth_token')-&gt;plainTextToken;\n\n           return response()-&gt;json([\n               'user' =&gt; $user,\n               'access_token' =&gt; $token,\n               'token_type' =&gt; 'Bearer'\n           ], 201);\n       }\n   }<\/pre>\n\n\n\n<ol start=\"2\" class=\"wp-block-list\">\n<li><strong>\u30ed\u30b0\u30a4\u30f3API<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">   \/\/ app\/Http\/Controllers\/Auth\/LoginController.php\n   class LoginController extends Controller\n   {\n       public function login(Request $request)\n       {\n           $credentials = $request-&gt;validate([\n               'email' =&gt; 'required|email',\n               'password' =&gt; 'required'\n           ]);\n\n           if (!Auth::attempt($credentials)) {\n               return response()-&gt;json([\n                   'message' =&gt; 'Invalid login credentials'\n               ], 401);\n           }\n\n           $user = $request-&gt;user();\n           $token = $user-&gt;createToken('auth_token')-&gt;plainTextToken;\n\n           return response()-&gt;json([\n               'user' =&gt; $user,\n               'access_token' =&gt; $token,\n               'token_type' =&gt; 'Bearer'\n           ]);\n       }\n   }<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-10\">\u30bb\u30ad\u30e5\u30a2\u306a\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u7ba1\u7406\u3068\u30d9\u30b9\u30c8\u30d7\u30e9\u30af\u30c6\u30a3\u30b9<\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u30c8\u30fc\u30af\u30f3\u6709\u52b9\u671f\u9650\u306e\u7ba1\u7406<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">   \/\/ config\/sanctum.php\n   return [\n       'expiration' =&gt; 60 * 24, \/\/ 24\u6642\u9593\n       'token_prefix' =&gt; env('SANCTUM_TOKEN_PREFIX', 'sanctum_'),\n   ];\n\n   \/\/ app\/Providers\/AuthServiceProvider.php\n   public function boot()\n   {\n       Sanctum::authenticateAccessTokensUsing(function ($token, $isValid) {\n           if ($isValid &amp;&amp; $token-&gt;created_at-&gt;lte(now()-&gt;subDays(7))) {\n               return false;\n           }\n           return $isValid;\n       });\n   }<\/pre>\n\n\n\n<ol start=\"2\" class=\"wp-block-list\">\n<li><strong>\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u30d8\u30c3\u30c0\u30fc\u306e\u8a2d\u5b9a<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">   \/\/ app\/Http\/Middleware\/SecurityHeaders.php\n   class SecurityHeaders\n   {\n       public function handle($request, Closure $next)\n       {\n           $response = $next($request);\n\n           $response-&gt;headers-&gt;set('X-Content-Type-Options', 'nosniff');\n           $response-&gt;headers-&gt;set('X-Frame-Options', 'DENY');\n           $response-&gt;headers-&gt;set('X-XSS-Protection', '1; mode=block');\n           $response-&gt;headers-&gt;set('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');\n\n           return $response;\n       }\n   }<\/pre>\n\n\n\n<ol start=\"3\" class=\"wp-block-list\">\n<li><strong>\u30ec\u30fc\u30c8\u5236\u9650\u306e\u5b9f\u88c5<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">   \/\/ routes\/api.php\n   Route::middleware(['auth:sanctum', 'throttle:60,1'])-&gt;group(function () {\n       Route::post('\/actions\/sensitive', 'ActionController@sensitive');\n   });<\/pre>\n\n\n\n<p>\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u306e\u30d9\u30b9\u30c8\u30d7\u30e9\u30af\u30c6\u30a3\u30b9\uff1a<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u30c8\u30fc\u30af\u30f3\u7ba1\u7406<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u9069\u5207\u306a\u6709\u52b9\u671f\u9650\u306e\u8a2d\u5b9a<\/li>\n\n\n\n<li>\u672a\u4f7f\u7528\u30c8\u30fc\u30af\u30f3\u306e\u5b9a\u671f\u7684\u306a\u30af\u30ea\u30fc\u30f3\u30a2\u30c3\u30d7<\/li>\n\n\n\n<li>\u30c8\u30fc\u30af\u30f3\u306e\u6a29\u9650\u30b9\u30b3\u30fc\u30d7\u306e\u6700\u5c0f\u5316<\/li>\n<\/ul>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u30a8\u30e9\u30fc\u30cf\u30f3\u30c9\u30ea\u30f3\u30b0<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">   \/\/ app\/Exceptions\/Handler.php\n   public function render($request, Throwable $exception)\n   {\n       if ($exception instanceof AuthenticationException) {\n           return response()-&gt;json([\n               'error' =&gt; 'Unauthenticated',\n               'message' =&gt; 'Please login to access this resource'\n           ], 401);\n       }\n\n       return parent::render($request, $exception);\n   }<\/pre>\n\n\n\n<ol start=\"3\" class=\"wp-block-list\">\n<li><strong>\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u30c1\u30a7\u30c3\u30af\u30ea\u30b9\u30c8<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>SSL\/TLS\u901a\u4fe1\u306e\u5f37\u5236<\/li>\n\n\n\n<li>\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u30d8\u30c3\u30c0\u30fc\u306e\u8a2d\u5b9a<\/li>\n\n\n\n<li>\u30ec\u30fc\u30c8\u5236\u9650\u306e\u5b9f\u88c5<\/li>\n\n\n\n<li>\u9069\u5207\u306a\u30d0\u30ea\u30c7\u30fc\u30b7\u30e7\u30f3\u306e\u5b9f\u88c5<\/li>\n\n\n\n<li>\u30a8\u30e9\u30fc\u30e1\u30c3\u30bb\u30fc\u30b8\u306e\u9069\u5207\u306a\u5236\u5fa1<\/li>\n<\/ul>\n\n\n\n<p>\u3053\u306e\u5b9f\u88c5\u306b\u3088\u308a\u3001\u30bb\u30ad\u30e5\u30a2\u3067\u4fdd\u5b88\u6027\u306e\u9ad8\u3044API\u8a8d\u8a3c\u30b7\u30b9\u30c6\u30e0\u3092\u69cb\u7bc9\u3059\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"i-11\">SPA\u3068\u30e2\u30d0\u30a4\u30eb\u30a2\u30d7\u30ea\u306e\u8a8d\u8a3c\u5bfe\u5fdc<\/h2>\n\n\n\n<p>Laravel Sanctum\u306f\u3001SPA\u3068\u30e2\u30d0\u30a4\u30eb\u30a2\u30d7\u30ea\u306e\u4e21\u65b9\u306b\u5bfe\u3057\u3066\u3001\u30b7\u30fc\u30e0\u30ec\u30b9\u306a\u8a8d\u8a3c\u4f53\u9a13\u3092\u63d0\u4f9b\u3057\u307e\u3059\u3002\u3053\u3053\u3067\u306f\u3001\u305d\u308c\u305e\u308c\u306e\u30d7\u30e9\u30c3\u30c8\u30d5\u30a9\u30fc\u30e0\u306b\u5bfe\u3059\u308b\u5177\u4f53\u7684\u306a\u5b9f\u88c5\u65b9\u6cd5\u3092\u89e3\u8aac\u3057\u307e\u3059\u3002<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-12\">CORS\u306e\u8a2d\u5b9a\u3068CSRF\u4fdd\u8b77\u306e\u5b9f\u88c5<\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>CORS\u306e\u57fa\u672c\u8a2d\u5b9a<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">   \/\/ config\/cors.php\n   return [\n       'paths' =&gt; ['api\/*', 'sanctum\/csrf-cookie'],\n       'allowed_methods' =&gt; ['*'],\n       'allowed_origins' =&gt; [\n           'http:\/\/localhost:3000',\n           'http:\/\/localhost:8080',\n           'https:\/\/your-frontend-domain.com'\n       ],\n       'allowed_headers' =&gt; ['*'],\n       'exposed_headers' =&gt; [],\n       'max_age' =&gt; 0,\n       'supports_credentials' =&gt; true, \/\/ \u91cd\u8981: \u5fc5\u305atrue\u306b\u8a2d\u5b9a\n   ];<\/pre>\n\n\n\n<ol start=\"2\" class=\"wp-block-list\">\n<li><strong>CSRF\u4fdd\u8b77\u306e\u8a2d\u5b9a<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">   \/\/ app\/Http\/Middleware\/VerifyCsrfToken.php\n   protected $except = [\n       'sanctum\/csrf-cookie',\n       'api\/mobile\/*'  \/\/ \u30e2\u30d0\u30a4\u30ebAPI\u306e\u30a8\u30f3\u30c9\u30dd\u30a4\u30f3\u30c8\n   ];<\/pre>\n\n\n\n<ol start=\"3\" class=\"wp-block-list\">\n<li><strong>\u30bb\u30c3\u30b7\u30e7\u30f3\u8a2d\u5b9a\u306e\u8abf\u6574<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">   \/\/ config\/session.php\n   return [\n       'domain' =&gt; env('SESSION_DOMAIN', null),\n       'secure' =&gt; env('SESSION_SECURE_COOKIE', true),\n       'same_site' =&gt; 'lax',\n   ];<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-13\">Vue\u3068React\u3068\u306e\u9023\u643a\u65b9\u6cd5<\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Vue\u3067\u306e\u5b9f\u88c5\u4f8b<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">   \/\/ Vue 3\u3067\u306e\u5b9f\u88c5\n   import axios from 'axios'\n\n   axios.defaults.withCredentials = true\n\n   const login = async (email, password) =&gt; {\n     \/\/ CSRF\u4fdd\u8b77\u306e\u521d\u671f\u5316\n     await axios.get('\/sanctum\/csrf-cookie')\n\n     try {\n       const response = await axios.post('\/api\/login', {\n         email,\n         password\n       })\n\n       \/\/ \u30ed\u30b0\u30a4\u30f3\u6210\u529f\u6642\u306e\u51e6\u7406\n       localStorage.setItem('user', JSON.stringify(response.data.user))\n       return response.data\n     } catch (error) {\n       console.error('Login failed:', error)\n       throw error\n     }\n   }\n\n   \/\/ API\u547c\u3073\u51fa\u3057\u306e\u4f8b\n   const fetchUserData = async () =&gt; {\n     try {\n       const response = await axios.get('\/api\/user')\n       return response.data\n     } catch (error) {\n       if (error.response.status === 401) {\n         \/\/ \u672a\u8a8d\u8a3c\u6642\u306e\u51e6\u7406\n         router.push('\/login')\n       }\n     }\n   }<\/pre>\n\n\n\n<ol start=\"2\" class=\"wp-block-list\">\n<li><strong>React\u3067\u306e\u5b9f\u88c5\u4f8b<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">   \/\/ React\u5b9f\u88c5\u4f8b\n   import axios from 'axios'\n\n   const api = axios.create({\n     baseURL: process.env.REACT_APP_API_URL,\n     withCredentials: true,\n     headers: {\n       'Content-Type': 'application\/json',\n       'Accept': 'application\/json'\n     }\n   })\n\n   const AuthProvider = ({ children }) =&gt; {\n     const [user, setUser] = useState(null)\n     const [loading, setLoading] = useState(true)\n\n     const login = async (email, password) =&gt; {\n       await axios.get('\/sanctum\/csrf-cookie')\n\n       const response = await api.post('\/login', {\n         email,\n         password\n       })\n\n       setUser(response.data.user)\n       return response.data\n     }\n\n     const logout = async () =&gt; {\n       await api.post('\/logout')\n       setUser(null)\n     }\n\n     \/\/ \u8a8d\u8a3c\u72b6\u614b\u306e\u78ba\u8a8d\n     useEffect(() =&gt; {\n       const checkAuth = async () =&gt; {\n         try {\n           const response = await api.get('\/api\/user')\n           setUser(response.data)\n         } catch (error) {\n           setUser(null)\n         } finally {\n           setLoading(false)\n         }\n       }\n\n       checkAuth()\n     }, [])\n\n     return (\n       &lt;AuthContext.Provider value={{ user, login, logout, loading }}&gt;\n         {children}\n       &lt;\/AuthContext.Provider&gt;\n     )\n   }<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-14\">\u30e2\u30d0\u30a4\u30eb\u30a2\u30d7\u30ea\u3067\u306e\u8a8d\u8a3c\u306e\u5b9f\u88c5\u4f8b<\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>iOS Swift\u5b9f\u88c5\u4f8b<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">   class APIClient {\n       static let baseURL = \"https:\/\/api.your-domain.com\"\n       static var token: String?\n\n       static func login(email: String, password: String) async throws -&gt; User {\n           let url = URL(string: \"\\(baseURL)\/api\/login\")!\n           var request = URLRequest(url: url)\n           request.httpMethod = \"POST\"\n           request.setValue(\"application\/json\", forHTTPHeaderField: \"Content-Type\")\n\n           let body = [\"email\": email, \"password\": password]\n           request.httpBody = try JSONSerialization.data(withJSONObject: body)\n\n           let (data, response) = try await URLSession.shared.data(for: request)\n           guard let httpResponse = response as? HTTPURLResponse,\n                 httpResponse.statusCode == 200 else {\n               throw APIError.invalidResponse\n           }\n\n           let loginResponse = try JSONDecoder().decode(LoginResponse.self, from: data)\n           token = loginResponse.token\n           return loginResponse.user\n       }\n\n       static func authenticatedRequest&lt;T: Decodable&gt;(_ endpoint: String) async throws -&gt; T {\n           guard let token = token else { throw APIError.unauthorized }\n\n           let url = URL(string: \"\\(baseURL)\/api\/\\(endpoint)\")!\n           var request = URLRequest(url: url)\n           request.setValue(\"Bearer \\(token)\", forHTTPHeaderField: \"Authorization\")\n\n           let (data, _) = try await URLSession.shared.data(for: request)\n           return try JSONDecoder().decode(T.self, from: data)\n       }\n   }<\/pre>\n\n\n\n<ol start=\"2\" class=\"wp-block-list\">\n<li><strong>Android Kotlin\u5b9f\u88c5\u4f8b<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">   class ApiService {\n       private val retrofit = Retrofit.Builder()\n           .baseUrl(\"https:\/\/api.your-domain.com\")\n           .addConverterFactory(GsonConverterFactory.create())\n           .client(createOkHttpClient())\n           .build()\n\n       private fun createOkHttpClient(): OkHttpClient {\n           return OkHttpClient.Builder()\n               .addInterceptor { chain -&gt;\n                   val original = chain.request()\n\n                   val request = original.newBuilder()\n                       .header(\"Accept\", \"application\/json\")\n                       .method(original.method, original.body)\n                       .apply {\n                           UserPreferences.token?.let {\n                               header(\"Authorization\", \"Bearer $it\")\n                           }\n                       }\n                       .build()\n\n                   chain.proceed(request)\n               }\n               .build()\n       }\n\n       suspend fun login(email: String, password: String): LoginResponse {\n           return retrofit.create(ApiInterface::class.java)\n               .login(LoginRequest(email, password))\n               .also {\n                   UserPreferences.token = it.token\n               }\n       }\n   }<\/pre>\n\n\n\n<p>\u3053\u308c\u3089\u306e\u5b9f\u88c5\u306b\u3088\u308a\u3001SPA\u3084\u30e2\u30d0\u30a4\u30eb\u30a2\u30d7\u30ea\u304b\u3089\u306e\u30bb\u30ad\u30e5\u30a2\u306a\u8a8d\u8a3c\u304c\u53ef\u80fd\u306b\u306a\u308a\u307e\u3059\u3002\u5b9f\u88c5\u6642\u306e\u6ce8\u610f\u70b9\u3068\u3057\u3066\uff1a<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u8003\u616e\u4e8b\u9805<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u30c8\u30fc\u30af\u30f3\u306e\u5b89\u5168\u306a\u4fdd\u5b58<\/li>\n\n\n\n<li>HTTPS\u901a\u4fe1\u306e\u5f37\u5236<\/li>\n\n\n\n<li>\u30c8\u30fc\u30af\u30f3\u306e\u6709\u52b9\u671f\u9650\u7ba1\u7406<\/li>\n\n\n\n<li>\u30ea\u30d5\u30ec\u30c3\u30b7\u30e5\u30c8\u30fc\u30af\u30f3\u306e\u5b9f\u88c5<\/li>\n<\/ul>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u30a8\u30e9\u30fc\u30cf\u30f3\u30c9\u30ea\u30f3\u30b0<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u30a8\u30e9\u30fc<\/li>\n\n\n\n<li>\u8a8d\u8a3c\u30a8\u30e9\u30fc<\/li>\n\n\n\n<li>\u30c8\u30fc\u30af\u30f3\u671f\u9650\u5207\u308c<\/li>\n<\/ul>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u30e6\u30fc\u30b6\u30fc\u4f53\u9a13\u306e\u6700\u9069\u5316<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u30aa\u30d5\u30e9\u30a4\u30f3\u5bfe\u5fdc<\/li>\n\n\n\n<li>\u81ea\u52d5\u30ed\u30b0\u30a4\u30f3<\/li>\n\n\n\n<li>\u30bb\u30c3\u30b7\u30e7\u30f3\u7dad\u6301<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"i-15\">\u5b9f\u969b\u306e\u904b\u7528\u306b\u5411\u3051\u305f\u91cd\u8981\u306a\u8a2d\u5b9a\u3068\u6ce8\u610f\u70b9<\/h2>\n\n\n\n<p>\u672c\u756a\u74b0\u5883\u3067Laravel Sanctum\u3092\u904b\u7528\u3059\u308b\u969b\u306e\u91cd\u8981\u306a\u8a2d\u5b9a\u3068\u3001\u5b9f\u969b\u306e\u904b\u7528\u3067\u767a\u751f\u3057\u3084\u3059\u3044\u554f\u984c\u3078\u306e\u5bfe\u51e6\u65b9\u6cd5\u3092\u89e3\u8aac\u3057\u307e\u3059\u3002<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-16\">\u672c\u756a\u74b0\u5883\u3067\u306e\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u8a2d\u5b9a<\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u74b0\u5883\u5909\u6570\u306e\u9069\u5207\u306a\u8a2d\u5b9a<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">   # .env\n   SESSION_SECURE_COOKIE=true\n   SESSION_DOMAIN=.your-domain.com\n   SANCTUM_STATEFUL_DOMAINS=your-frontend-domain.com\n   SESSION_LIFETIME=120\n   SANCTUM_EXPIRATION=60<\/pre>\n\n\n\n<ol start=\"2\" class=\"wp-block-list\">\n<li><strong>\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u30d8\u30c3\u30c0\u30fc\u306e\u8a2d\u5b9a<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">   \/\/ app\/Http\/Middleware\/SecurityHeadersMiddleware.php\n   class SecurityHeadersMiddleware\n   {\n       public function handle($request, Closure $next)\n       {\n           $response = $next($request);\n\n           $response-&gt;headers-&gt;set('X-Frame-Options', 'DENY');\n           $response-&gt;headers-&gt;set('X-Content-Type-Options', 'nosniff');\n           $response-&gt;headers-&gt;set('X-XSS-Protection', '1; mode=block');\n           $response-&gt;headers-&gt;set('Referrer-Policy', 'strict-origin-when-cross-origin');\n           $response-&gt;headers-&gt;set('Content-Security-Policy', \"default-src 'self'\");\n\n           if (app()-&gt;environment('production')) {\n               $response-&gt;headers-&gt;set('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');\n           }\n\n           return $response;\n       }\n   }<\/pre>\n\n\n\n<ol start=\"3\" class=\"wp-block-list\">\n<li><strong>\u9069\u5207\u306a\u30ed\u30b0\u8a2d\u5b9a<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">   \/\/ config\/logging.php\n   'channels' =&gt; [\n       'stack' =&gt; [\n           'driver' =&gt; 'stack',\n           'channels' =&gt; ['daily', 'slack'],\n           'ignore_exceptions' =&gt; false,\n       ],\n       'daily' =&gt; [\n           'driver' =&gt; 'daily',\n           'path' =&gt; storage_path('logs\/laravel.log'),\n           'level' =&gt; env('LOG_LEVEL', 'debug'),\n           'days' =&gt; 14,\n       ],\n       'slack' =&gt; [\n           'driver' =&gt; 'slack',\n           'url' =&gt; env('LOG_SLACK_WEBHOOK_URL'),\n           'username' =&gt; 'Laravel Log',\n           'emoji' =&gt; ':boom:',\n           'level' =&gt; env('LOG_LEVEL', 'critical'),\n       ],\n   ]<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-17\">\u30d1\u30d5\u30a9\u30fc\u30de\u30f3\u30b9\u6700\u9069\u5316\u306e\u305f\u3081\u306e\u30ad\u30e3\u30c3\u30b7\u30e5\u6226\u7565<\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u30c8\u30fc\u30af\u30f3\u30ad\u30e3\u30c3\u30b7\u30e5\u306e\u5b9f\u88c5<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">   \/\/ app\/Providers\/AuthServiceProvider.php\n   use Illuminate\\Support\\Facades\\Cache;\n\n   public function boot()\n   {\n       Sanctum::authenticateAccessTokensUsing(function ($token, $isValid) {\n           $cacheKey = 'sanctum_token_' . $token-&gt;id;\n\n           return Cache::remember($cacheKey, now()-&gt;addMinutes(5), function () use ($token, $isValid) {\n               return $isValid &amp;&amp; !$token-&gt;expired();\n           });\n       });\n   }<\/pre>\n\n\n\n<ol start=\"2\" class=\"wp-block-list\">\n<li><strong>\u4e0d\u8981\u30c8\u30fc\u30af\u30f3\u306e\u5b9a\u671f\u30af\u30ea\u30fc\u30f3\u30a2\u30c3\u30d7<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">   \/\/ app\/Console\/Commands\/CleanupTokens.php\n   class CleanupTokens extends Command\n   {\n       protected $signature = 'sanctum:cleanup';\n\n       public function handle()\n       {\n           \/\/ \u671f\u9650\u5207\u308c\u30c8\u30fc\u30af\u30f3\u306e\u524a\u9664\n           $expiredTokens = PersonalAccessToken::where('created_at', '&lt;', now()-&gt;subDays(30))\n               -&gt;orWhere('last_used_at', '&lt;', now()-&gt;subDays(7))\n               -&gt;delete();\n\n           \/\/ \u4f7f\u7528\u3055\u308c\u3066\u3044\u306a\u3044\u30c8\u30fc\u30af\u30f3\u306e\u524a\u9664\n           $unusedTokens = PersonalAccessToken::whereNull('last_used_at')\n               -&gt;where('created_at', '&lt;', now()-&gt;subDays(1))\n               -&gt;delete();\n\n           $this-&gt;info('Cleaned up expired and unused tokens.');\n       }\n   }<\/pre>\n\n\n\n<ol start=\"3\" class=\"wp-block-list\">\n<li><strong>\u30ec\u30fc\u30c8\u5236\u9650\u306e\u6700\u9069\u5316<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">   \/\/ routes\/api.php\n   Route::middleware(['auth:sanctum', 'throttle:api'])-&gt;group(function () {\n       \/\/ \u901a\u5e38\u306eAPI\u5236\u9650\n       Route::get('\/user', function () {\n           return auth()-&gt;user();\n       })-&gt;middleware('throttle:60,1');\n\n       \/\/ \u91cd\u8981\u306a\u64cd\u4f5c\u306e\u5236\u9650\n       Route::post('\/sensitive-operation', [Controller::class, 'handle'])\n           -&gt;middleware('throttle:3,1');\n   });<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-18\">\u30c8\u30e9\u30d6\u30eb\u30b7\u30e5\u30fc\u30c6\u30a3\u30f3\u30b0\u3068\u4e00\u822c\u7684\u306a\u554f\u984c\u306e\u89e3\u6c7a\u65b9\u6cd5<\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u8a8d\u8a3c\u30a8\u30e9\u30fc\u306e\u8a3a\u65ad\u3068\u5bfe\u51e6<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">   \/\/ app\/Exceptions\/Handler.php\n   public function render($request, Throwable $exception)\n   {\n       if ($exception instanceof AuthenticationException) {\n           Log::debug('Authentication failed', [\n               'ip' =&gt; $request-&gt;ip(),\n               'user_agent' =&gt; $request-&gt;userAgent(),\n               'headers' =&gt; $request-&gt;headers-&gt;all()\n           ]);\n\n           return response()-&gt;json([\n               'error' =&gt; 'Unauthenticated',\n               'debug_info' =&gt; app()-&gt;environment('local') ? [\n                   'cookies_present' =&gt; $request-&gt;cookies-&gt;all() ? 'yes' : 'no',\n                   'token_present' =&gt; $request-&gt;bearerToken() ? 'yes' : 'no',\n               ] : null\n           ], 401);\n       }\n\n       return parent::render($request, $exception);\n   }<\/pre>\n\n\n\n<ol start=\"2\" class=\"wp-block-list\">\n<li><strong>\u3088\u304f\u3042\u308b\u554f\u984c\u3068\u89e3\u6c7a\u65b9\u6cd5<\/strong> \u554f\u984c \u539f\u56e0 \u89e3\u6c7a\u65b9\u6cd5 CORS \u30a8\u30e9\u30fc \u30c9\u30e1\u30a4\u30f3\u8a2d\u5b9a\u306e\u4e0d\u4e00\u81f4 <code>config\/cors.php<\/code>\u306e<code>allowed_origins<\/code>\u3092\u78ba\u8a8d \u30c8\u30fc\u30af\u30f3\u8a8d\u8a3c\u5931\u6557 \u30bb\u30c3\u30b7\u30e7\u30f3\u8a2d\u5b9a\u306e\u554f\u984c <code>SESSION_DOMAIN<\/code>\u3068<code>SANCTUM_STATEFUL_DOMAINS<\/code>\u3092\u78ba\u8a8d \u30d1\u30d5\u30a9\u30fc\u30de\u30f3\u30b9\u4f4e\u4e0b \u30c8\u30fc\u30af\u30f3\u6570\u306e\u5897\u5927 \u5b9a\u671f\u7684\u306a\u30af\u30ea\u30fc\u30f3\u30a2\u30c3\u30d7\u30b8\u30e7\u30d6\u3092\u5b9f\u884c<\/li>\n\n\n\n<li><strong>\u30c7\u30d0\u30c3\u30b0\u7528\u306e\u30d8\u30eb\u30d1\u30fc\u95a2\u6570<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">   \/\/ app\/Helpers\/AuthDebugger.php\n   class AuthDebugger\n   {\n       public static function diagnose(Request $request)\n       {\n           $issues = [];\n\n           if (!$request-&gt;secure() &amp;&amp; app()-&gt;environment('production')) {\n               $issues[] = 'HTTPS is not enabled';\n           }\n\n           if (!$request-&gt;cookies-&gt;has(config('session.cookie'))) {\n               $issues[] = 'Session cookie is missing';\n           }\n\n           if (!in_array($request-&gt;getHost(), config('sanctum.stateful'))) {\n               $issues[] = 'Domain is not in stateful domains list';\n           }\n\n           return $issues;\n       }\n   }<\/pre>\n\n\n\n<p>\u904b\u7528\u6642\u306e\u91cd\u8981\u306a\u30c1\u30a7\u30c3\u30af\u30dd\u30a4\u30f3\u30c8\uff1a<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u5b9a\u671f\u7684\u306a\u76e3\u8996\u9805\u76ee<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u30a2\u30af\u30c6\u30a3\u30d6\u30c8\u30fc\u30af\u30f3\u6570<\/li>\n\n\n\n<li>\u8a8d\u8a3c\u5931\u6557\u7387<\/li>\n\n\n\n<li>\u30ec\u30fc\u30c8\u5236\u9650\u30d2\u30c3\u30c8\u6570<\/li>\n\n\n\n<li>\u30bb\u30c3\u30b7\u30e7\u30f3\u30b9\u30c8\u30a2\u306e\u30b5\u30a4\u30ba<\/li>\n<\/ul>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u76e3\u67fb\u9805\u76ee<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u4e0d\u6b63\u30a2\u30af\u30bb\u30b9\u306e\u691c\u77e5<\/li>\n\n\n\n<li>\u30c8\u30fc\u30af\u30f3\u306e\u4f7f\u7528\u30d1\u30bf\u30fc\u30f3<\/li>\n\n\n\n<li>\u7570\u5e38\u306a\u30ea\u30af\u30a8\u30b9\u30c8\u30d1\u30bf\u30fc\u30f3<\/li>\n<\/ul>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u30d1\u30d5\u30a9\u30fc\u30de\u30f3\u30b9\u76e3\u8996<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u30ec\u30b9\u30dd\u30f3\u30b9\u30bf\u30a4\u30e0<\/li>\n\n\n\n<li>\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u8ca0\u8377<\/li>\n\n\n\n<li>\u30ad\u30e3\u30c3\u30b7\u30e5\u30d2\u30c3\u30c8\u7387<\/li>\n<\/ul>\n\n\n\n<p>\u3053\u308c\u3089\u306e\u8a2d\u5b9a\u3068\u5bfe\u7b56\u306b\u3088\u308a\u3001\u672c\u756a\u74b0\u5883\u3067\u306e\u5b89\u5b9a\u3057\u305f\u904b\u7528\u304c\u53ef\u80fd\u306b\u306a\u308a\u307e\u3059\u3002<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"i-19\">Laravel Sanctum\u3092\u4f7f\u3063\u305f\u8a8d\u8a3c\u30b7\u30b9\u30c6\u30e0\u306e\u767a\u5c55\u7684\u306a\u4f7f\u3044\u65b9<\/h2>\n\n\n\n<p>Sanctum\u306e\u57fa\u672c\u6a5f\u80fd\u3092\u62e1\u5f35\u3057\u3001\u3088\u308a\u9ad8\u5ea6\u306a\u8a8d\u8a3c\u30b7\u30b9\u30c6\u30e0\u3092\u69cb\u7bc9\u3059\u308b\u305f\u3081\u306e\u5b9f\u88c5\u65b9\u6cd5\u3092\u89e3\u8aac\u3057\u307e\u3059\u3002<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-20\">\u30de\u30eb\u30c1\u30c7\u30d0\u30a4\u30b9\u5bfe\u5fdc\u306e\u5b9f\u88c5\u65b9\u6cd5<\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u30c7\u30d0\u30a4\u30b9\u60c5\u5831\u306e\u7ba1\u7406<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">   \/\/ database\/migrations\/create_user_devices_table.php\n   public function up()\n   {\n       Schema::create('user_devices', function (Blueprint $table) {\n           $table-&gt;id();\n           $table-&gt;foreignId('user_id')-&gt;constrained()-&gt;onDelete('cascade');\n           $table-&gt;string('device_name');\n           $table-&gt;string('device_type');\n           $table-&gt;string('push_token')-&gt;nullable();\n           $table-&gt;timestamp('last_active_at');\n           $table-&gt;timestamps();\n       });\n   }\n\n   \/\/ app\/Models\/UserDevice.php\n   class UserDevice extends Model\n   {\n       protected $fillable = [\n           'device_name',\n           'device_type',\n           'push_token',\n           'last_active_at'\n       ];\n\n       protected $casts = [\n           'last_active_at' =&gt; 'datetime'\n       ];\n   }<\/pre>\n\n\n\n<ol start=\"2\" class=\"wp-block-list\">\n<li><strong>\u30c7\u30d0\u30a4\u30b9\u8a8d\u8a3c\u306e\u62e1\u5f35<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">   \/\/ app\/Http\/Controllers\/Auth\/DeviceController.php\n   class DeviceController extends Controller\n   {\n       public function register(Request $request)\n       {\n           $validated = $request-&gt;validate([\n               'device_name' =&gt; 'required|string',\n               'device_type' =&gt; 'required|in:ios,android,web',\n               'push_token' =&gt; 'nullable|string'\n           ]);\n\n           $device = auth()-&gt;user()-&gt;devices()-&gt;create([\n               'device_name' =&gt; $validated['device_name'],\n               'device_type' =&gt; $validated['device_type'],\n               'push_token' =&gt; $validated['push_token'],\n               'last_active_at' =&gt; now()\n           ]);\n\n           $token = auth()-&gt;user()-&gt;createToken(\n               $device-&gt;device_name,\n               ['*'],\n               now()-&gt;addYear()\n           );\n\n           return response()-&gt;json([\n               'token' =&gt; $token-&gt;plainTextToken,\n               'device' =&gt; $device\n           ]);\n       }\n\n       public function listDevices()\n       {\n           return auth()-&gt;user()-&gt;devices()\n               -&gt;orderBy('last_active_at', 'desc')\n               -&gt;get();\n       }\n\n       public function revokeDevice($deviceId)\n       {\n           $device = auth()-&gt;user()-&gt;devices()-&gt;findOrFail($deviceId);\n           $device-&gt;delete();\n\n           \/\/ \u95a2\u9023\u3059\u308b\u30c8\u30fc\u30af\u30f3\u306e\u524a\u9664\n           auth()-&gt;user()-&gt;tokens()\n               -&gt;where('name', $device-&gt;device_name)\n               -&gt;delete();\n\n           return response()-&gt;json(['message' =&gt; 'Device removed successfully']);\n       }\n   }<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-21\">\u30c8\u30fc\u30af\u30f3\u306e\u6709\u52b9\u671f\u9650\u3068\u81ea\u52d5\u66f4\u65b0\u306e\u5b9f\u88c5<\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u30c8\u30fc\u30af\u30f3\u7ba1\u7406\u306e\u62e1\u5f35<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">   \/\/ app\/Models\/Concerns\/HasAdvancedTokens.php\n   trait HasAdvancedTokens\n   {\n       public function createTokenWithRefresh($name, array $abilities = ['*'])\n       {\n           $token = $this-&gt;createToken($name, $abilities, now()-&gt;addHours(2));\n\n           $refreshToken = Str::random(64);\n           Cache::put(\n               \"refresh_token_{$refreshToken}\",\n               $token-&gt;accessToken-&gt;id,\n               now()-&gt;addDays(30)\n           );\n\n           return [\n               'access_token' =&gt; $token-&gt;plainTextToken,\n               'refresh_token' =&gt; $refreshToken,\n               'expires_in' =&gt; 7200\n           ];\n       }\n\n       public function refreshToken($refreshToken)\n       {\n           $tokenId = Cache::get(\"refresh_token_{$refreshToken}\");\n\n           if (!$tokenId) {\n               throw new AuthenticationException('Invalid refresh token');\n           }\n\n           $oldToken = $this-&gt;tokens()-&gt;find($tokenId);\n\n           if (!$oldToken) {\n               Cache::forget(\"refresh_token_{$refreshToken}\");\n               throw new AuthenticationException('Token not found');\n           }\n\n           \/\/ \u65b0\u3057\u3044\u30c8\u30fc\u30af\u30f3\u306e\u767a\u884c\n           $newToken = $this-&gt;createTokenWithRefresh(\n               $oldToken-&gt;name,\n               $oldToken-&gt;abilities\n           );\n\n           \/\/ \u53e4\u3044\u30c8\u30fc\u30af\u30f3\u306e\u524a\u9664\n           $oldToken-&gt;delete();\n           Cache::forget(\"refresh_token_{$refreshToken}\");\n\n           return $newToken;\n       }\n   }<\/pre>\n\n\n\n<ol start=\"2\" class=\"wp-block-list\">\n<li><strong>\u81ea\u52d5\u66f4\u65b0\u306e\u5b9f\u88c5<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">   \/\/ app\/Http\/Middleware\/CheckTokenExpiration.php\n   class CheckTokenExpiration\n   {\n       public function handle($request, Closure $next)\n       {\n           if (!$request-&gt;user() || !$request-&gt;user()-&gt;currentAccessToken()) {\n               return $next($request);\n           }\n\n           $token = $request-&gt;user()-&gt;currentAccessToken();\n\n           \/\/ \u30c8\u30fc\u30af\u30f3\u306e\u6709\u52b9\u671f\u9650\u304c\u8fd1\u3044\u5834\u5408\u306f\u81ea\u52d5\u66f4\u65b0\n           if ($token-&gt;created_at-&gt;addHours(1)-&gt;isPast()) {\n               $newToken = $request-&gt;user()-&gt;createToken(\n                   $token-&gt;name,\n                   $token-&gt;abilities,\n                   now()-&gt;addHours(2)\n               );\n\n               $response = $next($request);\n\n               return $response-&gt;header('New-Token', $newToken-&gt;plainTextToken);\n           }\n\n           return $next($request);\n       }\n   }<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-22\">\u30ab\u30b9\u30bf\u30e0\u30ac\u30fc\u30c9\u3068\u30dd\u30ea\u30b7\u30fc\u306e\u6d3b\u7528\u65b9\u6cd5<\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u30ab\u30b9\u30bf\u30e0\u30ac\u30fc\u30c9\u306e\u5b9f\u88c5<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">   \/\/ app\/Auth\/Guards\/SanctumDeviceGuard.php\n   class SanctumDeviceGuard extends TokenGuard\n   {\n       protected function validateToken($token)\n       {\n           if (!parent::validateToken($token)) {\n               return false;\n           }\n\n           $device = UserDevice::where('device_name', $token-&gt;name)\n               -&gt;where('user_id', $token-&gt;tokenable_id)\n               -&gt;first();\n\n           if (!$device) {\n               return false;\n           }\n\n           $device-&gt;update(['last_active_at' =&gt; now()]);\n           return true;\n       }\n   }\n\n   \/\/ config\/auth.php\n   'guards' =&gt; [\n       'sanctum-device' =&gt; [\n           'driver' =&gt; 'sanctum-device',\n           'provider' =&gt; 'users',\n       ],\n   ]<\/pre>\n\n\n\n<ol start=\"2\" class=\"wp-block-list\">\n<li><strong>\u9ad8\u5ea6\u306a\u30dd\u30ea\u30b7\u30fc\u306e\u5b9f\u88c5<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">   \/\/ app\/Policies\/DevicePolicy.php\n   class DevicePolicy\n   {\n       public function manageSensitiveData(User $user, UserDevice $device)\n       {\n           \/\/ \u30c7\u30d0\u30a4\u30b9\u304c\u4fe1\u983c\u3067\u304d\u308b\u5834\u5408\u306e\u307f\u8a31\u53ef\n           return $device-&gt;last_active_at-&gt;diffInDays() &lt; 30 &amp;&amp;\n                  $device-&gt;user_id === $user-&gt;id;\n       }\n\n       public function revokeOtherDevices(User $user, UserDevice $device)\n       {\n           \/\/ \u30d7\u30e9\u30a4\u30de\u30ea\u30c7\u30d0\u30a4\u30b9\u306e\u307f\u306b\u8a31\u53ef\n           return $device-&gt;is_primary &amp;&amp; $device-&gt;user_id === $user-&gt;id;\n       }\n   }<\/pre>\n\n\n\n<ol start=\"3\" class=\"wp-block-list\">\n<li><strong>\u30a2\u30af\u30bb\u30b9\u5236\u5fa1\u306e\u5b9f\u88c5\u4f8b<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">   \/\/ routes\/api.php\n   Route::middleware(['auth:sanctum-device'])-&gt;group(function () {\n       Route::post('\/sensitive-data', function (Request $request) {\n           $device = UserDevice::where('device_name', $request-&gt;user()\n               -&gt;currentAccessToken()-&gt;name)\n               -&gt;firstOrFail();\n\n           if ($request-&gt;user()-&gt;cannot('manageSensitiveData', $device)) {\n               return response()-&gt;json([\n                   'message' =&gt; 'This device is not authorized for this operation'\n               ], 403);\n           }\n\n           \/\/ \u51e6\u7406\u306e\u5b9f\u884c\n       });\n   });<\/pre>\n\n\n\n<p>\u3053\u306e\u767a\u5c55\u7684\u306a\u5b9f\u88c5\u306b\u3088\u308a\u3001\u4ee5\u4e0b\u306e\u3088\u3046\u306a\u9ad8\u5ea6\u306a\u6a5f\u80fd\u304c\u5b9f\u73fe\u3067\u304d\u307e\u3059\uff1a<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u5f37\u5316<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u30c7\u30d0\u30a4\u30b9\u3054\u3068\u306e\u8a73\u7d30\u306a\u6a29\u9650\u7ba1\u7406<\/li>\n\n\n\n<li>\u4e0d\u5be9\u306a\u30a2\u30af\u30bb\u30b9\u306e\u691c\u77e5\u3068\u9632\u6b62<\/li>\n\n\n\n<li>\u30c8\u30fc\u30af\u30f3\u306e\u9069\u5207\u306a\u30e9\u30a4\u30d5\u30b5\u30a4\u30af\u30eb\u7ba1\u7406<\/li>\n<\/ul>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u30e6\u30fc\u30b6\u30fc\u4f53\u9a13\u306e\u5411\u4e0a<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u30b7\u30fc\u30e0\u30ec\u30b9\u306a\u30c8\u30fc\u30af\u30f3\u66f4\u65b0<\/li>\n\n\n\n<li>\u30c7\u30d0\u30a4\u30b9\u7ba1\u7406\u6a5f\u80fd\u306e\u63d0\u4f9b<\/li>\n\n\n\n<li>\u304d\u3081\u7d30\u304b\u3044\u30a2\u30af\u30bb\u30b9\u5236\u5fa1<\/li>\n<\/ul>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u904b\u7528\u7ba1\u7406\u306e\u52b9\u7387\u5316<\/strong><\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u30c7\u30d0\u30a4\u30b9\u30a2\u30af\u30c6\u30a3\u30d3\u30c6\u30a3\u306e\u76e3\u8996<\/li>\n\n\n\n<li>\u7570\u5e38\u691c\u77e5\u306e\u81ea\u52d5\u5316<\/li>\n\n\n\n<li>\u30c8\u30fc\u30af\u30f3\u30e9\u30a4\u30d5\u30b5\u30a4\u30af\u30eb\u306e\u81ea\u52d5\u7ba1\u7406<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Warning: Undefined array key &#8220;is_admin&#8221; in \/home\/xs392991\/dexall.co.jp\/public_html\/articles\/wp-content\/themes\/ &#8230; <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[33,12],"tags":[],"class_list":{"0":"post-3193","1":"post","2":"type-post","3":"status-publish","4":"format-standard","6":"category-php-laravel","7":"category-php","8":"nothumb"},"_links":{"self":[{"href":"https:\/\/dexall.co.jp\/articles\/index.php?rest_route=\/wp\/v2\/posts\/3193","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dexall.co.jp\/articles\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dexall.co.jp\/articles\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dexall.co.jp\/articles\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/dexall.co.jp\/articles\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=3193"}],"version-history":[{"count":2,"href":"https:\/\/dexall.co.jp\/articles\/index.php?rest_route=\/wp\/v2\/posts\/3193\/revisions"}],"predecessor-version":[{"id":3195,"href":"https:\/\/dexall.co.jp\/articles\/index.php?rest_route=\/wp\/v2\/posts\/3193\/revisions\/3195"}],"wp:attachment":[{"href":"https:\/\/dexall.co.jp\/articles\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=3193"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dexall.co.jp\/articles\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=3193"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dexall.co.jp\/articles\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=3193"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}