砂肝の料理

砂肝の料理ガイド

砂肝は炒める・揚げる・焼く・茹でるなど、シンプルな味付けでおいしく食べられる万能な部位です。

定番で作りやすい料理

砂肝の塩こしょう炒め 薄切りにして油で炒め、塩・こしょう・にんにくで味付け。おつまみにもおかずにもなります。

砂肝ポン酢(ねぎポン) さっと茹でてスライスし、ねぎ塩ダレ(ねぎ・ごま油・塩・黒胡椒・レモン汁)と和える。

砂肝ガーリック炒め/バター焼き にんにくを炒めて香りを出し、砂肝を加えて塩こしょうや醤油で仕上げるスタミナ系。

おつまみにぴったり

砂肝のアヒージョ オリーブオイルににんにくと唐辛子を入れ、砂肝とキノコを煮る洋風おつまみ。バゲットと相性抜群。

砂肝の唐揚げ 醤油・酒・おろししょうが・にんにくで下味をつけて片栗粉をまぶし、カリッと揚げる。ビールによく合います。

砂肝のオイスターソース炒め 薄切り砂肝と野菜を炒めて、オイスターソースや醤油で味付けする中華風おつまみ。

ご飯のおかずに

砂肝のしょうが焼き しょうが・醤油・みりんのタレで炒めると、ご飯が進む主菜に。

砂肝と野菜の炒め物 にら・ピーマン・もやし・長ねぎなどと一緒に炒めるとボリュームアップ。栄養バランスも◎

砂肝の甘辛煮 醤油・砂糖(はちみつ)・しょうがで煮ると、作り置きやお弁当のおかずに最適。

下処理とおいしく作るコツ

下処理 白い筋を包丁でそぎ落とすか、「筋なし」表示の砂肝を使うと食べやすく調理も簡単。

火加減のポイント 火を通しすぎないことが大切。加熱しすぎると固くなるので、色が変わって中まで火が通ったら早めに火を止めましょう。


ソドムとゴモラ


ソドムとゴモラ:概要

ソドムゴモラは、旧約聖書『創世記』に登場する都市で、神の裁きにより天からの硫黄と火で滅ぼされたとされています。後の預言書でも、神の裁きと滅びの象徴、悪徳や堕落の代名詞として用いられています。

滅亡の経緯

  • 預言者アブラハムの甥ロトとその家族は、神の使いによってソドムから脱出しました
  • 聖書にはソドムの滅亡が詳しく描かれていますが、ゴモラの滅亡の具体的描写はありません
  • ソドムとゴモラに加え、アデマとゼボイムも同時に滅ぼされました(これらの滅亡描写も省略されています)

五つの都市

これらは「五つの都市(Pentapolis)」と呼ばれ、死海周辺の低地(ヨルダン渓谷)に位置していたとされます。五都市のうち、ロトの家族が逃げ込んだゾアルを除く四都市(ソドム、ゴモラ、アデマ、ゼボイム)が神の裁きで滅ぼされ、荒廃の象徴とされています。

罪の内容

聖書における記述

  • **新約聖書「ユダの手紙」**では、ソドムとゴモラが「みだらな行い」と「不自然な肉の欲」によって永遠の火の刑罰を受けたと記されています
  • 『レビ記』18章では、性に関する規定として、近親相姦、姦淫、同性間の性行為、獣姦などが禁じられています

イスラム教の記述

クルアーンにも同様の物語が述べられており、預言者ルート(ロト)に従わなかった民が滅ぼされました。他の民(ノアの洪水、アード族、サムード族など)が偶像崇拝で滅ぼされたのとは異なり、ソドムの住民は男色などの風俗の乱れによって滅ぼされたとされています。

地理的位置

ソドムとゴモラの廃墟は死海南部の湖底に沈んだと伝えられています。これは『創世記』に記された「シディムの谷」とアスファルトの穴の描写が、死海南部の状況と類似していることに基づいています。ただし、死海南岸付近の遺跡と結びつけようとする研究者も存在します。

Auth0のAPIの使い方

https://www.youtube.com/watch?v=Tlk2pT-RKxM

https://developer.okta.com/

https://github.com/JiroYoyogi/auth0-app

Auth0 の API(Authentication API と Management API)の使い方を日本語でわかりやすく整理し、実際のリクエスト例(cURL/Node.js)や設定手順、注意点(セキュリティ・トラブルシューティング)までまとめます。まず概観を示し、そのあと具体例・ベストプラクティスを順に説明します。

概要(何があるか)

  • Authentication API(認証フロー用)
    • /authorize(ブラウザリダイレクトで認可コード / implicit / PKCE)
    • /oauth/token(トークン発行:authorization_code、refresh_token、client_credentials、password など)
    • /userinfo(ID トークンやアクセストークンでユーザー情報取得)
    • パスワードレスやソーシャルログインもこの辺で扱う
  • Management API(ユーザー・接続・クライアント等の管理)
    • ベース URL: https://{YOUR_DOMAIN}/api/v2/
    • 例: /users, /clients, /connections, /rules など
    • アクセスには Machine-to-Machine(M2M)用のアクセストークン(client_credentials)を使う

認証(API を呼ぶためのトークンの取り方)

  • Web/API(サーバー間)操作で Management API を叩くときは client_credentials を使う
    • トークン取得(例: cURL)
      POST https://YOUR_DOMAIN/oauth/token
      content-type: application/json
      
      {
        "client_id": "YOUR_M2M_CLIENT_ID",
        "client_secret": "YOUR_M2M_CLIENT_SECRET",
        "audience": "https://YOUR_DOMAIN/api/v2/",
        "grant_type": "client_credentials"
      }
      
    • レスポンス例(アクセストークンを Authorization: Bearer として使用) { “access_token”: “eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9…”, “expires_in”: 86400, “token_type”: “Bearer” }
  • SPA(ブラウザ)やネイティブアプリでは PKCE を使う(client_secret を渡さない)
  • 認可コードフロー:
    • ユーザーを /authorize へリダイレクト → 承認後 code を受け取り /oauth/token で交換(PKCE を推奨)
  • refresh_token は長期ログインに使えるが、SPA では注意(Refresh Token Rotation を検討)

Management API の使い方(例:ユーザー取得・作成)

githubにブランチを追加して切替

これから「ローカルでブランチを作ってリモート(GitHub)に追加 → そのブランチに切り替える」手順と、逆に「GitHub上でブランチを作ってからローカルで切り替える」手順、あとよく使うコマンドの補足を順に示します。

  1. ローカルで新しいブランチを作ってリモートに追加し、そのブランチに切り替える(推奨)
  • 新しいブランチを作成してすぐ切り替える(git v2.23+ 推奨) git switch -c
  • 古いスタイル(全バージョン対応) git checkout -b
  • 作業してコミットする git add . git commit -m “作業内容の説明”
  • リモート origin に新しいブランチを作ってプッシュし、ローカルブランチに upstream を設定する git push -u origin 説明:-u (–set-upstream) を付けると以降 git push / git pull が簡単になります。
  1. 既にリモートにあるブランチをローカルに取り込み、切り替える
  • 最新のリモート情報を取得 git fetch origin
  • origin/ を追跡するローカルブランチを作って切り替える(推奨) git switch -c –track origin/
  • あるいは古い書き方 git checkout –track origin/
  1. GitHub の Web UI でブランチを作成してからローカルで切り替える
  • GitHub のリポジトリページで、ブランチ選択ドロップダウン(“main” などと書かれた箇所)を開く
  • テキストボックスに新しいブランチ名を入力 → “Create branch: ” を選ぶとリモートブランチが作成されます
  • ローカルで作業するには上の「2)」の手順(git fetch → git switch -c …)を実行してください
  1. GUI/エディタ(例:VS Code)での切り替え
  • VS Code の左下にブランチ名が表示されているのでクリック → “Create new branch” で作成、または一覧から既存ブランチを選んで切り替え
  • 作成後は push でリモートへ送る(VS Code の同期ボタンやコマンドパレットの Git: Push)
  1. よくある注意点とトラブルシュート
  • ブランチ名にスペースは使わない(ハイフンやスラッシュを使う)
  • リモートにプッシュできない場合は権限(保護されたブランチや書き込み権限)を確認
  • 既にローカルに同名ブランチがあると作れないので、その場合は別名にするか既存ブランチを削除・リネームする
  • リモートの更新を取り込みたいときは git fetch → git merge / git rebase あるいは git pull を使う(チームの運用によって rebase/merge を合わせる)

NotebookLM(ノートブックエルエム)

NotebookLM(ノートブックエルエム)は、Googleが提供するAI搭載のメモ・リサーチ支援ツールです。

Googleの高性能AIモデル「Gemini 1.5 Pro」を搭載しており、ユーザーがアップロードした資料(PDFやGoogleドキュメントなど)をAIが読み込み、その内容に基づいて要約、回答、アイデア出しを行ってくれます。

主な特徴と何がすごいのかを簡単にまとめました。

1. 最大の特徴:「自分の資料」だけを元に回答する

ChatGPTなどの一般的なAIチャットボットは、インターネット上の膨大な知識から回答しますが、NotebookLMは**「ユーザーがアップロードしたソース(資料)」のみ**を根拠(ソース)として回答を生成します。これを「グラウンディング」と呼びます。

  • メリット: AI特有の「知ったかぶり(ハルシネーション)」が極めて少なく、信頼性が高い。
  • 用途: 論文の読み込み、社内マニュアルの検索、会議議事録の分析などに最適です。

2. 主な機能

  • 要約とQ&A: 大量の資料を読み込ませて、「この資料の要点は?」「〇〇についての記述はある?」と質問すると、瞬時に回答してくれます。
  • 出典(引用)の明記: 回答の根拠となった箇所(ページ数や段落)を番号で示してくれるため、すぐに元の資料を確認できます。
  • 音声の概要(Audio Overview): これが現在大きな話題になっている機能です。アップロードした資料の内容について、2人のAIホスト(男女)が対話形式(ポッドキャスト風)で議論する音声を生成できます。単なる読み上げではなく、「ここが面白いね」「つまりこういうことか」といった自然な会話で内容を解説してくれます。(※日本語の資料を読み込ませても、現在は主に英語での会話生成が基本ですが、内容は正確に反映されます)

3. 対応しているファイル形式

以下のものを「ソース」として追加できます(1つのノートブックにつき最大50件)。

  • PDF
  • テキストファイル (.txt)
  • Google ドキュメント
  • Google スライド
  • WebサイトのURL
  • クリップボードのテキスト(コピー&ペースト)
  • 音声ファイル(MP3など)

4. プライバシーと料金

  • プライバシー: Googleは、NotebookLMにアップロードされたデータをAIモデルのトレーニングには使用しないと明言しています(個人の機密情報や企業の内部資料も扱いやすい設計です)。
  • 料金: 現在は試験運用版として提供されており、無料で利用できます(Googleアカウントがあれば誰でも使えます)。

どんな時に便利?

  • 学生・研究者: 難解な論文を複数アップロードして、要約させたり、用語解説をさせたりする。
  • ビジネスマン: 会議の議事録や大量の報告書を読み込ませて、決定事項や課題を抽出する。
  • クリエイター: 自分の過去のメモやアイデアを読み込ませて、新しい企画の壁打ち相手にする。

簡単に言うと、**「自分専用の完璧な記憶力を持ったAIアシスタント」**を作れるツールです。

アクセス方法: NotebookLM公式サイト からすぐに試せます。

シンプルなアプリ

以下は「React(SPA)でログイン中のユーザーだけが実行(ボタン押下など)できるシンプルなアプリ」の基本テンプレートです。Auth0 の @auth0/auth0-react を使い、認証済みかどうかでボタンを有効化/API 呼び出しを行います。ローカルで動く最小構成と、Auth0 のアクセストークンを取得して保護されたバックエンド API を呼ぶ例を含めています。

やったこと(この返信で用意したもの)

  • 最小限で動く React SPA のファイル群(Auth0 プロバイダ、ルーティング、保護されたページ、実行ボタン、API 呼び出しの実装例)
  • README にセットアップ手順(Auth0 設定、環境変数、起動方法) 次にできること(必要なら)
  • 実際のバックエンド(Express)と連携するサンプルを追加
  • PKCE の理解やトークン検証の具体例(サーバ側)を付ける

ファイル一覧 — コードをそのままコピーして使えます。

{
  "name": "auth0-react-runner",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-scripts": "5.0.1",
    "react-router-dom": "^6.12.1",
    "@auth0/auth0-react": "^2.1.0"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts eject"
  }
}
```markdown
# Auth0 + React (SPA) - シンプル実行アプリ

概要
- Auth0 を使った認証(@auth0/auth0-react)
- ログイン済みのユーザーだけが「実行」できるシンプル UI(ボタン)
- 必要に応じてアクセストークンを取得して保護された API を呼び出す例あり

前提(Auth0)
1. Auth0 ダッシュボードでアプリを作成(Single Page Application)
2. Allowed Callback URLs, Allowed Logout URLs に `http://localhost:3000` を登録
3. アプリの Client ID と Domain を控える
4. (API を呼ぶ場合)API を Auth0 で作成し、Identifier(例: `https://my-api.example.com`)を控える

環境変数(プロジェクトルートに `.env` を作る)
- REACT_APP_AUTH0_DOMAIN=YOUR_AUTH0_DOMAIN
- REACT_APP_AUTH0_CLIENT_ID=YOUR_CLIENT_ID
- REACT_APP_AUTH0_AUDIENCE=YOUR_API_IDENTIFIER (API を呼ぶ場合に設定)

セットアップ
1. 依存インストール
   npm install
2. 開発サーバ起動
   npm start
3. ブラウザで http://localhost:3000 を開く

動作
- 未ログイン時: ログインボタンを表示
- ログインすると「実行」ボタンが使える(ローカル実行と、アクセストークンを付けて保護 API を呼ぶ例がある)

次のステップ(必要なら)
- 実際のバックエンド(Express 等)を用意してアクセストークンの検証を追加
- トークンのスコープ/ロールに応じた表示制御
- Refresh Token Rotation の導入(長期セッションが必要な場合)

```javascript name=src/index.js
import React from "react";
import { createRoot } from "react-dom/client";
import App from "./App";
import { Auth0ProviderWithHistory } from "./auth/auth0-provider";
import { BrowserRouter as Router } from "react-router-dom";

const container = document.getElementById("root");
const root = createRoot(container);

root.render(
  <Router>
    <Auth0ProviderWithHistory>
      <App />
    </Auth0ProviderWithHistory>
  </Router>
);
```

```javascript name=src/auth/auth0-provider.jsx
import React from "react";
import { Auth0Provider } from "@auth0/auth0-react";
import { useNavigate } from "react-router-dom";

/*
  環境変数:
  - REACT_APP_AUTH0_DOMAIN
  - REACT_APP_AUTH0_CLIENT_ID
  - REACT_APP_AUTH0_AUDIENCE (任意, API 呼び出しをする場合)
*/

export const Auth0ProviderWithHistory = ({ children }) => {
  const navigate = useNavigate();

  const domain = process.env.REACT_APP_AUTH0_DOMAIN;
  const clientId = process.env.REACT_APP_AUTH0_CLIENT_ID;
  const audience = process.env.REACT_APP_AUTH0_AUDIENCE;

  if (!domain || !clientId) {
    return <div>Auth0 の環境変数が設定されていません。</div>;
  }

  const onRedirectCallback = (appState) => {
    navigate(appState?.returnTo || window.location.pathname);
  };

  return (
    <Auth0Provider
      domain={domain}
      clientId={clientId}
      authorizationParams={{
        redirect_uri: window.location.origin,
        audience: audience, // audience を指定すると access_token を取得可能
        scope: "openid profile email",
      }}
      onRedirectCallback={onRedirectCallback}
      useRefreshTokens={false}
    >
      {children}
    </Auth0Provider>
  );
};
```

```javascript name=src/App.jsx
import React from "react";
import { Routes, Route, Link } from "react-router-dom";
import Home from "./pages/Home";
import Dashboard from "./pages/Dashboard";
import { useAuth0 } from "@auth0/auth0-react";
import ProtectedRoute from "./components/ProtectedRoute";

export default function App() {
  const { isLoading } = useAuth0();

  if (isLoading) return <div>Loading auth...</div>;

  return (
    <div style={{ padding: 20 }}>
      <nav style={{ marginBottom: 20 }}>
        <Link to="/">Home</Link> | <Link to="/dashboard">Dashboard</Link>
      </nav>

      <Routes>
        <Route path="/" element={<Home />} />
        <Route
          path="/dashboard"
          element={
            <ProtectedRoute>
              <Dashboard />
            </ProtectedRoute>
          }
        />
      </Routes>
    </div>
  );
}
```

```javascript name=src/components/ProtectedRoute.jsx
import React from "react";
import { useAuth0 } from "@auth0/auth0-react";
import { Navigate } from "react-router-dom";

/*
  ログイン済みでない場合はログインページ(Auth0 のログイン画面)にリダイレクトする簡易保護ルート。
  単純に要認証ページを実現するのに使います。
*/

export default function ProtectedRoute({ children }) {
  const { isAuthenticated, loginWithRedirect, isLoading } = useAuth0();

  if (isLoading) return <div>Loading...</div>;

  if (!isAuthenticated) {
    // loginWithRedirect を呼んでからもどってくる実装にしても良いですが、
    // ここではシンプルにリダイレクト先を / にしてログインを促します。
    loginWithRedirect();
    return <div>Redirecting to login...</div>;
    // あるいは以下のように Navigate を使う:
    // return <Navigate to="/" replace />;
  }

  return children;
}
```

```javascript name=src/pages/Home.jsx
import React from "react";
import { useAuth0 } from "@auth0/auth0-react";

export default function Home() {
  const { loginWithRedirect, logout, isAuthenticated, user } = useAuth0();

  return (
    <div>
      <h1>Auth0 React Runner(サンプル)</h1>
      {isAuthenticated ? (
        <div>
          <p>ようこそ、{user?.name || user?.email}</p>
          <button onClick={() => logout({ logoutParams: { returnTo: window.location.origin } })}>
            ログアウト
          </button>
        </div>
      ) : (
        <div>
          <p>ログインして実行ボタンを使ってみてください。</p>
          <button onClick={() => loginWithRedirect()}>ログイン</button>
        </div>
      )}
    </div>
  );
}
```

```javascript name=src/pages/Dashboard.jsx
import React, { useState } from "react";
import { useAuth0 } from "@auth0/auth0-react";
import { callProtectedApi } from "../utils/api";

/*
  Dashboard は「ログイン中に実行できる」ページの例です。
  - ログイン済みでないと来られない(ProtectedRoute で保護)
  - ローカルの実行(単純な処理)と、保護されたバックエンド API を呼ぶ例を含む
*/

export default function Dashboard() {
  const { getAccessTokenSilently } = useAuth0();
  const [log, setLog] = useState([]);

  const append = (msg) => setLog((l) => [msg, ...l]);

  const doLocalRun = () => {
    append(`実行: ローカル処理が成功しました (${new Date().toLocaleTimeString()})`);
  };

  const doProtectedApiCall = async () => {
    try {
      // API を呼ぶ場合、Auth0 の audience を設定していれば access token を取得可能
      const token = await getAccessTokenSilently();
      append("アクセストークン取得: 成功 (トークン長: " + token.length + ")");
      // 例: 実際の API URL を環境変数等で設定して呼ぶ
      const res = await callProtectedApi("/api/run", token);
      append("API 実行結果: " + JSON.stringify(res));
    } catch (e) {
      console.error(e);
      append("API 実行エラー: " + (e.message || e));
    }
  };

  return (
    <div>
      <h2>Dashboard(実行ページ)</h2>
      <div style={{ marginBottom: 12 }}>
        <button onClick={doLocalRun}>ローカル実行(ログに記録)</button>{" "}
        <button onClick={doProtectedApiCall}>保護 API を呼んで実行</button>
      </div>

      <div>
        <h3>ログ</h3>
        <ul>
          {log.map((l, i) => (
            <li key={i}>{l}</li>
          ))}
        </ul>
      </div>
    </div>
  );
}
```

```javascript name=src/utils/api.js
/*
  保護された API を呼ぶためのヘルパー。
  - token を Authorization: Bearer <token> として渡す
  - サンプルでは同じオリジンの /api/run を叩く想定(実際はバックエンドの URL を指定してください)
*/

export async function callProtectedApi(path = "/api/run", token) {
  if (!token) throw new Error("アクセストークンがありません");

  const res = await fetch(path, {
    method: "POST",
    headers: {
      Authorization: `Bearer ${token}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ action: "run" }),
  });

  if (!res.ok) {
    const text = await res.text();
    throw new Error(`API エラー: ${res.status} ${text}`);
  }

  return res.json();
}
```

使用上のポイント(短く)
- SPA の場合は client_secret をクライアントに置かず、PKCE を用いるか @auth0/auth0-react の内部実装に従う
- Access Token を取得するには Auth0 のアプリ設定で Audience を設定し、Auth0Provider に audience を渡す必要があります
- API を呼ぶときはサーバ側でアクセストークン(JWT)の検証を行う(jwks を用いて署名検証、iss/aud/exp チェック)
- ローカルでテストする場合、バックエンドが無ければ callProtectedApi をモックするか、簡単な Express サーバを用意してください

以下で「React(SPA)フロント」と「保護された Express バックエンド」をつなぎ、Auth0 のアクセストークンを検証して保護されたエンドポイントを実行できる実装を提示します。やったことは:

- Express サーバーを作成し、@auth0/express-jwt + jwks-rsa で JWT(RS256)を検証するミドルウェアを組み込みました。
- /api/run エンドポイントを保護し、認証済みユーザーのみが実行できるようにしました。
- CORS 設定とエラーハンドリング(認証失敗時のレスポンス)を追加しました。
- フロント側の API 呼び出しヘルパーをバックエンド URL を使うように更新する例を用意しました。
- 必要な環境変数と実行手順の README を用意しました。

まずバックエンドのファイル群です。

```json name=backend/package.json
{
  "name": "auth0-express-api",
  "version": "0.1.0",
  "private": true,
  "main": "server.js",
  "scripts": {
    "start": "node server.js",
    "dev": "nodemon server.js"
  },
  "dependencies": {
    "cors": "^2.8.5",
    "dotenv": "^16.0.3",
    "express": "^4.18.2",
    "@auth0/express-jwt": "^7.7.5",
    "jwks-rsa": "^3.0.1",
    "body-parser": "^1.20.2"
  },
  "devDependencies": {
    "nodemon": "^2.0.22"
  }
}
```

```text name=backend/.env.example
# Auth0 設定
# 例:
# AUTH0_DOMAIN=dev-xxxxx.us.auth0.com
# AUTH0_AUDIENCE=https://my-api.example.com

AUTH0_DOMAIN=
AUTH0_AUDIENCE=

# サーバー設定
PORT=4000

# フロント側をホワイトリストに入れる(開発時)
CORS_ORIGIN=http://localhost:3000
```

```javascript name=backend/server.js
require('dotenv').config();
const express = require('express');
const cors = require('cors');
const bodyParser = require('body-parser');
const { expressjwt: jwt } = require('@auth0/express-jwt');
const jwksRsa = require('jwks-rsa');

const app = express();

const PORT = process.env.PORT || 4000;
const AUTH0_DOMAIN = process.env.AUTH0_DOMAIN;
const AUTH0_AUDIENCE = process.env.AUTH0_AUDIENCE;
const CORS_ORIGIN = process.env.CORS_ORIGIN || 'http://localhost:3000';

if (!AUTH0_DOMAIN || !AUTH0_AUDIENCE) {
  console.error('Missing AUTH0_DOMAIN or AUTH0_AUDIENCE in environment. See .env.example');
  process.exit(1);
}

app.use(cors({
  origin: CORS_ORIGIN,
  methods: ['GET', 'POST', 'OPTIONS'],
  allowedHeaders: ['Content-Type', 'Authorization']
}));
app.use(bodyParser.json());

// JWT ミドルウェア: JWKS から公開鍵を取得して署名検証
const checkJwt = jwt({
  // Provide a signing key based on the kid in the header and the signing keys provided by the JWKS endpoint.
  secret: jwksRsa.expressJwtSecret({
    cache: true,
    rateLimit: true,
    jwksRequestsPerMinute: 5,
    // JWKS endpoint
    jwksUri: `https://${AUTH0_DOMAIN}/.well-known/jwks.json`
  }),

  // Validate the audience and the issuer.
  audience: AUTH0_AUDIENCE,
  issuer: `https://${AUTH0_DOMAIN}/`,
  algorithms: ['RS256']
});

// 保護された実行エンドポイント
app.post('/api/run', checkJwt, (req, res) => {
  // express-jwt は署名検証後に req.auth をセットします
  const auth = req.auth || {};
  // ユーザー情報(sub, scope など)は auth に入る
  const userId = auth.sub || 'unknown';
  const now = new Date().toISOString();

  // 実行ロジック(ここは必要に応じて置き換え)
  const result = {
    message: 'Protected action executed successfully',
    executedAt: now,
    user: userId
  };

  res.json(result);
});

// ヘルスチェック(非保護)
app.get('/api/health', (req, res) => {
  res.json({ status: 'ok', time: new Date().toISOString() });
});

// エラーハンドリング (認証エラーを整形して返す)
app.use((err, req, res, next) => {
  if (err.name === 'UnauthorizedError') {
    // express-jwt のエラー
    return res.status(401).json({
      error: 'invalid_token',
      error_description: err.message
    });
  }
  console.error(err);
  res.status(500).json({ error: 'server_error', error_description: err.message || 'Internal Server Error' });
});

app.listen(PORT, () => {
  console.log(`Auth0-protected API listening on http://localhost:${PORT}`);
  console.log(`Auth0 domain: ${AUTH0_DOMAIN}`);
  console.log(`Expected audience: ${AUTH0_AUDIENCE}`);
});
```

````markdown name=backend/README.md
```markdown
# Auth0-protected Express API (サンプル)

このバックエンドは Auth0 が発行した Access Token(JWT、RS256)を検証して保護されたエンドポイントを提供します。

主要エンドポイント
- GET  /api/health  (公開)
- POST /api/run     (保護、Authorization: Bearer <access_token> が必要)

