Twitter / X OAuth 2.0 social login in react native

Eranga Dulshan
5 min readJun 24, 2024

--

I recently wanted to have sign in with X integrated to one of my react native apps. There are libraries that can be used for google and Linkedin in react-native. But I could not find an existing working that works for Twitter. So here is how I implemented the Twitter login.

If you know how OAuth works you can jump in to Setting up a Twitter App section. If you just want the code, you can check here. https://github.com/ErangaD/TwitterOAuth

First of all, I think it is better to have an idea of how X’s OAuth 2.0 works. First, we have to create an app in X’s developer console, where we will get a client ID and a client secret for the app. When the user logs in, it means that we get access to the X user data through that app.

Then, we request X’s authorization URL with the client ID and relevant scopes that we need, along with a redirection URL. We also have to set the allowed redirection URLs in the X console (we will get back to that later).

What X, or any other OAuth provider, does is verify the client ID and redirect URL provided. If they match, it will call or request the provided redirect URL with a specific code parameter attached to it.

Then, with that code and the client secret (that we obtained for the app created in X’s console), we request X’s token URL to get a token. This token allows us to access user data.

Ideally, we should not store both the client ID and client secret on the mobile side due to security risks. We need the client secret to obtain the final access token using the code that comes with the redirect URI. Therefore, we can provide a server URL as a redirect URI and handle the token retrieval process on the backend.

In this blog, to demonstrate how this works, I have implemented the final access token retrieval process on the client side (mobile app).

Setting up a Twitter App

First go to the Twitter/X Apps. You should see the default X project there.

In the app settings you can see the edit option.

When you scroll down you will see the app section. Add a website url and the redirect/callback urls. You can directly use the redirect url that I have used https://erangad.github.io/TwitterOAuth if you do not have one already. What I have used is a github page (source -> index.html file in the repo) that acts as a redirect url.

Then you can copy the clientID and client secret from the keys and tokens section.

Now you have completed the Twitter / X side of configurations required.

So let’s get to coding. Here is my demo repo link that I am going to explain here.

https://github.com/ErangaD/TwitterOAuth

If you are cloning the above repo make sure you replace the relevant clientID and clientSecret within the code (App.tsx).

I have installed following additional modules.

react-native-inappbrowser-reborn

uuid

query-string

react-native-get-random-values

ramda

Make sure that you have setup the deep links as well. In the above repo I have setup following as the deep link.

my-scheme://

You can find more on setting up deep links in

https://github.com/proyecto26/react-native-inappbrowser/tree/1f7299782c57f849b2256277ef1c20f50c13db9a#authentication-flow-using-deep-linking

When the login button is pressed, the first thing we do is opening the Twitter authorization url with additional url parameters using the InAppBrowser installed.

const onLoginPressed = async () => {
const deepLink = getDeepLink('callback');
const authState = uuid();
const inappBorwserAuthURL = `${AUTHORIZATION_URL}?${querystring.stringify({
response_type: 'code',
client_id: clientID,
scope: permissions!.join(' ').trim(),
state: authState,
redirect_uri: `${redirectUri}?redirect_url=${encodeURIComponent(
deepLink,
)}`,
code_challenge: authState,
code_challenge_method: 'plain',
})}`;

try {
if (await InAppBrowser.isAvailable()) {
InAppBrowser.openAuth(inappBorwserAuthURL, deepLink, {
ephemeralWebSession: false,
enableUrlBarHiding: true,
enableDefaultShare: false,
}).then(async (response: any) => {
const {code} = getCodeAndStateFromUrl(response.url);
const token = await getAccessToken(code, authState);
console.log('INFO::accessToken::response::', token); // this is the access token received
});
} else {
Linking.openURL(inappBorwserAuthURL); // in case any error try to open the inbuilt browser
}
} catch (error) {
Linking.openURL(inappBorwserAuthURL); // in case any error try to open the inbuilt browser
}
};

Here note these.

inappBorwserAuthURL has an additional authState which is a generated uuid string this needs to be passed later with the token request.

redirect_uri consists of the provided redirect_url + a deep link schema that is going to be used to navigate back to the app later.

The provided redirect_uri is the github page that I have created https://erangad.github.io/TwitterOAuth. The source code can be found in index.html file of the repo.

Since we provided redirect_uri as the https://erangad.github.io/TwitterOAuth?redirect_url=my-scheme://callback

Twitter is going to redirect our initial request to the above url with two additional parameters (code and state like below).

https://erangad.github.io/TwitterOAuth?redirect_url=my-scheme://callback&code=’**code**’&state=’**state**’

In the github page, what I do is extracting those code and state parameters and passing back via the deep link to the app when the “click to navigate back to the app” link is pressed.

So the response we get from InAppBrowser callback above will have those data and scheme as the response url.

const {code} = getCodeAndStateFromUrl(response.url);

So we then extract that code and state and use that to get the access token.

const getAccessToken = async (code: string, currentAuthState: string) => {
const deepLink = getDeepLink('callback');
const redirectUriWithRedirectUrl = `${redirectUri}?redirect_url=${encodeURIComponent(
deepLink,
)}`;
const payload: string = getPayloadForToken({
clientID,
clientSecret,
code,
redirectUriWithRedirectUrl,
currentAuthState,
});
const token = await fetchToken(payload);
if (token.error) {
return {};
}
return token;
};

Note that we have to use the authState (uuid) that we originally passed with the autorization url when we requested the access token as well.

As I mentioned before, this access token retrieval should ideally be done in the backend. So instead of the custom github page that I created, you can do the code extraction and access token retrieval at the backend and show a success message in the browser and navigate back to the app after that. What I have done is kind of a simulation of that.

So after this is fully complete you will see the token in the console.

const token = await getAccessToken(code, authState);
// this is the access token received
console.log('INFO::accessToken::response::', token);

Happy coding 😃

References

--

--