Last active
November 13, 2018 09:47
-
-
Save junkycoder/101ba736c229fc6d840b117fb69d6170 to your computer and use it in GitHub Desktop.
Simple React Native auth factory
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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; | |
}} | |
/> | |
); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* @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