事前準備(Auth0)
1. Auth0 Dashboard で「APIs」から API を作成します。
   - Identifier に任意の値(例: https://my-api.example.com)を設定します。
   - この Identifier をバックエンドの AUTH0_AUDIENCE に設定します。

2. SPA(Single Page Application)用の Application を作成し、
   - Allowed Callback URLs / Allowed Web Origins に `http://localhost:3000` を登録。
   - SPA から access token を取得するために、Auth0Provider に audience を渡します(フロント側の設定)。

セットアップ(ローカル)
1. コピーして .env を作成(backend/.env)
   - AUTH0_DOMAIN=your-tenant.auth0.com
   - AUTH0_AUDIENCE=https://my-api.example.com
   - PORT=4000
   - CORS_ORIGIN=http://localhost:3000

2. 依存インストール
   cd backend
   npm install

3. サーバ起動
   npm start
   (開発時は npm run dev)

フロントと接続する流れ
- フロント(SPA)で @auth0/auth0-react を使い、Auth0Provider に audience を渡すと getAccessTokenSilently() で access token が取得できます。
- 取得したトークンを Authorization: Bearer <token> ヘッダにのせて POST /api/run を呼びます。
- バックエンドは JWKS (/ .well-known/jwks.json) を使って署名検証し、aud/iss/exp をチェックしてリクエストを許可します。

テスト(フロントがない場合の簡易テスト)
- トークンは通常ユーザーのログインを通して取得するため、curl 単体でテストするには
  1) 事前にトークンを取得して(例: OAuth 認可コードで取得)、
  2) curl -X POST http://localhost:4000/api/run -H "Authorization: Bearer <ACCESS_TOKEN>" -d '{}'
- 正常なら 200 と JSON レスポンスが返ります。

セキュリティノート
- audience と issuer を正確に検査してください。
- 本番では CORS、ログ、レート制限、監査ログの設定を再確認してください。
```

次にフロント側での呼び出しを少しだけ更新します(既存プロジェクトに貼り付ける想定)。環境変数の追加例と API ヘルパーの更新です。

Auth0チュートリアル動画

日本語でReact向けAuth0チュートリアル動画

これらは初心者から中級者まで対応しており、認証機能の実装を日本語で段階的に学べるためおすすめです.qiita+2​youtube+1​

  1. https://qiita.com/pilot/items/bf10caffe4fa280815d2
  2. https://zenn.dev/mikakane/articles/react_auth0_tutorial
  3. https://www.youtube.com/watch?v=id4z09Q_L88
  4. https://auth0.com/jp/resources/videos
  5. https://auth0.com/resources/videos/jp-quickstartguide-auth0-demo
  6. https://www.youtube.com/watch?v=jSA7VRR7tXE
  7. https://www.okta.com/jp/demo/auth0-quick-start-demo/
  8. https://zenn.dev/mikakane/scraps/a867c5ce615f1c
  9. https://www.okta.com/jp/demos/passkeys-auth0-demo/
  10. https://auth0.github.io/auth0-react/

ミディアン


ミディアン(ミディアン人)に関する整理

1. 起源と族系

  • ミディアンはアブラハムの息子
    アブラハムとケトラの間に生まれた息子がミディアン。

  • ヨセフ物語との関連
    ヨセフは兄たちに穴に投げ込まれた後、ミディアン人またはイシュマエル人の商人に売られた。


2. モーセとミディアン

● ミディアンへの亡命

  • モーセはエジプト人殺害後、40年間ミディアンで亡命生活を送った。

● ミディアンの祭司エテロ(レウエル)

  • モーセはミディアンの祭司 エテロ(別名レウエル) の娘 ツィポラ と結婚。

  • エテロはモーセに、
    **裁判業務を部下へ委任する司法制度(分権的な裁きの仕組み)**を助言した。

● ホバブの同行要請

  • モーセはレウエルの息子 ホバブ に、約束の地への案内役として同行を求めたが、
    ホバブは故郷に帰ることを望み、同行しなかった。

● シナイ山と火山説

  • 一部の学者は、シナイ山の燃えるような描写は、
    サウジアラビア北西部ハラ・アル・バドル火山の噴火を反映した可能性を指摘。

3. バアル・ペオル事件とミディアン

● ジムリとコズビ

  • バアル・ペオル事件で、

    • イスラエルの男がモアブの娘たちに誘惑され堕落

    • その中で、シメオン族の族長の息子 ジムリ が、
      ミディアン人の女性コズビ と関係を持った

  • 二人はピネハスによって槍で刺し殺された。

● ミディアン征討(民数記31章)

  • その後、イスラエルはミディアン人と戦争を行う。

  • 民数記31章によれば、

    • 処女以外のすべての女性が殺され

    • 町々は焼き払われた

● モアブではなくミディアンへの攻撃理由

  • 『説教壇注解』『ギル聖書注解』などでは、
    神の命令は モアブ人ではなくミディアン人を攻撃せよ という点が強調される。

  • 申命記では、モーセは
    「モアブを苦しめてはならない」
    と命じている。

● 現代の誤解(ピネハス神権運動)

  • 一部の現代運動(ピネハス神権)は物語を
    異人種間結婚禁止の根拠と解釈したが、

    • ミディアン人もアブラハムの子孫であり

    • モーセ自身ミディアン人女性と結婚しているため
      誤った解釈とされる。


4. 士師記時代のミディアン

  • 士師記では、イスラエルはミディアン人の圧政を7年間受ける。

  • しかし ギデオン がわずかな兵を率いてミディアン軍を撃破し、解放した。

ランダム文字列

以下の内容を整理しました。手順どおり実行すれば、Windows環境で openssl を使わずに安全なランダム文字列を生成して AUTH0_SECRET に設定できます。

手順

  1. PowerShell を開く
    スタートメニューで「PowerShell」と検索して起動します。

  2. ランダム文字列を生成する
    PowerShell のプロンプトで次のコマンドをコピーして実行してください(1バイトごとに16進2桁で 32 バイト分を生成し、結合します)。

    -join ((1..32) | ForEach-Object { (Get-Random -Maximum 256).ToString('X2') })
    

    実行すると 64 文字の16進文字列(例: A1B2…)が出力されるので、それをコピーします。

  3. .env.local ファイルを作成・編集する
    プロジェクトのルート(例: C:\Users\seiic\Git\msl8)に .env.local を作成して、コピーした文字列を AUTH0_SECRET に設定します。例:

    AUTH0_SECRET='コピーした文字列をここに貼り付け'
    
  4. サーバーを再起動する
    .env.local を変更したら開発サーバー/アプリを再起動して、環境変数が反映されることを確認してください。

補足

  • .env ファイルは秘密情報が含まれるため、リポジトリにコミットしないでください(.gitignore に .env.local を追加することを推奨します)。
  • もし WSL や Git Bash、別途 OpenSSL をインストールしている場合は openssl での生成も可能ですが、Windows 標準の PowerShell で代替できます。

営業現場

中小企業の営業現場は、人・時間・情報などリソースが限られる中で成果を出さなければならず、“勝率を上げる仕組み”を作れるかどうかが大きな差になります。
以下では、よくある課題 → あるべき姿 → 勝率を上げるための具体的ノウハウの流れで整理します。


中小企業の営業現場が直面する主な「課題」と「あるべき姿」


1. 営業プロセスが属人化している

● 課題

  • ベテラン営業しか売れない

  • 「なぜ受注できたのか/失注したのか」理由が言語化されない

  • 個々の勘と経験に依存

★ あるべき姿

  • 営業プロセスの明確化(型の構築)

  • 誰がやっても一定の成果が出る“再現性のある営業プロセス”


2. 課題ヒアリングが浅く、提案が弱い

● 課題

  • 「御社の課題は何ですか?」と聞いて終わる

  • 顧客は本音や真の課題を言わない

  • 結果、価格勝負になりやすい

★ あるべき姿

  • 顧客の“表層課題”と“真の課題(本質)”を切り分けて聞き出す力

  • 課題 → 解決策 → 投資価値のストーリーを描けること


3. 見込み客フォローが雑・行方不明になる

● 課題

  • 「あの案件どうなってた?」問題

  • 営業日報だけで追いきれない

  • フォロー漏れで競合に持っていかれる

★ あるべき姿

  • 案件管理とフォロー設計が仕組み化されていること

  • 案件ステージごとに“次の一手”が決まっている


4. 営業の勝ちパターンがない(改善しない)

● 課題

  • 成績が運任せ

  • データがない/振り返りがない

  • 勝因・敗因が曖昧

★ あるべき姿

  • 勝ちパターンの可視化(勝っている人の行動・提案・ストーリー)

  • PDCAではなく「FAT(Fast Action Trial)」で高速改善


🔥 中小企業が“勝率を上げる”ための実践ノウハウ


① 営業プロセスをシンプルに体系化する

最低限、この5ステップで十分です。

  1. ターゲティング(誰に売るか)

  2. 初回接触(課題探索)

  3. 診断・課題深掘り

  4. 提案

  5. クロージング・フォロー

👉 まずは簡単に 「型」をつくることが勝率アップの第一歩。