1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
| // PKCE用のcode_verifierとcode_challengeを生成
function generatePKCE() {
const verifier = crypto.randomBytes(32).toString('base64url');
const challenge = crypto
.createHash('sha256')
.update(verifier)
.digest('base64url');
return { verifier, challenge };
}
// 認可リクエスト
const { verifier, challenge } = generatePKCE();
// verifierをセッションに保存
req.session.codeVerifier = verifier;
const authUrl = `https://oauth.example.com/authorize?` +
`client_id=${CLIENT_ID}&` +
`redirect_uri=${encodeURIComponent(REDIRECT_URI)}&` +
`response_type=code&` +
`code_challenge=${challenge}&` +
`code_challenge_method=S256`;
// トークン交換(PKCEあり)
app.get('/callback', async (req, res) => {
const { code } = req.query;
const codeVerifier = req.session.codeVerifier;
const response = await fetch('https://oauth.example.com/token', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'authorization_code',
code,
redirect_uri: REDIRECT_URI,
client_id: CLIENT_ID,
code_verifier: codeVerifier // PKCEのverifier
})
});
});
|