前提・実現したいこと
現在、iOSアプリ開発において、LINEログインをFirebaseカスタム認証を用いて実装しております。 node.jsでアクセストークンの認証サーバーをCloudFunction上で稼働させています。
発生している問題・エラーメッセージ
403 "error_message" : "Authentication error: Cannot verify access token."
該当のソースコード
// Generate a Request option to access LINE APIs
function generateLineApiRequest(apiEndpoint, lineAccessToken) {
return {
method: 'GET',
url: ${apiEndpoint}?access_token=${lineAccessToken}
,
json: true
};
}
function lineProfileRequest(apiEndpoint, lineAccessToken) {
return {
method: 'GET',
url: ${apiEndpoint}
,
headers: {'Authorization': Bearer ${lineAccessToken}
},
json: true
}
}
/**
- Look up Firebase user based on LINE's mid. If the Firebase user does not exist,
- fetch LINE profile and create a new Firebase user with it.
-
@returns {Promise<UserRecord>} The Firebase user record in a promise. */ function getFirebaseUser(lineAccessToken) { const getProfileOptions = lineProfileRequest('https://api.line.me/v2/profile', lineAccessToken); console.log(getProfileOptions); return request(getProfileOptions).then(response => { const displayName = response.displayName; const firebaseUid =
line:${response.userId}
; console.log('displayName', response.displayName); console.log('firebaseUid', response.userId);return firebaseAdmin.auth().getUser(firebaseUid).catch(err => { if (err.code === 'auth/user-not-found') { return firebaseAdmin.auth().createUser({ provider: 'LINE', uid: firebaseUid, displayName: displayName }) } throw err })
}) }
/**
- Verify LINE access token and return a custom auth token allowing signing-in
- the corresponding Firebase account.
- Here are the steps involved:
-
- Verify with LINE server that a LINE access token is valid
-
- Check if a Firebase user corresponding to the LINE user already existed.
- If not, fetch user profile from LINE and generate a corresponding Firebase user.
-
- Return a custom auth token allowing signing-in the Firebase account.
- @returns {Promise<string>} The Firebase custom auth token in a promise. */
function verifyLineToken(lineAccessToken) { // Send request to LINE server for access token verification const verifyTokenOptions = generateLineApiRequest('https://api.line.me/oauth2/v2.1/verify', lineAccessToken); console.log(verifyTokenOptions); var firebaseUid = '';
// STEP 1: Verify with LINE server that a LINE access token is valid return rp(verifyTokenOptions) .then(response => { // Verify the token’s channelId match with my channelId to prevent spoof attack // <IMPORTANT> As LINE's Get user profiles API response doesn't include channelID, // you must not skip this step to make sure that the LINE access token is indeed // issued for your channel. //TODO: consider !== here if (response.client_id != config.line.channel_id) return Promise.reject(new Error('LINE channel ID mismatched'));
// STEP 2: Access token validation succeeded, so look up the corresponding Firebase user
return getFirebaseUser(lineAccessToken);
})
.then(userRecord => {
// STEP 3: Generate Firebase Custom Auth Token
const tokenPromise = admin.auth().createCustomToken(userRecord.uid,{provider: 'LINE'});
tokenPromise.then(token => {
console.log('Created Custom token for UID "', userRecord.uid, '" Token:', token);
});
return tokenPromise;
});
}
// ExpressJS setup const app = express(); app.use(bodyParser.json());
// Verify LINE token and exchange for Firebase Custom Auth token app.post('/verifyToken', (req, res) => { if (req.body.token === undefined) { const ret = { error_message: 'Access Token not found' }; return res.status(400).send(ret); }
const reqToken = req.body.token; console.log('Access Token is', reqToken);
// Verify LINE access token with LINE server then generate Firebase Custom Auth token verifyLineToken(reqToken) .then(customAuthToken => { const ret = { firebase_token: customAuthToken }; return res.status(200).send(ret); }) .catch(err => { // If LINE access token verification failed, return error response to client const ret = { error_message: 'Authentication error: Cannot verify access token.' }; return res.status(403).send(ret); });
});
// Endpoint to verify if your Node server is up app.get('/', (req, res) => { return res.status(200).send('Server is up and running!'); });
// Start the server const server = app.listen(process.env.PORT || '8080', () => { console.log('App listening on port %s', server.address().port); console.log('Press Ctrl+C to quit.'); });
// Expose the API as a function exports.api = functions.https.onRequest(app);
試したこと
CloudFunctionの問題かと思い、Herokuなどでも試しましたが、同じ403エラーでした。 本当に解決の糸口が掴めずに2週間ほど立ってしまいました。 どうかどんな些細なことでも構わないので、どなたかに何かご教授いただきたいです。
補足情報(FW/ツールのバージョンなど)
Similar posts