<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>!!!0xFOMOer#3825</title>
        <link>https://paragraph.com/@0xfomoer-3825</link>
        <description>Non-Professional Crypto Investor
Alpha Shark: http://linktr.ee/AlphaSharkClub</description>
        <lastBuildDate>Tue, 04 Aug 2026 14:35:17 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <image>
            <title>!!!0xFOMOer#3825</title>
            <url>https://storage.googleapis.com/papyrus_images/71f5ab9f12d2030644a7b7ab640f93a38dedb34da41a7211e7658db58edf0376.png</url>
            <link>https://paragraph.com/@0xfomoer-3825</link>
        </image>
        <copyright>All rights reserved</copyright>
        <item>
            <title><![CDATA[twitter OAUTH2 PKCE 實做紀錄]]></title>
            <link>https://paragraph.com/@0xfomoer-3825/twitter-oauth2-pkce</link>
            <guid>QC6vKs8oboh3cxbamJms</guid>
            <pubDate>Fri, 24 Jun 2022 12:04:04 GMT</pubDate>
            <description><![CDATA[1. 前言本文實做如何使用 OAUTH2 PKCE 的方法，來取得不同帳號間的 access token，如此可以只用一支程式控制多個帳號。 由於需要回到 callback url ，所以使用 flask 以及搭配 tweepy 來實做整體的操作。2. 實做這份實做是參考 twauth_web 來做的，替我省了不少工夫。2.1 twitter developer 設定首先在 twitter 上需進行以下設定ebable oauth 2.0填入callback url，我查到有人是沒有辦法用 localhost ，直接用 ip 是比較快也常見的做法。填入website url，一般來說沒特別，可以填自己的 twitter 即可。2.2 開啟 flask web 與取得使用者 access token在程式一開始除了啟動 flask 外，我們還需要去連接 twitter server 來取得 handler。範例如下oauth2_user_handler = tweepy.OAuth2UserHandler( client_id=Client_ID, redirect_uri="ht...]]></description>
            <content:encoded><![CDATA[<h2 id="h-1" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">1. 前言</h2><p>本文實做如何使用 OAUTH2 PKCE 的方法，來取得不同帳號間的 access token，如此可以只用一支程式控制多個帳號。 由於需要回到 callback url ，所以使用 flask 以及搭配 tweepy 來實做整體的操作。</p><h2 id="h-2" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">2. 實做</h2><p>這份實做是參考 <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://twauth-web">twauth_web</a> 來做的，替我省了不少工夫。</p><h3 id="h-21-twitter-developer" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">2.1 twitter developer 設定</h3><p>首先在 twitter 上需進行以下設定</p><ol><li><p>ebable oauth 2.0</p></li></ol><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/6b208d7e9c0aa8c6c8c1333cfd10ab7e718d7ddad15e4a8e9def1288515770f7.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><ol><li><p>填入callback url，我查到有人是沒有辦法用 localhost ，直接用 ip 是比較快也常見的做法。</p></li><li><p>填入website url，一般來說沒特別，可以填自己的 twitter 即可。</p></li></ol><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/fb40c1341466a26c9c207303edab52705f595d2e2e4d131323cbd23061652dac.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><h3 id="h-22-flask-web-access-token" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">2.2 開啟 flask web 與取得使用者 access token</h3><p>在程式一開始除了啟動 flask 外，我們還需要去連接 twitter server 來取得 handler。範例如下</p><pre data-type="codeBlock" text="oauth2_user_handler = tweepy.OAuth2UserHandler(
    client_id=Client_ID,
    redirect_uri=&quot;http://127.0.0.1:5000/callback&quot;, 
    scope=[&quot;tweet.read&quot;,&quot;tweet.write&quot;, &quot;users.read&quot;, &quot;follows.read&quot;, &quot;follows.write&quot;, &quot;like.read&quot;, &quot;like.write&quot;, &quot;offline.access&quot;],
    # Client Secret is only necessary if using a confidential client
    client_secret=Client_Secret,
)
"><code><span class="hljs-attr">oauth2_user_handler</span> = tweepy.OAuth2UserHandler(
    <span class="hljs-attr">client_id</span>=Client_ID,
    <span class="hljs-attr">redirect_uri</span>=<span class="hljs-string">"http://127.0.0.1:5000/callback"</span>, 
    <span class="hljs-attr">scope</span>=[<span class="hljs-string">"tweet.read"</span>,<span class="hljs-string">"tweet.write"</span>, <span class="hljs-string">"users.read"</span>, <span class="hljs-string">"follows.read"</span>, <span class="hljs-string">"follows.write"</span>, <span class="hljs-string">"like.read"</span>, <span class="hljs-string">"like.write"</span>, <span class="hljs-string">"offline.access"</span>],
    <span class="hljs-comment"># Client Secret is only necessary if using a confidential client</span>
    <span class="hljs-attr">client_secret</span>=Client_Secret,
)
</code></pre><ul><li><p>scope 在 <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://developer.twitter.com/en/docs/authentication/oauth-2-0/authorization-code">twitter developer docs</a> 上可以看到完整的細節，這邊所選取主要是為了可以完成 like/retweet/reply 、 tag 3 位朋友參加抽獎和可以一直 refresh token 。</p></li></ul><p>此外要在 flask 的首頁中開啟 session ，不然在頁面轉換時，會因為 session id 不同，而導致與 twitter 的認證無法通過。</p><pre data-type="codeBlock" text="@app.route(&apos;/&apos;)
def hello():
    session_secret_key= os.urandom(24)
    app.config[&apos;SECRET_KEY&apos;] =session_secret_key
    app.config[&apos;SESSION_COOKIE_NAME&apos;] = &quot;my_session&quot;

    return render_template(&apos;index.html&apos;, SECRET_KEY=session_secret_key)

@app.route(&apos;/callback&apos;)
def callback():
    app.config[&apos;SECRET_KEY&apos;] =session_secret_key
    app.config[&apos;SESSION_COOKIE_NAME&apos;] = &quot;my_session&quot;
"><code>@app.route(<span class="hljs-string">'/'</span>)
def hello():
    session_secret_key<span class="hljs-operator">=</span> os.urandom(<span class="hljs-number">24</span>)
    app.config[<span class="hljs-string">'SECRET_KEY'</span>] <span class="hljs-operator">=</span>session_secret_key
    app.config[<span class="hljs-string">'SESSION_COOKIE_NAME'</span>] <span class="hljs-operator">=</span> <span class="hljs-string">"my_session"</span>

    <span class="hljs-keyword">return</span> render_template(<span class="hljs-string">'index.html'</span>, SECRET_KEY<span class="hljs-operator">=</span>session_secret_key)

@app.route(<span class="hljs-string">'/callback'</span>)
def callback():
    app.config[<span class="hljs-string">'SECRET_KEY'</span>] <span class="hljs-operator">=</span>session_secret_key
    app.config[<span class="hljs-string">'SESSION_COOKIE_NAME'</span>] <span class="hljs-operator">=</span> <span class="hljs-string">"my_session"</span>
</code></pre><p>然後透過下面這行，來產生連到 twitter 做驗證的連節</p><pre data-type="codeBlock" text="authorize_url= oauth2_user_handler.get_authorization_url()
"><code>authorize_url<span class="hljs-operator">=</span> oauth2_user_handler.get_authorization_url()
</code></pre><p>點入連結後，可以看到以下畫面。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/fe6f76f0e342d8e4d2935d8ced1900e7f3958411c5cdcddac9d9e399a7c4f835.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>在點下 Authorize app 後，會回到你所提供的 callback 頁面，這時就可以用取得的 state 和 code ，再去要求 access token ，也因此重複此步驟，你可以得到不同 twitter 帳號的 token 來操作。</p><pre data-type="codeBlock" text="    response= &quot;http://127.0.0.1:5000/callback?state=&quot;+oauth_state+&quot;&amp;code=&quot;+oauth_code
    access_token = oauth2_user_handler.fetch_token(response)
"><code>    response<span class="hljs-operator">=</span> <span class="hljs-string">"http://127.0.0.1:5000/callback?state="</span><span class="hljs-operator">+</span>oauth_state<span class="hljs-operator">+</span><span class="hljs-string">"&#x26;code="</span><span class="hljs-operator">+</span>oauth_code
    access_token <span class="hljs-operator">=</span> oauth2_user_handler.fetch_token(response)
</code></pre><h3 id="h-23-refresh-token" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">2.3 Refresh token</h3><p>雖然我們有使用 offline.access 來取得 token ，但 twitter 仍只給這個 token 兩個小時的有效時間，所以可以用以下的方是來更新 token ，達到一直可以使用的目的，範例如下，</p><pre data-type="codeBlock" text="new_access_token= oauth2_user_handler.refresh_token(access_token[&quot;refresh_token&quot;])
access_token= new_access_token
"><code><span class="hljs-attr">new_access_token</span>= oauth2_user_handler.refresh_token(access_token[<span class="hljs-string">"refresh_token"</span>])
<span class="hljs-attr">access_token</span>= new_access_token
</code></pre><h3 id="h-24" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">2.4 其他指令使用注意</h3><p>由於 ESSENTIAL 只能用 APIv2，且我們又用 ouath2 ，所以很多指令要多給 user_auth= False ，才能確保指令可以被執行。</p><pre data-type="codeBlock" text="client.like(tweet_id, user_auth= False)
client.retweet(tweet_id, user_auth= False)
"><code>client.like(tweet_id, <span class="hljs-attr">user_auth</span>= <span class="hljs-literal">False</span>)
client.retweet(tweet_id, <span class="hljs-attr">user_auth</span>= <span class="hljs-literal">False</span>)
</code></pre><p>如果你也遇到 oauthlib.oauth2.rfc6749.errors.InsecureTransportError 的問題，可以設定以下參數去避開。</p><pre data-type="codeBlock" text="os.environ[&apos;OAUTHLIB_INSECURE_TRANSPORT&apos;] = &apos;1&apos;
"><code>os.environ[<span class="hljs-string">'OAUTHLIB_INSECURE_TRANSPORT'</span>] <span class="hljs-operator">=</span> <span class="hljs-string">'1'</span>
</code></pre><h2 id="h-3" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">3. 指令限制</h2><p>最後要注意的是由於 ESSENTIAL 給與的流量不大，所以很容易不小心爆掉。以我自己為例，我剛上線時，應該是指令短時間內送太快，結果 app 整個被限制，並於八小時後被封鎖。還好可以砍掉重練。</p><h2 id="h-4" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">4. 補充資料</h2><ul><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://mirror.xyz/zlexdl.eth/-SLMZ8BPOIalMcxCwfxdMNIDsAF_0hplA1H0p38t37A">教你开发一个简易的推特白名单机器人</a>，由於我只能用 APIv2 所以裡面許多指令無法套用，但整體的概念是很有用的。</p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://blog.yorkxin.org/posts/oauth2-1-introduction.html">OAuth 2.0 系列文目錄</a>，想深入了解 OAuth 2.0 可以看這篇。</p></li><li><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://cdn.cms-twdigitalassets.com/content/dam/developer-twitter/docs/OAuth.png.twimg.1920.png">Twitter 對 OAuth 2.0 所畫的流程圖</a>，或是可以到<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://developer.twitter.com/en/docs/authentication/oauth-2-0/authorization-code">文件</a>中看，我覺得這個圖很清楚。</p></li></ul>]]></content:encoded>
            <author>0xfomoer-3825@newsletter.paragraph.com (!!!0xFOMOer#3825)</author>
        </item>
    </channel>
</rss>