DEV Community

Cover image for Zero to SaaS - Bookmarksy.io Sign in with Twitter
Brandon
Brandon

Posted on

Zero to SaaS - Bookmarksy.io Sign in with Twitter

So at the end of week 2 of 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

A typical user story would look something like this:

The web app can revoke an access token like so:

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}'
Enter fullscreen mode Exit fullscreen mode

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:

// 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();
Enter fullscreen mode Exit fullscreen mode

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://bookmarksy.io) is coming along well!

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

Top comments (0)