From fa62a14db63c703ec9c1f99f90c1963538e22cbc Mon Sep 17 00:00:00 2001 From: na2hiro Date: Sun, 12 Jan 2025 12:15:48 +0900 Subject: [PATCH] s/twitter.com/x.com/g --- README.md | 20 +++++++++++++++----- src/Twitter1Strategy.ts | 10 +++++----- src/Twitter2Strategy.ts | 2 +- src/oauth2Api.ts | 6 +++--- test/Twitter1Strategy.test.ts | 14 +++++++------- test/Twitter2Strategy.test.ts | 10 +++++----- 6 files changed, 36 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 7e79e39..dff7011 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Remix Auth Twitter ![example branch parameter](https://github.com/na2hiro/remix-auth-twitter/actions/workflows/main.yml/badge.svg?branch=main) -Remix Auth plugin for Twitter [OAuth 2.0](https://developer.twitter.com/en/docs/authentication/oauth-2-0/user-access-token) and [1.0a](https://developer.twitter.com/en/docs/authentication/oauth-1-0a/obtaining-user-access-tokens). +Remix Auth plugin for Twitter [OAuth 2.0](https://developer.x.com/en/docs/authentication/oauth-2-0/user-access-token) and [1.0a](https://developer.x.com/en/docs/authentication/oauth-1-0a/obtaining-user-access-tokens). ## Supported runtimes @@ -9,9 +9,9 @@ Remix Auth plugin for Twitter [OAuth 2.0](https://developer.twitter.com/en/docs/ | Node.js | ✅ | | Cloudflare | ✅ | -## Demo +## Example -Try out ~~[live demo](https://remix-auth-twitter-example.na2hiro.workers.dev/)~~ Currently it doesn't work due to updates on Twitter APIs. You could try cloning the [source code](https://github.com/na2hiro/remix-auth-twitter-example) +See [example repo](https://github.com/na2hiro/remix-auth-twitter-example) ## Installation @@ -20,11 +20,21 @@ Install `remix-auth-twitter` npm module along with `remix-auth`: ```shell npm install remix-auth-twitter remix-auth ``` + +### Compatibility + +| remix-auth-twitter | remix-auth | other notes | +|--------------------|------------|-----------------------| +| @2 | @3 | Points to twitter.com | +| @3 | @3 | Points to x.com | +| @4 (coming soon) | @4 | Points to x.com | + + ## How to use ### Prerequisites -* Your app is registered to Twitter and you have client ID and secret (OAuth 2.0) or [consumer key and secret (OAuth 1.0a)](https://developer.twitter.com/en/docs/authentication/oauth-1-0a/api-key-and-secret) +* Your app is registered to Twitter and you have client ID and secret (OAuth 2.0) or [consumer key and secret (OAuth 1.0a)](https://developer.x.com/en/docs/authentication/oauth-1-0a/api-key-and-secret) * Your app has [remix-auth](https://github.com/sergiodxa/remix-auth) set up and `authenticator` is provided: ```typescript // app/services/auth.server.ts @@ -33,7 +43,7 @@ npm install remix-auth-twitter remix-auth ### Tell the Authenticator to use the Twitter strategy (OAuth 2.0) -Note that profile is not passed to the verify function as it was done for 1.0a. You need to manually hit [/2/users/me](https://developer.twitter.com/en/docs/twitter-api/users/lookup/api-reference/get-users-me) for example in order to retrieve user's id, screen name, etc. The example uses [`twitter-api-v2`](https://github.com/PLhery/node-twitter-api-v2) to do so. +Note that profile is not passed to the verify function as it was done for 1.0a. You need to manually hit [/2/users/me](https://developer.x.com/en/docs/twitter-api/users/lookup/api-reference/get-users-me) for example in order to retrieve user's id, screen name, etc. The example uses [`twitter-api-v2`](https://github.com/PLhery/node-twitter-api-v2) to do so. ```typescript jsx // app/services/auth.server.ts diff --git a/src/Twitter1Strategy.ts b/src/Twitter1Strategy.ts index 609af85..24146b6 100644 --- a/src/Twitter1Strategy.ts +++ b/src/Twitter1Strategy.ts @@ -17,10 +17,10 @@ import { fixedEncodeURIComponent } from "./utils"; let debug = createDebug("TwitterStrategy"); -const requestTokenURL = "https://api.twitter.com/oauth/request_token"; -const authorizationURL = "https://api.twitter.com/oauth/authorize"; -const authenticationURL = "https://api.twitter.com/oauth/authenticate"; -const tokenURL = "https://api.twitter.com/oauth/access_token"; +const requestTokenURL = "https://api.x.com/oauth/request_token"; +const authorizationURL = "https://api.x.com/oauth/authorize"; +const authenticationURL = "https://api.x.com/oauth/authenticate"; +const tokenURL = "https://api.x.com/oauth/access_token"; export interface Twitter1StrategyOptions { consumerKey: string; @@ -44,7 +44,7 @@ export interface Twitter1StrategyVerifyParams { export const Twitter1StrategyDefaultName = "twitter1"; /** - * Twitter's OAuth 1.0a login (https://developer.twitter.com/en/docs/authentication/oauth-1-0a/obtaining-user-access-tokens) + * Twitter's OAuth 1.0a login (https://developer.x.com/en/docs/authentication/oauth-1-0a/obtaining-user-access-tokens) * * Applications must supply a `verify` callback, for which the function signature is: * diff --git a/src/Twitter2Strategy.ts b/src/Twitter2Strategy.ts index 7f17673..a38af75 100644 --- a/src/Twitter2Strategy.ts +++ b/src/Twitter2Strategy.ts @@ -32,7 +32,7 @@ export interface Twitter2StrategyVerifyParams { export const Twitter2StrategyDefaultName = "twitter2"; /** - * Twitter's OAuth 2.0 login (https://developer.twitter.com/en/docs/authentication/oauth-2-0/user-access-token) + * Twitter's OAuth 2.0 login (https://developer.x.com/en/docs/authentication/oauth-2-0/user-access-token) * * Applications must supply a `verify` callback, for which the function signature is: * diff --git a/src/oauth2Api.ts b/src/oauth2Api.ts index d2f85c3..2fe3ebe 100644 --- a/src/oauth2Api.ts +++ b/src/oauth2Api.ts @@ -1,6 +1,6 @@ import { generateRandomString } from "./utils"; -// https://developer.twitter.com/en/docs/authentication/oauth-2-0/authorization-code +// https://developer.x.com/en/docs/authentication/oauth-2-0/authorization-code export type Scope = | "tweet.read" | "tweet.write" @@ -38,7 +38,7 @@ export function buildAuthorizeUrl( code_challenge_method: "plain", }); - let url = new URL("https://twitter.com/i/oauth2/authorize"); + let url = new URL("https://x.com/i/oauth2/authorize"); url.search = params.toString(); return { url, state, challenge }; @@ -62,7 +62,7 @@ export async function requestToken( code_verifier: challenge, }); - const url = new URL("https://api.twitter.com/2/oauth2/token"); + const url = new URL("https://api.x.com/2/oauth2/token"); url.search = params.toString(); return await fetch(url.toString(), { diff --git a/test/Twitter1Strategy.test.ts b/test/Twitter1Strategy.test.ts index 166acd4..2dd43de 100644 --- a/test/Twitter1Strategy.test.ts +++ b/test/Twitter1Strategy.test.ts @@ -101,7 +101,7 @@ describe(Twitter1Strategy, () => { assertResponse(error); expect(fetchMock.mock.calls[0][0]).toMatchInlineSnapshot( - `"https://api.twitter.com/oauth/request_token?oauth_callback=https%3A%2F%2Fexample.com%2Fcallback&oauth_consumer_key=MY_CLIENT_ID&oauth_nonce=abcdefg&oauth_timestamp=NaN&oauth_version=1.0&oauth_signature_method=HMAC-SHA1&oauth_signature=1X41i0CFd3rGyZCbyb%2BH5WPMbts%3D"` + `"https://api.x.com/oauth/request_token?oauth_callback=https%3A%2F%2Fexample.com%2Fcallback&oauth_consumer_key=MY_CLIENT_ID&oauth_nonce=abcdefg&oauth_timestamp=NaN&oauth_version=1.0&oauth_signature_method=HMAC-SHA1&oauth_signature=1X41i0CFd3rGyZCbyb%2BH5WPMbts%3D"` ); expect(error.status).toBe(401); @@ -118,7 +118,7 @@ describe(Twitter1Strategy, () => { const url = new URL(req.url); url.search = ""; switch (url.toString()) { - case "https://api.twitter.com/oauth/request_token": + case "https://api.x.com/oauth/request_token": return { body: "oauth_token=REQUEST_TOKEN&oauth_token_secret=REQUEST_TOKEN_SECRET&oauth_callback_confirmed=true", init: { @@ -136,12 +136,12 @@ describe(Twitter1Strategy, () => { assertResponse(error); expect(fetchMock.mock.calls[0][0]).toMatchInlineSnapshot( - `"https://api.twitter.com/oauth/request_token?oauth_callback=https%3A%2F%2Fexample.com%2Fcallback&oauth_consumer_key=MY_CLIENT_ID&oauth_nonce=abcdefg&oauth_timestamp=NaN&oauth_version=1.0&oauth_signature_method=HMAC-SHA1&oauth_signature=1X41i0CFd3rGyZCbyb%2BH5WPMbts%3D"` + `"https://api.x.com/oauth/request_token?oauth_callback=https%3A%2F%2Fexample.com%2Fcallback&oauth_consumer_key=MY_CLIENT_ID&oauth_nonce=abcdefg&oauth_timestamp=NaN&oauth_version=1.0&oauth_signature_method=HMAC-SHA1&oauth_signature=1X41i0CFd3rGyZCbyb%2BH5WPMbts%3D"` ); let redirect = error.headers.get("Location"); expect(redirect).toMatchInlineSnapshot( - `"https://api.twitter.com/oauth/authenticate?oauth_token=REQUEST_TOKEN"` + `"https://api.x.com/oauth/authenticate?oauth_token=REQUEST_TOKEN"` ); } }); @@ -200,7 +200,7 @@ describe(Twitter1Strategy, () => { const url = new URL(req.url); url.search = ""; switch (url.toString()) { - case "https://api.twitter.com/oauth/access_token": + case "https://api.x.com/oauth/access_token": return { body: "oauth_token=ACCESS_TOKEN&oauth_token_secret=ACCESS_TOKEN_SECRET&screen_name=na2hiro&user_id=123", init: { @@ -233,7 +233,7 @@ describe(Twitter1Strategy, () => { }); expect(fetchMock.mock.calls[0][0]).toMatchInlineSnapshot( - `"https://api.twitter.com/oauth/access_token"` + `"https://api.x.com/oauth/access_token"` ); expect(fetchMock.mock.calls[0][1]!.body!.toString()).toMatchInlineSnapshot( `"oauth_token=TOKEN&oauth_verifier=VERIFIER&oauth_consumer_key=MY_CLIENT_ID"` @@ -254,7 +254,7 @@ describe(Twitter1Strategy, () => { const url = new URL(req.url); url.search = ""; switch (url.toString()) { - case "https://api.twitter.com/oauth/access_token": + case "https://api.x.com/oauth/access_token": return { body: "oauth_token=ACCESS_TOKEN&oauth_token_secret=ACCESS_TOKEN_SECRET", init: { diff --git a/test/Twitter2Strategy.test.ts b/test/Twitter2Strategy.test.ts index 413af15..6e4a66d 100644 --- a/test/Twitter2Strategy.test.ts +++ b/test/Twitter2Strategy.test.ts @@ -98,7 +98,7 @@ describe(Twitter2Strategy, () => { let redirect = error.headers.get("Location"); expect(redirect).toMatchInlineSnapshot( - `"https://twitter.com/i/oauth2/authorize?response_type=code&client_id=MY_CLIENT_ID&redirect_uri=https%3A%2F%2Fexample.com%2Fcallback&scope=tweet.write+tweet.read+users.read&state=MOCKED_RANDOM_CHARS_16&code_challenge=MOCKED_RANDOM_CHARS_43&code_challenge_method=plain"` + `"https://x.com/i/oauth2/authorize?response_type=code&client_id=MY_CLIENT_ID&redirect_uri=https%3A%2F%2Fexample.com%2Fcallback&scope=tweet.write+tweet.read+users.read&state=MOCKED_RANDOM_CHARS_16&code_challenge=MOCKED_RANDOM_CHARS_43&code_challenge_method=plain"` ); } }); @@ -159,7 +159,7 @@ describe(Twitter2Strategy, () => { const url = new URL(req.url); url.search = ""; switch (url.toString()) { - case "https://api.twitter.com/2/oauth2/token": + case "https://api.x.com/2/oauth2/token": return { body: JSON.stringify({ token_type: "bearer", @@ -207,7 +207,7 @@ describe(Twitter2Strategy, () => { const url = new URL(req.url); url.search = ""; switch (url.toString()) { - case "https://api.twitter.com/2/oauth2/token": + case "https://api.x.com/2/oauth2/token": return { body: JSON.stringify({ token_type: "bearer", @@ -247,7 +247,7 @@ describe(Twitter2Strategy, () => { }); expect(fetchMock.mock.calls[0][0]).toMatchInlineSnapshot( - `"https://api.twitter.com/2/oauth2/token?code=TOKEN&grant_type=authorization_code&client_id=MY_CLIENT_ID&redirect_uri=https%3A%2F%2Fexample.com%2Fcallback&code_verifier=undefined"` + `"https://api.x.com/2/oauth2/token?code=TOKEN&grant_type=authorization_code&client_id=MY_CLIENT_ID&redirect_uri=https%3A%2F%2Fexample.com%2Fcallback&code_verifier=undefined"` ); expect(verify).toHaveBeenLastCalledWith({ @@ -264,7 +264,7 @@ describe(Twitter2Strategy, () => { const url = new URL(req.url); url.search = ""; switch (url.toString()) { - case "https://api.twitter.com/2/oauth2/token": + case "https://api.x.com/2/oauth2/token": return { body: JSON.stringify({ access_token: "TOKEN",