68 lines
2.0 KiB
JavaScript
68 lines
2.0 KiB
JavaScript
#!/usr/bin/env node
|
|
const crypto = require('crypto')
|
|
|
|
function b64urlDecode(s) {
|
|
s = String(s || '')
|
|
s = s.replace(/-/g, '+').replace(/_/g, '/')
|
|
while (s.length % 4) s += '='
|
|
return Buffer.from(s, 'base64').toString('utf8')
|
|
}
|
|
|
|
function b64urlEncode(buf) {
|
|
return buf.toString('base64').replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_')
|
|
}
|
|
|
|
function verifyHS256(token, secret) {
|
|
const parts = token.split('.')
|
|
if (parts.length !== 3) return { ok: false, reason: 'bad token format' }
|
|
const [h64, p64, s64] = parts
|
|
const signingInput = `${h64}.${p64}`
|
|
const expected = b64urlEncode(crypto.createHmac('sha256', secret).update(signingInput).digest())
|
|
return { ok: expected === s64, expected, actual: s64 }
|
|
}
|
|
|
|
function usage() {
|
|
console.log('Usage: node server/verify_supa_token.js <token> [secret]')
|
|
console.log('Or set env vars: TOKEN and SECRET and run without args')
|
|
}
|
|
|
|
const token = process.argv[2] || process.env.TOKEN
|
|
const secret = process.argv[3] || process.env.SECRET || process.env.JWT_SECRET || process.env.SERVICE_ROLE_KEY || process.env.SUPA_KEY
|
|
|
|
if (!token) {
|
|
usage()
|
|
process.exit(2)
|
|
}
|
|
|
|
if (!secret) {
|
|
console.error('No secret provided. Pass as second arg or set SECRET/JWT_SECRET/SERVICE_ROLE_KEY env var')
|
|
process.exit(2)
|
|
}
|
|
|
|
try {
|
|
const parts = token.split('.')
|
|
const header = JSON.parse(b64urlDecode(parts[0]))
|
|
const payload = JSON.parse(b64urlDecode(parts[1]))
|
|
|
|
console.log('Header:')
|
|
console.log(JSON.stringify(header, null, 2))
|
|
console.log('Payload:')
|
|
console.log(JSON.stringify(payload, null, 2))
|
|
|
|
if ((header.alg || '').toUpperCase() !== 'HS256') {
|
|
console.warn('Warning: token alg is not HS256; this verifier only checks HS256 signatures')
|
|
}
|
|
|
|
const res = verifyHS256(token, secret)
|
|
if (res.ok) {
|
|
console.log('\nSignature: VALID (HMAC-SHA256)')
|
|
} else {
|
|
console.log('\nSignature: INVALID')
|
|
console.log('expected:', res.expected)
|
|
console.log('actual :', res.actual)
|
|
}
|
|
} catch (e) {
|
|
console.error('verify error', e && e.message ? e.message : e)
|
|
process.exit(1)
|
|
}
|