feat: replace keystore handling with node-jose
This commit is contained in:
@@ -8,12 +8,12 @@ const Debug = require('debug')
|
||||
const path = require('path')
|
||||
const cors = require('cors')
|
||||
const bodyParser = require('body-parser')
|
||||
const jose = require('node-jose');
|
||||
const favicon = require('serve-favicon')
|
||||
const cert = require('./cert')
|
||||
const initialUsers = require('./users')
|
||||
|
||||
let issuer = process.env.ISSUER || 'localhost:3333'
|
||||
let jwksOrigin = `https://${issuer}/`
|
||||
const issuer = process.env.ISSUER || 'localhost:3333'
|
||||
const jwksOrigin = `https://${issuer}/`
|
||||
const audience = process.env.AUDIENCE || 'https://generic-audience'
|
||||
const adminCustomClaim =
|
||||
process.env.ADMIN_CUSTOM_CLAIM || 'https://unbound.se/admin'
|
||||
@@ -22,7 +22,9 @@ const emailCustomClaim =
|
||||
|
||||
const debug = Debug('app')
|
||||
|
||||
let { privateKey, certDer, thumbprint, exponent, modulus } = cert(jwksOrigin)
|
||||
const keyStore = jose.JWK.createKeyStore()
|
||||
keyStore.generate('RSA', 2048, { alg: 'RS256', use: 'sig' })
|
||||
// let { privateKey, certDer, thumbprint, exponent, modulus } = cert(jwksOrigin)
|
||||
const users = initialUsers(process.env.USERS_FILE || './users.json')
|
||||
const sessions = {}
|
||||
const challenges = {}
|
||||
@@ -42,11 +44,12 @@ const addCustomClaims = (email, customClaims, token) => {
|
||||
}, token)
|
||||
}
|
||||
|
||||
const signToken = (token) => {
|
||||
return jwt.sign(Buffer.from(JSON.stringify(token)), privateKey, {
|
||||
algorithm: 'RS256',
|
||||
keyid: thumbprint
|
||||
})
|
||||
const signToken = async (token) => {
|
||||
const [key] = keyStore.all({ use: 'sig' })
|
||||
const opt = { compact: true, jwk: key, fields: { typ: 'jwt' } }
|
||||
return await jose.JWS.createSign(opt, key)
|
||||
.update(JSON.stringify(token))
|
||||
.final()
|
||||
}
|
||||
|
||||
// Configure our small auth0-mock-server
|
||||
@@ -60,10 +63,10 @@ app
|
||||
.use(favicon(path.join(__dirname, 'public', 'favicon.ico')))
|
||||
|
||||
// This route can be used to generate a valid jwt-token.
|
||||
app.post('/oauth/token', (req, res) => {
|
||||
let date = Math.floor(Date.now() / 1000)
|
||||
app.post('/oauth/token', async (req, res) => {
|
||||
const date = Math.floor(Date.now() / 1000)
|
||||
if (req.body.grant_type === 'client_credentials' && req.body.client_id) {
|
||||
let accessToken = signToken({
|
||||
const accessToken = await signToken({
|
||||
iss: jwksOrigin,
|
||||
aud: [audience],
|
||||
sub: 'auth0|management',
|
||||
@@ -72,7 +75,7 @@ app.post('/oauth/token', (req, res) => {
|
||||
azp: req.body.client_id
|
||||
})
|
||||
|
||||
let idToken = signToken({
|
||||
const idToken = await signToken({
|
||||
iss: jwksOrigin,
|
||||
aud: req.body.client_id,
|
||||
sub: 'auth0|management',
|
||||
@@ -94,7 +97,7 @@ app.post('/oauth/token', (req, res) => {
|
||||
} else if (req.body.code) {
|
||||
const code = req.body.code
|
||||
const session = sessions[code]
|
||||
let accessToken = signToken(
|
||||
const accessToken = await signToken(
|
||||
addCustomClaims(session.email, session.customClaims, {
|
||||
iss: jwksOrigin,
|
||||
aud: [audience],
|
||||
@@ -105,7 +108,7 @@ app.post('/oauth/token', (req, res) => {
|
||||
})
|
||||
)
|
||||
|
||||
let idToken = signToken(
|
||||
const idToken = await signToken(
|
||||
addCustomClaims(session.email, session.customClaims, {
|
||||
iss: jwksOrigin,
|
||||
aud: session.clientId,
|
||||
@@ -294,26 +297,78 @@ app.get('/v2/logout', (req, res) => {
|
||||
res.redirect(req.query.returnTo)
|
||||
})
|
||||
|
||||
app.get('/.well-known/jwks.json', (req, res) => {
|
||||
app.get('/.well-known/openid-configuration', (req, res) => {
|
||||
debug('Fetching OpenID configuration')
|
||||
res.contentType('application/json').send(
|
||||
JSON.stringify({
|
||||
keys: [
|
||||
{
|
||||
alg: 'RS256',
|
||||
// e: 'AQAB',
|
||||
e: exponent,
|
||||
kid: thumbprint,
|
||||
kty: 'RSA',
|
||||
n: modulus,
|
||||
use: 'sig',
|
||||
x5c: [certDer],
|
||||
x5t: thumbprint
|
||||
}
|
||||
]
|
||||
"issuer":
|
||||
"https://auth0",
|
||||
"authorization_endpoint":
|
||||
"https://server.example.com/authorize",
|
||||
"token_endpoint":
|
||||
"https://server.example.com/oauth/token",
|
||||
"token_endpoint_auth_methods_supported":
|
||||
["client_secret_basic", "private_key_jwt"],
|
||||
"token_endpoint_auth_signing_alg_values_supported":
|
||||
["RS256"],
|
||||
"userinfo_endpoint":
|
||||
"https://server.example.com/userinfo",
|
||||
"check_session_iframe":
|
||||
"https://server.example.com/check_session",
|
||||
"end_session_endpoint":
|
||||
"https://server.example.com/end_session",
|
||||
"jwks_uri":
|
||||
"https://server.example.com/.well-known/jwks.json",
|
||||
"registration_endpoint":
|
||||
"https://server.example.com/register",
|
||||
"scopes_supported":
|
||||
["openid", "profile", "email", "address",
|
||||
"phone", "offline_access"],
|
||||
"response_types_supported":
|
||||
["code", "code id_token", "id_token", "id_token token"],
|
||||
"acr_values_supported":
|
||||
[],
|
||||
"subject_types_supported":
|
||||
["public", "pairwise"],
|
||||
"userinfo_signing_alg_values_supported":
|
||||
["RS256", "ES256", "HS256"],
|
||||
"userinfo_encryption_alg_values_supported":
|
||||
["RSA-OAEP-256", "A128KW"],
|
||||
"userinfo_encryption_enc_values_supported":
|
||||
["A128CBC-HS256", "A128GCM"],
|
||||
"id_token_signing_alg_values_supported":
|
||||
["RS256", "ES256", "HS256"],
|
||||
"id_token_encryption_alg_values_supported":
|
||||
["RSA-OAEP-256", "A128KW"],
|
||||
"id_token_encryption_enc_values_supported":
|
||||
["A128CBC-HS256", "A128GCM"],
|
||||
"request_object_signing_alg_values_supported":
|
||||
["none", "RS256", "ES256"],
|
||||
"display_values_supported":
|
||||
["page", "popup"],
|
||||
"claim_types_supported":
|
||||
["normal", "distributed"],
|
||||
"claims_supported":
|
||||
["sub", "iss", "auth_time", "acr",
|
||||
"name", "given_name", "family_name", "nickname",
|
||||
"profile", "picture", "website",
|
||||
"email", "email_verified", "locale", "zoneinfo",
|
||||
"https://unbound.se/email", "https://unbound.se/admin"],
|
||||
"claims_parameter_supported":
|
||||
true,
|
||||
"service_documentation":
|
||||
"http://auth0/",
|
||||
"ui_locales_supported":
|
||||
["en-US"]
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
app.get('/.well-known/jwks.json', (req, res) => {
|
||||
debug('Fetching JWKS')
|
||||
res.contentType('application/json').send(keyStore.toJSON())
|
||||
})
|
||||
|
||||
// This route returns the inside of a jwt-token. Your main application
|
||||
// should use this route to keep the auth0-flow
|
||||
app.post('/tokeninfo', (req, res) => {
|
||||
@@ -331,29 +386,6 @@ app.post('/tokeninfo', (req, res) => {
|
||||
}
|
||||
})
|
||||
|
||||
app.post('/issuer', (req, res) => {
|
||||
if (!req.body.issuer) {
|
||||
debug('No issuer given in the body!')
|
||||
return res.status(401).send('missing issuer')
|
||||
}
|
||||
issuer = req.body.issuer
|
||||
jwksOrigin = `https://${issuer}/`
|
||||
const {
|
||||
privateKey: key,
|
||||
certDer: der,
|
||||
thumbprint: thumb,
|
||||
exponent: exp,
|
||||
modulus: mod
|
||||
} = cert(jwksOrigin)
|
||||
privateKey = key
|
||||
certDer = der
|
||||
thumbprint = thumb
|
||||
exponent = exp
|
||||
modulus = mod
|
||||
debug('Issuer set to ' + req.body.issuer)
|
||||
res.send('ok')
|
||||
})
|
||||
|
||||
app.get('/api/v2/users-by-email', (req, res) => {
|
||||
const email = req.query.email
|
||||
console.log('users', users)
|
||||
|
||||
Reference in New Issue
Block a user