Merge pull request #3 from expo/use-auth-session

Update Facebook example to use AuthSession API
This commit is contained in:
Adam Perry
2017-09-21 15:39:06 -07:00
committed by GitHub
14 changed files with 758 additions and 806 deletions

3
.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
.expo
.vscode
node_modules

70
with-facebook-auth/App.js Normal file
View File

@@ -0,0 +1,70 @@
import React from 'react';
import { Image, Button, StyleSheet, Text, View } from 'react-native';
import { AuthSession } from 'expo';
const FB_APP_ID = '672636582940821';
export default class App extends React.Component {
state = {
userInfo: null,
};
render() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
{!this.state.userInfo ? (
<Button title="Open FB Auth" onPress={this._handlePressAsync} />
) : (
this._renderUserInfo()
)}
</View>
);
}
_renderUserInfo = () => {
return (
<View style={{ alignItems: 'center' }}>
<Image
source={{ uri: this.state.userInfo.picture.data.url }}
style={{ width: 100, height: 100, borderRadius: 50 }}
/>
<Text style={{ fontSize: 20 }}>{this.state.userInfo.name}</Text>
<Text>ID: {this.state.userInfo.id}</Text>
</View>
);
};
_handlePressAsync = async () => {
let redirectUrl = AuthSession.getRedirectUrl();
// You need to add this url to your authorized redirect urls on your Facebook app
console.log({ redirectUrl });
// NOTICE: Please do not actually request the token on the client (see:
// response_type=token in the authUrl), it is not secure. Request a code
// instead, and use this flow:
// https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow/#confirm
// The code here is simplified for the sake of demonstration. If you are
// just prototyping then you don't need to concern yourself with this and
// can copy this example, but be aware that this is not safe in production.
let result = await AuthSession.startAsync({
authUrl:
`https://www.facebook.com/v2.8/dialog/oauth?response_type=token` +
`&client_id=${FB_APP_ID}` +
`&redirect_uri=${encodeURIComponent(redirectUrl)}`,
});
if (result.type !== 'success') {
alert('Uh oh, something went wrong');
return;
}
let accessToken = result.params.access_token;
let userInfoResponse = await fetch(
`https://graph.facebook.com/me?access_token=${accessToken}&fields=id,name,picture.type(large)`
);
const userInfo = await userInfoResponse.json();
this.setState({ userInfo });
};
}

View File

