CORS problem with Passport.js implemented in Azure Function in Static Web App. Passport returns 401
I am working on a project which uses the Azure Static Web App offering. I have implemented a Passport.js authentication strategy powered by azure-function-express which receives a JWT in an Authentication header, validates the JWT, and returns user information.
My system works locally, but returns a 401 unauthorized in deployment.
When tested in deployment, Application Insights infers that a resource is blocked due to a CORS issue, but does not specify which resource. It appears that the function executes despite the CORS issue, but returns a 401 even though the test account info is correct.
Does anybody have experience with this issue or know how to identify which resource is being blocked by CORS?
Azure Live Analytics -- Sorry these cannot be expanded fully for readability
CORS messages expanded
The request has an origin header: 'https://icy-plant-mysiteID.centralus.azurestaticapps.net'.
CORS policy execution failed.
Request origin https://icy-plant-mysiteid.centralus.azurestaticapps.net/ does not have permission to access the resource.
GetUserFromJwt Azure Function
const passport = require('passport');
const createHandler = require("azure-function-express").createHandler;
const express = require("express");
const app = express();
const mongooseHelper = require('../config/mongoose');
// Configure passport, express
require('../config/passport')(passport);
require('../config/express')(app, passport);
mongooseHelper.connectToMongoose("GetUserIdFromJwt");
app.get('/api/getUserIdFromJwt', passport.authenticate('jwt', { session: false }), (req, res, next) => {
res.status(200).json(req.user)
});
// Binds the express app to an Azure Function handler
module.exports = createHandler(app);
API Call (Called from client upon retrieval of JWT)
export const getUserIdFromJwt = (jwt) => {
return new Promise((resolve, reject) => {
axios({
url: '/api/getUserIdFromJwt',
method: 'GET',
headers: { "Authorization": jwt }
}).then((res) => {
resolve(res.data)
}).catch((err) => {
reject(console.log("An error occured getting the User from JWT: " + err));
});
})
}
passport config
// Configure Passport
const User = require('../models/UserModel');
const JwtStrat = require('passport-jwt').Strategy;
const ExtractJwt = require('passport-jwt').ExtractJwt;
const PUB_KEY = **MY KEY**;
const passportOptions = {
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: PUB_KEY,
algorithms: ['OurAlgorithm'],
passReqToCallback: true
}
const strat = new JwtStrat(passportOptions, (req, payload, done) => {
User.findOne({ _id: payload.sub })
.then((user) => {
if (user) {
// Send id as User. Do not send personal info here.
req.user = {id: payload.sub, role: payload.role};
return done(null, req.user);
} else {
return done(null, false);
}
})
.catch(err => {
done(err, null)
});
});
module.exports = (passport) => {
passport.use(strat);
}
Express Config
const express = require('express')
const cors = require('cors');
module.exports = (app, passport) => {
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cors());
app.use(passport.initialize());
}
1 ответ
Я обнаружил проблему после обращения в службу технической поддержки Microsoft.
Служба статических веб-приложений, предлагаемая Microsoft, внутренне использует заголовок авторизации, поэтому токен, отправляемый функции через заголовок авторизации, изменялся или перезаписывался. Проблема была решена путем отправки JWT с другим заголовком.
Что касается проблемы, выполните следующие действия.
Создать функцию Azure
Код. Я использую Azure Cosmos DB Mongo API, чтобы спасти пользователя. Вы можете получить доступ сюда, чтобы прочитать мой код функции
конфигурация паспорта
const passportJWT = require("passport-jwt");
const User = require("../Models/UserModel");
// passport & jwt config
const { Strategy: JWTStrategy, ExtractJwt: ExtractJWT } = passportJWT;
// define passport jwt strategy
const opts = {};
opts.jwtFromRequest = ExtractJWT.fromAuthHeaderWithScheme("jwt");
opts.secretOrKey =
"QOOC3nUVl9yTZiH2F0VYjOJhwm2ZkyBjWK7Mzo4bH54cNBBUQmp262S0Tx1eBBTT";
opts.algorithms = ["HS256"];
const passportJWTStrategy = new JWTStrategy(opts, function (jwtPayload, done) {
// retreive mail from jwt payload
const email = jwtPayload.email;
User.findOne({ email: email }, (error, user) => {
if (error) {
return done(error, false);
} else {
if (user) {
done(null, user);
} else {
done(null, false);
}
}
});
});
// config passport
module.exports = function (passport) {
// token strategy
passport.use(passportJWTStrategy);
// return configured passport
return passport;
};
GetUserFromJwt Функция Azure
const passport = require("passport");
const bodyParser = require("body-parser");
const createHandler = require("azure-function-express").createHandler;
const express = require("express");
const app = express();
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }));
// parse application/json
app.use(bodyParser.json());
// init and configure passport
app.use(passport.initialize());
// Configure passport
require("../config/passport")(passport);
require("../config/mongo")
.connect()
.catch((error) => {
throw error;
});
app.get(
"/api/getUserIdFromJwt",
passport.authenticate("jwt", { session: false }),
(req, res, next) => {
res.status(200).json(req.user);
}
);
// Binds the express app to an Azure Function handler
module.exports = createHandler(app);
4 Создайте токен jwt
const jwt = require("jsonwebtoken");
const secretOrKey =
"QOOC3nUVl9yTZiH2F0VYjOJhwm2ZkyBjWK7Mzo4bH54cNBBUQmp262S0Tx1eBBTT";
const token = jwt.sign(<your playlaod>, secretOrKey , { algorithm: 'HS256' });
const jwt= `JWT ${token}`
- Тест в почтальоне
GET https://testjsfun.azurewebsites.net/api/getUserIdFromJwt
Authorization : JWT <token>