Expo+FirebaseAuthenticationでTwitter連携がしたいのですが、リクエストトークンのエラー(下記画像参照)が出て上手くいきません。
下記のServer側のプログラムをPC上で、Expo(Client)側のプログラムをIphone実機のExpoアプリ上で実行しています。
(*****部分に各種トークンなどを入力してあります)
Server側
JavaScirpt
1const express = require('express') 2const bodyParser = require('body-parser'); 3const fetch = require('node-fetch'); 4 5const OAuth = require('oauth-1.0a'); 6const qs = require('qs') 7const HmacSHA1 = require('crypto-js/hmac-sha1') 8const Base64 = require('crypto-js/enc-base64') 9 10const port = process.env.PORT || 3000 11 12const config = { 13 GOOGLE: { 14 CLIENT_ID: "", 15 CLIENT_SECRET: "", 16 }, 17 GITHUB: { 18 CLIENT_ID: "", 19 CLIENT_SECRET: "", 20 }, 21 TWITTER: { 22 CLIENT_ID: "*****", 23 CLIENT_SECRET: "*****", 24 } 25} 26 27const app = express(); 28 29app.use(bodyParser.urlencoded({ extended: true })); 30app.use(bodyParser.json()); 31 32app.post('/auth/google', async (req, res) => { 33 34 async function createTokenWithGoogleCode(code, redirect_uri) { 35 36 const url = `https://www.googleapis.com/oauth2/v4/token` 37 const res = await fetch(url, { 38 method: 'POST', 39 body: JSON.stringify({ 40 code, 41 client_id: config.GOOGLE.CLIENT_ID, 42 client_secret: config.GOOGLE.CLIENT_SECRET, 43 redirect_uri, 44 grant_type: 'authorization_code' 45 }) 46 }); 47 48 return await res.json() 49 } 50 51 return res.json(await createTokenWithGoogleCode(req.body.code, req.body.redirect_uri)) 52}); 53 54app.post('/auth/github', async (req, res) => { 55 56 async function createTokenWithGithubCode(code) { 57 const url = 58 `https://github.com/login/oauth/access_token` + 59 `?client_id=${config.GITHUB.CLIENT_ID}` + 60 `&client_secret=${config.GITHUB.CLIENT_SECRET}` + 61 `&code=${code}`; 62 63 const res = await fetch(url, { 64 method: 'POST', 65 headers: { 66 Accept: 'application/json', 67 'Content-Type': 'application/json', 68 }, 69 }); 70 return await res.json() 71 } 72 73 return res.json(await createTokenWithGithubCode(req.body.code)) 74}); 75 76app.post('/auth/twitter/request_token', async (req, res) => { 77 78 const { redirect_uri } = req.body 79 80 const oauth = OAuth({ 81 consumer: { 82 key: config.TWITTER.CLIENT_ID, 83 secret: config.TWITTER.CLIENT_SECRET, 84 }, 85 signature_method: 'HMAC-SHA1', 86 hash_function: (baseString, key) => Base64.stringify(HmacSHA1(baseString, key)) 87 }) 88 89 const request_data = { 90 url: 'https://api.twitter.com/oauth/request_token', 91 method: 'POST', 92 data: { 93 oauth_callback: redirect_uri, 94 } 95 }; 96 97 98 const response = await fetch(request_data.url, { 99 method: request_data.method, 100 headers: oauth.toHeader(oauth.authorize(request_data)) 101 }) 102 103 const text = await response.text(); 104 return res.json(qs.parse(text)) 105}); 106 107app.post('/auth/twitter/access_token', async (req, res) => { 108 109 const { oauth_token, oauth_token_secret, oauth_verifier } = req.body 110 111 const oauth = OAuth({ 112 consumer: { 113 key: config.TWITTER.CLIENT_ID, 114 secret: config.TWITTER.CLIENT_SECRET, 115 }, 116 signature_method: 'HMAC-SHA1', 117 hash_function: (baseString, key) => Base64.stringify(HmacSHA1(baseString, key)) 118 }) 119 120 const request_data = { 121 url: 'https://api.twitter.com/oauth/access_token', 122 method: 'POST', 123 data: { 124 oauth_verifier, 125 }, 126 } 127 128 const headers = oauth.toHeader(oauth.authorize(request_data, {key: oauth_token, secret: oauth_token_secret})) 129 130 const response = await fetch(request_data.url, { 131 method: request_data.method, 132 data: request_data.data, 133 headers 134 }) 135 136 if (response.status !== 200) { 137 res.status = response.status 138 return res.json({message: "something wrong"}) 139 } 140 const text = await response.text(); 141 return res.json(qs.parse(text)) 142}) 143 144if (!module.parent) { 145 app.listen(3000, () => { 146 console.log('Example app listening on port 3000!'); 147 }); 148} 149 150module.exports = app; 151Expo 152expo init expo && cd $_ 153yarn add firebase 154
Expo側
TypeScript
1import React from 'react' 2import { StyleSheet, Text, Button, View } from 'react-native' 3import { Facebook } from 'expo'; 4import * as AuthSession from "expo-auth-session" 5import firebase from 'firebase'; 6 7const AUTH_BASE_URL = "http://localhost:3000" 8const REDIRECT_URL = AuthSession.getRedirectUrl(); 9const FACEBOOK_APP_ID = "" 10const GOOGLE_CLIENT_ID = "" 11const GITHUB_CLIENT_ID = "" 12 13if (!firebase.apps.length) { 14 firebase.initializeApp({ 15 apiKey: "*****", 16 authDomain: "*****", 17 databaseURL: "*****", 18 projectId: "*****", 19 storageBucket: "*****", 20 messagingSenderId: "*****" 21 }) 22} 23 24async function createTokenWithCode(provider, code) { 25 const url = `${AUTH_BASE_URL}/auth/${provider}/` 26 console.log(url) 27 const res = await fetch(url, { 28 method: 'POST', 29 headers: { 30 'Accept': 'application/json', 31 'Content-Type': 'application/json', 32 }, 33 body: JSON.stringify({ 34 code, 35 redirect_uri: REDIRECT_URL // Google で必要 36 }) 37 }) 38 const json = await res.json(); 39 console.log(json) 40 return json 41} 42 43async function getTwitterRequestToken() { 44 const url = `${AUTH_BASE_URL}/auth/twitter/request_token` 45 const res = await fetch(url, { 46 method: 'POST', 47 headers: { 48 'Accept': 'application/json', 49 'Content-Type': 'application/json', 50 }, 51 body: JSON.stringify({ 52 redirect_uri: REDIRECT_URL 53 }) 54 }); 55 return await res.json(); 56} 57 58async function getTwitterAccessToken(params) { 59 const { oauth_token, oauth_token_secret, oauth_verifier } = params 60 const url = `${AUTH_BASE_URL}/auth/twitter/access_token` 61 const res = await fetch(url, { 62 method: 'POST', 63 headers: { 64 'Accept': 'application/json', 65 'Content-Type': 'application/json', 66 }, 67 body: JSON.stringify({ oauth_token, oauth_token_secret, oauth_verifier }) 68 }); 69 return await res.json(); 70} 71 72export default class App extends React.Component { 73 74 constructor(props) { 75 super(props) 76 this.state = { 77 user: null 78 } 79 firebase.auth().onAuthStateChanged((user) => { 80 if (user) { 81 this.setState({ user: user.toJSON() }) 82 console.log(user) 83 } else { 84 this.setState({ user: null }) 85 } 86 }) 87 } 88 89 handleLogout() { 90 firebase.auth().signOut() 91 } 92 93 94 95 async handleTwitterLogin() { 96 const { oauth_token, oauth_token_secret } = await getTwitterRequestToken() 97 98 const { params } = await AuthSession.startAsync({ 99 authUrl: `https://api.twitter.com/oauth/authenticate?oauth_token=${oauth_token}` 100 }); 101 102 const oauth_verifier = params.oauth_verifier 103 const result = await getTwitterAccessToken({oauth_token, oauth_token_secret, oauth_verifier}) 104 105 const credential = firebase.auth.TwitterAuthProvider.credential( 106 result.oauth_token, 107 result.oauth_token_secret 108 ) 109 firebase.auth().signInAndRetrieveDataWithCredential(credential); 110 } 111 112 render() { 113 return ( 114 <View style={styles.container}> 115 <Text>Firebase Authentication Example</Text> 116 <Button onPress={this.handleTwitterLogin} title="Twitter" /> 117 <Button onPress={this.handleLogout} title="Logout" /> 118 <Text>displayName: {this.state.user && this.state.user.displayName}</Text> 119 <Text>providerId: {this.state.user && this.state.user.providerData[0].providerId}</Text> 120 </View> 121 ); 122 } 123} 124 125const styles = StyleSheet.create({ 126 container: { 127 flex: 1, 128 backgroundColor: '#fff', 129 alignItems: 'center', 130 justifyContent: 'center', 131 }, 132});
下記のサイトを参考にしました。
https://qiita.com/okamuuu/items/6da12f295c3b8a7bc3d8
どなたか解決策がわかる方がおられましたら、是非ともご教授お願いします。
あなたの回答
tips
プレビュー