Skip to content

Commit

Permalink
s/twitter.com/x.com/g
Browse files Browse the repository at this point in the history
  • Loading branch information
na2hiro committed Jan 12, 2025
1 parent b4248dc commit fa62a14
Show file tree
Hide file tree
Showing 6 changed files with 36 additions and 26 deletions.
20 changes: 15 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -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

Expand All @@ -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

Expand All @@ -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
Expand All @@ -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
Expand Down
10 changes: 5 additions & 5 deletions src/Twitter1Strategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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:
*
Expand Down
2 changes: 1 addition & 1 deletion src/Twitter2Strategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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:
*
Expand Down
6 changes: 3 additions & 3 deletions src/oauth2Api.ts
Original file line number Diff line number Diff line change
@@ -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"
Expand Down Expand Up @@ -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 };
Expand All @@ -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(), {
Expand Down
14 changes: 7 additions & 7 deletions test/Twitter1Strategy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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: {
Expand All @@ -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"`
);
}
});
Expand Down Expand Up @@ -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: {
Expand Down Expand Up @@ -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"`
Expand All @@ -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: {
Expand Down
10 changes: 5 additions & 5 deletions test/Twitter2Strategy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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"`
);
}
});
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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({
Expand All @@ -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",
Expand Down

0 comments on commit fa62a14

Please sign in to comment.