Zero to SaaS - Bookmarksy.io Sign in with Twitter
Tags: webdev, javascript, beginners, tutorial
Published: 2022-11-15 22:54:16

So at the end of week 2 of [https://bookmarksy.io](https://bookmarksy.io) ‘s development, I now have a (semi) functioning frontend and backend!

I’ll do a technical breakdown of each component in a future post but would like to spend some time talking about the challenges I faced integration twitter authentication.

Initially, I spent some time familiarizing myself with the authorization and authentication flows twitter exposes for app clients. 

The type of app client I’m working with means my best option for authorization is OAuth2.0 with PKCE.

Q. What is OAuth 2 with PKCE?

A. OAuth 2.0 is the industry-standard protocol for authorization. Paired with PKCE (Proof key for code exchange), it helps prevent CSRF (Cross Site Request Forgery) and authorization code injection attacks.

Here’s a diagram of the flow:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jireqzp0ibbk5vuq8djj.png)

A typical user story would look something like this:

- User clicks sign in with twitter
- User is redirected to [https://twitter.com/i/oauth2/authorize?response_type=code&client_id={SOME CLIENT ID}&redirect_uri={SOME CALLBACK URL}&scope={SOME LIST OF SCOPES TO AUTHORIZE}&state={SOME STATE CODE}&code_challenge={SOME CODE CHALLENGE}&code_challenge_method={SOME CODE CHALLENGE METHOD}](https://www.notion.so/1ae3645697cf4cc4a4221c60b96b0591)
- user accepts authorization request
- user is redirected to {SOME CALLBACK URL} containing code and state in query string. e.g:
    - [https://example.com?code={SOME AUTHORIZATION CODE}&state={SOME AUTHORIZATION STATE}](https://example.com?code={SOME)
- Web app then requests an access token on behalf of the user using the code returned. E.g:
    
    ```bash
    curl --location --request POST 'https://api.twitter.com/2/oauth2/token' \
    --header 'Content-Type: application/x-www-form-urlencoded' \
    --header 'Authorization: Basic {SOME AUTH TOKEN FOR YOUR APP}'\
    --data-urlencode 'code={YOUR CODE RETURNED FROM CALLBACK}' \
    --data-urlencode 'grant_type=authorization_code' \
    --data-urlencode 'redirect_uri=https://www.example.com' \
    --data-urlencode 'code_verifier=challenge'
    ```
    
- Access token is stored and used to make API requests.

The web app can revoke an access token like so:

```bash
curl --location --request POST 'https://api.twitter.com/2/oauth2/revoke' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'Authorization: Basic {SOME AUTH TOKEN FOR YOUR APP}'\
--data-urlencode 'token={SOME ACCESS TOKEN TO REVOKE}'
```

Initially, I tried to implement this by hand with the physical endpoints, which worked fine after some time, but after stumbling upon the twitter API SDK, I found a much more elegant solution https://github.com/twitterdev/twitter-api-typescript-sdk.

So now the code looks something like this:

```tsx
// create an oauth2 client
const authClient = new auth.OAuth2User({
  client_id: process.env.CLIENT_ID,
  client_secret: process.env.CLIENT_SECRET,
  callback: "http://127.0.0.1:3000/callback",
  scopes: ["tweet.read", "users.read", "offline.access"],
});

const client = new Client(authClient);

// redirect client to this url
const authUrl = authClient.generateAuthURL({
  code_challenge_method: "s256",
});

// after authorization, retrieve code from query param
await authClient.requestAccessToken(code);

// revoke token
const response = await authClient.revokeAccessToken();
```

Which works wonderfully! 

My only concern at the moment is that the `revokeAccessToken` doesn’t use a parsed access token, so I’m unsure as to how exactly it knows which token to revoke access to and whether this will impact multiple users.

But otherwise, [https://twitter.com/bookmarksy_io](https://twitter.com/bookmarksy_io) (https://bookmarksy.io) is coming along well! 

Follow the journey on twitter [bookmarksy_io](https://twitter.com/bookmarksy_io) or [brandonkpbailey](https://twitter.com/brandonkpbailey) and join the waitlist! [https://brandonkpbailey.substack.com/](https://brandonkpbailey.substack.com/)