@@ -4,34 +4,30 @@ Try it at https://expo.io/@community/with-facebook-auth
## How to use
### Running the app
- `cd` into the `app` directory and run `yarn` or `npm install`
- Open `app` with `exp` or XDE, try it out.
- Press "Open FB Auth" in the app and then check your logs. Take the `redirectUrl` that was logged and enter it into the "Valid OAuth redirect URIs" in your Facebook app configuration step below.
### Setting up the Facebook app
- Follow the steps [described in the Facebook for Developers documentation](https://developers.facebook.com/docs/apps/register)
- Add the "Facebook Login" product and configure it ([screenshot](https://raw.githubusercontent.com/expo/examples/master/with-facebook-auth/_assets/add-facebook-login.png))
- Make the app public ([screenshot](https://raw.githubusercontent.com/expo/examples/master/with-facebook-auth/_assets/make-public.png))
### Running the app
- `cd` into the `app` directory and run `yarn` or `npm install`
- Open `app` with `exp` or XDE, try it out.
### Running the server (optional)
- `cd` into the `backend` directory and run `yarn` or `npm install`,
then run `yarn start`
- Swap out the `FB_APP_ID` in `App.js` with your Facebook app's id.
## The idea behind the example
Expo provides a
[WebBrowser](https://docs.expo.io/versions/v15.0.0/sdk/webbrowser.html)
[WebBrowser](https://docs.expo.io/versions/latest/sdk/webbrowser.html)
API that opens a SFSafariViewController or Chrome Custom Tab in a modal
window. This provides a much better user experience than using a
WebView, and it's more secure for your users because code cannot be
injected into these browser windows. Additionally, they share cookies
with the system browser, so there is no need to re-enter credentials if
already authenticated. This example demonstrates how to use this API to
sign in to Facebook. One quirk with Facebook authentication is that they
do not allow you to specify a redirect URI with a custom scheme, so the
backend piece of this example is a small express server that redirects
to our `exp://` URI and passes along the query parameters from the
original redirect.
already authenticated. Expo also provides a wrapper around the `WebBrowser`
API which is called [AuthSession](https://docs.expo.io/versions/latest/sdk/auth-session.html),
which makes setting up an authentication flow using `WebBrowser` dead simple.
This example demonstrates how to use the `AuthSession` API to sign in to
Facebook.

View File

@@ -3,20 +3,11 @@
"name": "with-facebook-auth",
"description": "Using Facebook authentication in Expo, see the source: https://github.com/expo/examples/blob/master/with-facebook-auth",
"slug": "with-facebook-auth",
"sdkVersion": "19.0.0",
"sdkVersion": "21.0.0",
"version": "1.0.0",
"orientation": "portrait",
"primaryColor": "#cccccc",
"privacy": "public",
"icon": "https://s3.amazonaws.com/exp-brand-assets/ExponentEmptyManifest_192.png",
"notification": {
"icon": "https://s3.amazonaws.com/exp-us-standard/placeholder-push-icon-blue-circle.png",
"color": "#000000"
},
"loading": {
"icon": "https://s3.amazonaws.com/exp-brand-assets/ExponentEmptyManifest_192.png",
"hideExponentText": false
},
"packagerOpts": {
"assetExts": [
"ttf",

View File

@@ -1,8 +0,0 @@
{
"presets": ["babel-preset-expo"],
"env": {
"development": {
"plugins": ["transform-react-jsx-source"]
}
}
}

View File

@@ -1,3 +0,0 @@
node_modules/**/*
.expo/*
npm-debug.*

View File

@@ -1,91 +0,0 @@
import { Constants, WebBrowser } from 'expo';
import React from 'react';
import { Alert, Button, Linking, StyleSheet, Text, View } from 'react-native';
import queryString from 'query-string';
const AppID = '288424861584897';
const RedirectURI = __DEV__
? 'https://expo-test.ngrok.io/facebook'
: 'https://redirect-with-params-vwlrmrqtzt.now.sh/facebook';
const FacebookAuthURI = `https://www.facebook.com/v2.8/dialog/oauth?response_type=token&client_id=${AppID}&redirect_uri=${RedirectURI}`;
export default class App extends React.Component {
state = {
url: '', // we will put the redirect url here
accessToken: '', // we will put the token we extract from redirect url here
result: {}, // we will put data about the user here
};
render() {
return (
<View style={styles.container}>
<Button
title="Sign in with Facebook"
onPress={this._handlePressSignIn}
/>
{this._renderResult()}
<Text style={styles.info}>sdkVersion: {Constants.manifest.sdkVersion}</Text>
</View>
);
}
_renderResult = () => {
if (!this.state.url || !this.state.accessToken || !this.state.result) {
return null;
}
return (
<View style={{ padding: 20 }}>
<Text style={{ fontWeight: 'bold' }}>Redirect received to:</Text>
<Text numberOfLines={2}>{this.state.url}</Text>
<Text style={{ fontWeight: 'bold', marginTop: 15 }}>
Extracted this token from the redirect url:
</Text>
<Text numberOfLines={2}>
{this.state.accessToken}
</Text>
<Text style={{ fontWeight: 'bold', marginTop: 15 }}>
For the following user
</Text>
<Text numberOfLines={2}>
{JSON.stringify(this.state.result)}
</Text>
</View>
);
};
_handlePressSignIn = async () => {
Linking.addEventListener('url', this._handleFacebookRedirect);
let result = await WebBrowser.openBrowserAsync(FacebookAuthURI);
console.log({ result });
Linking.removeEventListener('url', this._handleFacebookRedirect);
};
_handleFacebookRedirect = async event => {
WebBrowser.dismissBrowser();
let { access_token: accessToken } = queryString.parse(
queryString.extract(event.url)
);
const response = await fetch(
`https://graph.facebook.com/me?access_token=${accessToken}&fields=id,name,picture.type(large)`
);
const result = await response.json();
this.setState({ accessToken, url: event.url, result });
};
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
info: {
color: '#eee',
},
});

View File

@@ -1 +0,0 @@
node_modules/

View File

@@ -1,10 +0,0 @@
<script>
if (window.location.hash) {
var query = window.location.hash.replace(/^#/,'');
var url = window.location.origin + '/redirect' + '?' + query;
window.location = url;
document.write('Authenticating...');
} else {
document.write('Uh oh something went wrong');
}
</script>

View File

@@ -1,16 +0,0 @@
const app = require('express')();
app.get('/redirect', (req, res) => {
let qs = req._parsedUrl.query;
if (process.env.NODE_ENV === 'development') {
res.redirect('exp://ge-cha.notbrent.app.exp.direct:80/+redirect/?' + qs);
} else {
res.redirect('exp://exp.host/@community/with-facebook-auth/+redirect/?' + qs);
}
});
app.get('/facebook', (req, res) => {
res.sendFile('facebook.html', {root: __dirname });
});
app.listen(3000);

View File

@@ -1,15 +0,0 @@
{
"name": "redirect-with-params",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node index.js"
},
"author": "",
"license": "MIT",
"dependencies": {
"express": "^4.10.2"
}
}

View File

@@ -1,253 +0,0 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
accepts@~1.3.3:
version "1.3.3"
resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.3.tgz#c3ca7434938648c3e0d9c1e328dd68b622c284ca"
dependencies:
mime-types "~2.1.11"
negotiator "0.6.1"
array-flatten@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
content-disposition@0.5.2:
version "0.5.2"
resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4"
content-type@~1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.2.tgz#b7d113aee7a8dd27bd21133c4dc2529df1721eed"
cookie-signature@1.0.6:
version "1.0.6"
resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
cookie@0.3.1:
version "0.3.1"
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb"
debug@2.6.1:
version "2.6.1"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.1.tgz#79855090ba2c4e3115cc7d8769491d58f0491351"
dependencies:
ms "0.7.2"
debug@2.6.3:
version "2.6.3"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.3.tgz#0f7eb8c30965ec08c72accfa0130c8b79984141d"
dependencies:
ms "0.7.2"
depd@1.1.0, depd@~1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.0.tgz#e1bd82c6aab6ced965b97b88b17ed3e528ca18c3"
destroy@~1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80"
ee-first@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
encodeurl@~1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.1.tgz#79e3d58655346909fe6f0f45a5de68103b294d20"
escape-html@~1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
etag@~1.8.0:
version "1.8.0"
resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.0.tgz#6f631aef336d6c46362b51764044ce216be3c051"
express@^4.10.2:
version "4.15.2"
resolved "https://registry.yarnpkg.com/express/-/express-4.15.2.tgz#af107fc148504457f2dca9a6f2571d7129b97b35"
dependencies:
accepts "~1.3.3"
array-flatten "1.1.1"
content-disposition "0.5.2"
content-type "~1.0.2"
cookie "0.3.1"
cookie-signature "1.0.6"
debug "2.6.1"
depd "~1.1.0"
encodeurl "~1.0.1"
escape-html "~1.0.3"
etag "~1.8.0"
finalhandler "~1.0.0"
fresh "0.5.0"
merge-descriptors "1.0.1"
methods "~1.1.2"
on-finished "~2.3.0"
parseurl "~1.3.1"
path-to-regexp "0.1.7"
proxy-addr "~1.1.3"
qs "6.4.0"
range-parser "~1.2.0"
send "0.15.1"
serve-static "1.12.1"
setprototypeof "1.0.3"
statuses "~1.3.1"
type-is "~1.6.14"
utils-merge "1.0.0"
vary "~1.1.0"
finalhandler@~1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.0.1.tgz#bcd15d1689c0e5ed729b6f7f541a6df984117db8"
dependencies:
debug "2.6.3"
encodeurl "~1.0.1"
escape-html "~1.0.3"
on-finished "~2.3.0"
parseurl "~1.3.1"
statuses "~1.3.1"
unpipe "~1.0.0"
forwarded@~0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.0.tgz#19ef9874c4ae1c297bcf078fde63a09b66a84363"
fresh@0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.0.tgz#f474ca5e6a9246d6fd8e0953cfa9b9c805afa78e"
http-errors@~1.6.1:
version "1.6.1"
resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.1.tgz#5f8b8ed98aca545656bf572997387f904a722257"
dependencies:
depd "1.1.0"
inherits "2.0.3"
setprototypeof "1.0.3"
statuses ">= 1.3.1 < 2"
inherits@2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
ipaddr.js@1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.3.0.tgz#1e03a52fdad83a8bbb2b25cbf4998b4cffcd3dec"
media-typer@0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
merge-descriptors@1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61"
methods@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
mime-db@~1.27.0:
version "1.27.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.27.0.tgz#820f572296bbd20ec25ed55e5b5de869e5436eb1"
mime-types@~2.1.11, mime-types@~2.1.15:
version "2.1.15"
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.15.tgz#a4ebf5064094569237b8cf70046776d09fc92aed"
dependencies:
mime-db "~1.27.0"
mime@1.3.4:
version "1.3.4"
resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53"
ms@0.7.2:
version "0.7.2"
resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765"
negotiator@0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9"
on-finished@~2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947"
dependencies:
ee-first "1.1.1"
parseurl@~1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.1.tgz#c8ab8c9223ba34888aa64a297b28853bec18da56"
path-to-regexp@0.1.7:
version "0.1.7"
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
proxy-addr@~1.1.3:
version "1.1.4"
resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-1.1.4.tgz#27e545f6960a44a627d9b44467e35c1b6b4ce2f3"
dependencies:
forwarded "~0.1.0"
ipaddr.js "1.3.0"
qs@6.4.0:
version "6.4.0"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233"
range-parser@~1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e"
send@0.15.1:
version "0.15.1"
resolved "https://registry.yarnpkg.com/send/-/send-0.15.1.tgz#8a02354c26e6f5cca700065f5f0cdeba90ec7b5f"
dependencies:
debug "2.6.1"
depd "~1.1.0"
destroy "~1.0.4"
encodeurl "~1.0.1"
escape-html "~1.0.3"
etag "~1.8.0"
fresh "0.5.0"
http-errors "~1.6.1"
mime "1.3.4"
ms "0.7.2"
on-finished "~2.3.0"
range-parser "~1.2.0"
statuses "~1.3.1"
serve-static@1.12.1:
version "1.12.1"
resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.12.1.tgz#7443a965e3ced647aceb5639fa06bf4d1bbe0039"
dependencies:
encodeurl "~1.0.1"
escape-html "~1.0.3"
parseurl "~1.3.1"
send "0.15.1"
setprototypeof@1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04"
"statuses@>= 1.3.1 < 2", statuses@~1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e"
type-is@~1.6.14:
version "1.6.15"
resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.15.tgz#cab10fb4909e441c82842eafe1ad646c81804410"
dependencies:
media-typer "0.3.0"
mime-types "~2.1.15"
unpipe@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
utils-merge@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.0.tgz#0294fb922bb9375153541c4f7096231f287c8af8"
vary@~1.1.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.1.tgz#67535ebb694c1d52257457984665323f587e8d37"

View File

@@ -6,9 +6,8 @@
"private": true,
"main": "node_modules/expo/AppEntry.js",
"dependencies": {
"expo": "19.0.0",
"query-string": "^4.3.4",
"expo": "^21.0.0",
"react": "16.0.0-alpha.12",
"react-native": "https://github.com/expo/react-native/archive/sdk-19.0.0.tar.gz"
"react-native": "https://github.com/expo/react-native/archive/sdk-21.0.2.tar.gz"
}
}