Skip to content

Instantly share code, notes, and snippets.

@junkycoder
Last active November 13, 2018 09:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save junkycoder/101ba736c229fc6d840b117fb69d6170 to your computer and use it in GitHub Desktop.
Save junkycoder/101ba736c229fc6d840b117fb69d6170 to your computer and use it in GitHub Desktop.
Simple React Native auth factory
/**
* Usage in React Native component example
*/
import React, { Component } from 'react';
import { NavigationActions } from 'react-navigation';
import Navigator from 'app/navigators/RootNavigator';
import createAuth from './library/auth';
export default class Application extends Component {
navigator = null;
unsubscribe = [];
authentication = createAuth({
url: 'https://example.com/auth',
});
redirectByStateOfAuth(isAuthenticated) {
if (!this.navigator) return;
const action = NavigationActions.navigate({
routeName: isAuthenticated ? 'AppNavigator' : 'AuthNavigator',
});
this.navigator.dispatch(action);
}
componentDidMount() {
// Create auth subscription and push it to unsubscribe functions array
// so we can unsubscribe this later
this.unsubscribe.push(
this.authentication.subscribe(this.redirectByStateOfAuth),
);
}
componentWillUnmount() {
// Remove all subscriptions
this.unsubscribe.forEach(unsubscribe => {
if (typeof unsubscribe === 'function') unsubscribe();
});
this.unsubscribe = [];
}
render() {
return (
<Navigator
ref={nav => {
this.navigator = nav;
}}
/>
);
}
}
/*
* @flow
*/
import { EventEmitter } from 'fbemitter';
import { AsyncStorage } from 'react-native';
const PUBLISH_EVENT_TYPE = 'publish';
const AUTH_TOKEN_STORAGE_KEY = '@token';
const HAS_MORE_TOKENS_STORAGE_KEY = '@has-more-tokens';
export default function createAuth({ url }) {
const emitter = new EventEmitter();
// JWT auth token (value persisted in the storage)
let __token = '';
// Has user more that one auth token?
// (value persisted in the storage)
let __has_more_tokens = false;
// Was user just logged in?
// (this value is not persisted in the storage)
let __just_logged_in = false;
const auth = {
isAuthenticated() {
return !!__token;
},
getToken() {
return __token;
},
/**
* Core addEventListener fuction to subscribe auth activity
*
* @param {Function} callback
* @returns {Function} unsubscribe function
*/
subscribe(callback: Function): Function {
return emitter.addListener(PUBLISH_EVENT_TYPE, callback);
},
async setToken(token: string, silent: boolean = false) {
__token = token;
await AsyncStorage.setItem(
AUTH_TOKEN_STORAGE_KEY,
token ? token : '',
);
if (!silent) {
emitter.emit(PUBLISH_EVENT_TYPE, this.isAuthenticated());
}
},
async setHasMoreTokens(hasMoreTokens: boolean) {
__has_more_tokens = hasMoreTokens;
if (hasMoreTokens) {
await AsyncStorage.setItem(HAS_MORE_TOKENS_STORAGE_KEY, 'yes');
} else {
await AsyncStorage.removeItem(HAS_MORE_TOKENS_STORAGE_KEY);
}
},
getHasMoreTokens() {
return __has_more_tokens;
},
setJustLoggedIn(justLoggedIn: boolean) {
__just_logged_in = justLoggedIn;
},
getJustLoggedIn() {
return __just_logged_in;
},
/**
* Check if user has invitation,
* throws an error if not.
*
* @param {string} email
*/
async checkMail(email: string) {
const headers = new Headers({
Accept: 'application/json',
'Content-Type': 'application/json',
});
const body = JSON.stringify({ email });
const result = await fetch(`${url}/check-email`, {
headers,
method: 'POST',
body,
});
if (!result.ok) {
throw new Error('Check Mail failed');
}
},
/**
* Reset user's PIN code
*
* @param {string} email
*/
async resendPinCode({ email }) {
const headers = new Headers({
Accept: 'application/json',
'Content-Type': 'application/json',
});
const body = JSON.stringify({
email,
});
const result = await fetch(`${url}/reset`, {
headers,
method: 'POST',
body,
});
if (!result.ok) {
throw new Error('Resend PIN code failed');
}
},
/**
* Login with email and PIN code
*
* @param {string} email
*/
async login({ email, code }) {
const headers = new Headers({
Accept: 'application/json',
'Content-Type': 'application/json',
});
const body = JSON.stringify({
email,
PIN: code,
});
const result = await fetch(`${url}/login`, {
headers,
method: 'POST',
body,
});
if (!result.ok) {
throw new Error('Login failed');
}
const [token, ...more] = await result.json();
this.setJustLoggedIn(true);
this.setHasMoreTokens(more.length > 0);
// Must be last one cuz this setter fires publish event.
// getJustLoggedIn and getHasMoreTokens should return actual values
this.setToken(token);
},
/**
* Simple logout function
*/
logout() {
if (this.isAuthenticated()) {
this.setToken(null);
}
},
};
AsyncStorage.getItem(AUTH_TOKEN_STORAGE_KEY).then(token => {
auth.setToken(token);
});
return auth;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment