Created
September 27, 2019 03:38
-
-
Save kishino/281f13461e975c819161298d35b6de54 to your computer and use it in GitHub Desktop.
apple-login-sample-server.js
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
const express = require('express') | |
const app = express() | |
const fs = require('fs') | |
const cors = require('cors') | |
const Datastore = require('nedb') | |
const bodyParser = require('body-parser') | |
const jwt = require('jsonwebtoken') | |
const jwksClient = require('jwks-rsa') | |
const axios = require('axios') | |
const qs = require('qs') | |
const UIDGenerator = require('uid-generator') | |
const uidgen = new UIDGenerator() | |
app.use(express.static('www')) | |
app.use(cors()) | |
app.use(bodyParser.urlencoded({ | |
extended: true | |
})) | |
app.use(bodyParser.json()) | |
const db = new Datastore({ | |
filename: 'datastore', | |
autoload: true | |
}) | |
app.post('/signup', async (req, res) => { | |
try { | |
const payload = await getIdTokenPayload(req.body.code) | |
const userId = payload.sub | |
db.find({ userId }, async (err, ret) => { | |
let user = ret[0] | |
// ユーザーがすでに存在する場合エラー | |
if (user) { | |
res.status(400).json({ | |
message: 'すでに登録済みです。' | |
}) | |
return | |
} | |
// メールアドレスがない or 未検証の場合エラー | |
if (!payload.email || payload.email_verified !== 'true') { | |
res.status(400).json({ | |
message: 'メールアドレスが取得できませんでした。' | |
}) | |
return | |
} | |
// ユーザーを登録 | |
user = { | |
userId, | |
email: payload.email, | |
name: req.body.userName, | |
token: await uidgen.generate() | |
} | |
db.insert(user) | |
res.json(user) | |
}) | |
} catch (e) { | |
console.error(e) | |
res.status(404).json({ | |
message: 'エラーが発生しました' | |
}) | |
} | |
}) | |
app.post('/login', async (req, res) => { | |
try { | |
const payload = await getIdTokenPayload(req.body.code) | |
const userId = payload.sub | |
db.find({ userId }, function(err, ret) { | |
let user = ret[0] | |
// ユーザーが存在しない場合エラー | |
if (!user) { | |
res.status(400).json({ | |
message: 'このユーザーは存在しません' | |
}) | |
return | |
} | |
// メールを取得できた場合は更新 | |
if (payload.email && payload.email_verified === 'true') { | |
const id = user._id | |
delete user._id | |
db.update({ _id: id } , user) | |
} | |
res.json(user) | |
}) | |
} catch (e) { | |
console.error(e) | |
res.status(404).json({ | |
message: 'エラーが発生しました' | |
}) | |
} | |
}) | |
app.get('/user', async (req, res) => { | |
try { | |
const token = req.header('X-Token') | |
db.find({ token }, function(err, ret) { | |
let user = ret[0] | |
// ユーザーが存在しない場合エラー | |
if (!user) { | |
res.status(400).json({ | |
message: 'このユーザーは存在しません。' | |
}) | |
return | |
} | |
res.json(user) | |
}) | |
} catch (e) { | |
console.error(e) | |
res.status(404).json({ | |
message: 'エラーが発生しました' | |
}) | |
} | |
}) | |
async function getIdTokenPayload(code) { | |
// ID Tokenを発行 | |
const resp = await axios.post('https://appleid.apple.com/auth/token', qs.stringify({ | |
client_id: process.env.CLIENT_ID, | |
client_secret: process.env.CLIENT_SECRET, | |
code, | |
grant_type: 'authorization_code' | |
})) | |
const idToken = resp.data.id_token | |
const client = jwksClient({ | |
jwksUri: 'https://appleid.apple.com/auth/keys' | |
}) | |
// Appleから公開鍵を取得 | |
const getKey = (header, callback) => { | |
client.getSigningKey(header.kid, (err, key) => { | |
const signingKey = key.publicKey || key.rsaPublicKey | |
callback(null, signingKey) | |
}) | |
} | |
// ID Tokenの署名+内容(有効期限、発行者、発行先など)を検証 | |
return new Promise((resolve, reject) => { | |
jwt.verify(idToken, getKey, { | |
issuer: 'https://appleid.apple.com', | |
audience: process.env.CLIENT_ID | |
}, function(err, decoded) { | |
if (err) { | |
reject(err) | |
} else { | |
console.info(decoded) | |
resolve(decoded) | |
} | |
}) | |
}) | |
} | |
const port = 3000 | |
const listener = app.listen(port, function() { | |
console.log('Your app is listening on port ' + listener.address().port) | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment