node-passport-zitadel
node-passport-zitadel copied to clipboard
Docs should cover debugging
I'm attempting to use this module and i'm getting back a generic 401 Authorized error. I see nothing in the Zitadel logs on the server side and nothing in the app logs on the client side.
Looking at the source code for this module, there are multiple reasons why this.fail() could be called.
It would be very helpful to have documentation that explained how to access more detailed explanations of why authorization failed.
In passport/lib/authenticator.js there's a parameter documented failWithError. I believe I'm looking for an option such as this that provides more error about /why/ the request is unauthorized.
Without knowing /why/ the request is unauthorized, it's difficult to make progress.
Thanks.
For example, the failWithError option for Passport was added 10 years ago, but is still not documented. But it's useful! Even if passport doesn't document an example of using the option, passport-zitadel could.
https://github.com/jaredhanson/passport/issues/458
Here's a specific way the docs should improved. In the README, an example is provided that includes this code:
app.use(passport.initialize());
app.use(passport.authenticate('zitadel-introspection', { session: false }));
app.get('/', (req, res) => {
res.send('Hello World!');
});
But if this example is attempted to be followed, a generic "Unauthorized" err is returned and nothing in the logs will contain a more specific reason as to why.
Debugging will lead to this error:
"No bearer token found in authorization header"
Reading the code in the test suite will clarify what's going on, and why the example in the README is incomplete:
test('fail without bearer header', (done) => {
const strategy = new ZitadelIntrospectionStrategy(basic);
const authenticate = passport.authenticate(strategy, (err, user, info) => {
try {
expect(user).toBeFalsy();
expect(info?.message).toContain('No bearer token');
done();
} catch (e) {
done(e);
}
});
authenticate({ headers: { authorization: 'basic foo' } }, {}, () => {});
});
That shows that the code in the READ will fail unless a request is made which includes an Authorization header with a Bearer token.
More complete documentation would explain that you are supposed to generate some kind of bearer token before you attempt to call this middleware, and make sure and pass the token in an Authorization: Bearer XXX header to the request.
Second this!!
@markstos, were you able to figure out how we would be able to generate the Bearer token before using the middleware?
I was hoping this package would be a complete solution and the error would redirect to Zitadel login/signup screen and then sent back to redirect URI.
@prashansa-shukla I believe they are expecting you chain middleware. The first middleware, which you would provide yourself, would set your session and set the bearer token. My guess is the flow is intended to be this:
- Give the user a "session" on your site. At this point they are not logged but have a session token.
- Set the bearer token in the incoming request object as Zitadel expects.
These first two steps are the ones that would happen in your own middleware.
-
The Zitadel middleware is invoked, causing the user to be redirected to login and redirected back after successful authentication.
-
Update your database to mark that the user associated with the session token you generated is succesfully logged in.
But I'm guessing! The docs are not clear.
I've reviewed the source code of the passport-saml module, which I maintain, and the passport-oauth2 module and neither of them have any requirement like this that a Bearer token be set on the incoming request.
Here's my understanding of the OAuth 2 flow:
- Initiate the authorization request, typically by redirecting the user to the authorization server's endpoint.
- Receive the authorization code or ID token from the authorization server after the user grants consent.
- Exchange the authorization code or ID token for an access token by making a request to the token endpoint.
I think we both expected for this module to start at step 1, by redirecting to Zitadel to login. Yet, it seems to be implementing only step 3... since it requires that we already have a token?
The documentation could definitely stand to be clarified.
I think my primary issue may be that I'm using the wrong tool for the job. The docs for this module say:
the introspection strategy allows APIs to verify and validate an access token.
The docs do show how it's intended to be used:
So, it expects that some other code is responsible for redirecting the user to Zitadel to obtain an access token. Then, only after the user has an access token is this module used to perform "OAuth introspection" to validate the access the token.
What I'm looking for is a solution that starts from Step 0, including redirecting the user to Zitadel in the first place to get a token. For that, perhaps I should be looking at the Zitadel Reach docs instead:
https://zitadel.com/docs/sdk-examples/react
I also have same goal "a solution that starts from Step 0".
Were you able to figure out?
My application is Node.JS with express server and html pages served using express-handlebars.
I was following this guide : https://zitadel.com/docs/guides/integrate/login/oidc/login-users
I am able to successfully login users, but there is problem during logout. The logout guide is not clear.
I can't understand how they don't have any documentation or sample application for this.