Skip to content

Instantly share code, notes, and snippets.

@burdiuz
Last active March 11, 2019 22:33
Show Gist options
  • Save burdiuz/0256a2436e814f315f36713088efb49e to your computer and use it in GitHub Desktop.
Save burdiuz/0256a2436e814f315f36713088efb49e to your computer and use it in GitHub Desktop.
React Native component built to login users and obtain accessToken via callback
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { WebView } from 'react-native';
const WEBVIEW_URL = 'https://github.com/login/oauth/authorize';
const TOKEN_URL = 'https://github.com/login/oauth/access_token';
/*
URL that will be displayed after successful login, it should be different to track URL change, so component can grab code
*/
const STATE = `${Date.now()}${Math.random(Math.random())}`;
const getParam = (url, name) => {
const matches = url.match(new RegExp(`(?:&|\\?)${name}=([^&]+)`));
return (matches && decodeURIComponent(matches[1])) || '';
};
class GithubSignin extends Component {
static propTypes = {
/*
Client Id of your GitHub application
*/
clientId: PropTypes.string.isRequired,
/*
Client Secret of your GitHub application
*/
clientSecret: PropTypes.string.isRequired,
/*
Permissions
*/
scope: PropTypes.string.isRequired,
/*
Callback for successful login, passes object with accessToken as argument
*/
onSignInComplete: PropTypes.func.isRequired,
/*
Callback for failed login, passes error object as argument
*/
onSignInError: PropTypes.func.isRequired,
redirectUri: PropTypes.string,
state: PropTypes.string,
/*
Optional callback called when user logged in and redirect to "redirectUri" was requested
*/
onCodeReceived: PropTypes.func,
};
static defaultProps = {
state: STATE,
redirectUri: '',
onCodeReceived: undefined,
};
state = {
codeReceived: false,
};
get signInUri() {
const { clientId, redirectUri, scope, state } = this.props;
const params = `?client_id=${encodeURIComponent(clientId)}&scope=${encodeURIComponent(
scope,
)}&state=${encodeURIComponent(state)}${
redirectUri ? `&redirect_uri=${encodeURIComponent(redirectUri)}` : ''
}`;
return `${WEBVIEW_URL}${params}`;
}
handleWebViewReference = (webView) => {
this.webView = webView;
};
handleNavigationStateChange = (params) => {
const { url, loading } = params;
const { redirectUri, state, onCodeReceived } = this.props;
if (!loading || this.state.codeReceived) {
return;
}
const code = getParam(url, 'code');
const remoteState = getParam(url, 'state');
const errorCode = getParam(url, 'error');
const errorDescription = getParam(url, 'error_description');
if ((!redirectUri || url.indexOf(redirectUri) === 0) && code && state === remoteState) {
this.setState({ codeReceived: true });
if (onCodeReceived) {
onCodeReceived(code);
}
this.sendTokenRequest(code);
return;
}
if (errorCode) {
const error = new Error(errorCode);
error.description = errorDescription;
this.props.onSignInError(error);
}
};
sendTokenRequest(code) {
const { clientId, clientSecret, redirectUri, state } = this.props;
const headers = new Headers({
Accept: 'application/json',
'Content-Type': 'application/json',
});
return fetch(TOKEN_URL, {
method: 'POST',
headers,
body: JSON.stringify({
code,
state,
client_id: clientId,
client_secret: clientSecret,
redirect_uri: encodeURIComponent(redirectUri),
}),
})
.catch((error) => {
this.props.onSignInError(error);
return Promise.reject(error);
})
.then((response) => response.json())
.then((data) => {
const { onSignInError, onSignInComplete } = this.props;
const { error } = data || {};
const handler = error ? onSignInError : onSignInComplete;
handler(data);
return data;
});
}
render() {
const { scope, style, state, ...props } = this.props;
return (
<WebView
{...props}
ref={this.handleWebViewReference}
source={{ uri: this.signInUri }}
onNavigationStateChange={this.handleNavigationStateChange}
style={style}
/>
);
}
}
export default GithubSignin;
{
"name": "GithubSignIn",
"description": "React Native component built to login users and obtain accessToken via callback",
"version": "0.0.2",
"main": "GithubSignIn.js",
"dependencies": {
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment