Comments (14)
Thanks for reporting this @SacredMesa, we'll look into the issue.
from jackson.
@SacredMesa The authorize
call should return an authorize_form
value that is basically the POST binding response. You can send that back as the response inside the authorize endpoint.
See our service implementation here:
jackson/pages/api/oauth/authorize.ts
Line 22 in a688373
from jackson.
Thanks for the quick reply @deepakprabhakara and @niwsa. I've tried the implementation you linked, but I am still facing the same error.
From my understanding, the issue comes when Jackson sends a POST request to Azure's login url. The SAMLRequest is sent in the query params, however Azure is expecting this to be in the body, and so returns a 400 and the error screen.
Screenshots of the issue:
POST to Azure login url returns 400:
Payload of POST request to Azure login url (SAMLRequest in query params and absent in body):
from jackson.
@SacredMesa Jackson would use the redirect binding if the IdP metadata has one, else it uses the POST binding. Can you check your ADFS metadata for the supported bindings?
from jackson.
@niwsa It appears my metadata shows both bindings:
from jackson.
If the metadata has a redirect binding then the IdP should support the same. But looks like that is not the case here.
@SacredMesa From the screenshot you shared earlier, it looks like the app is making a POST instead of a GET. Jackson simply returns the redirect_url or the post binding in this case (does not make a request).
from jackson.
@SacredMesa Would you mind posting the code snippet, we can take a look to see if we can spot anything.
from jackson.
@niwsa @deepakprabhakara Really appreciate the help so far! I managed to get past the error by removing the redirect binding in the metadata xml file. A bit hacky, but it works. It's properly adding the authorize_form
now. Though, not sure why it was making a POST request instead of a GET for the redirect binding. When I logged the incoming req.method
in authorize.ts, it was a GET request.
The issue I'm facing now is that I'm getting a timeout error after getting the redirect_url
from ACS:
redirect_url in ACS https://<app-base-url>/api/auth/callback/jackson-saml?code=9ac638b03b03a87a61cc35bd5bc41d5e286e8a51&state=lMq9j_GpbQENA-2ZNPadcfUo7eKSrbw4cd4AGCkNFh8
--
[next-auth][error][OAUTH_CALLBACK_ERROR]
https://next-auth.js.org/errors#oauth_callback_error outgoing request timed out after 3500ms {
error: RPError: outgoing request timed out after 3500ms
at /app/node_modules/next-auth/node_modules/openid-client/lib/helpers/request.js:137:13
at async Client.grant (/app/node_modules/next-auth/node_modules/openid-client/lib/client.js:1316:22)
at async Client.oauthCallback (/app/node_modules/next-auth/node_modules/openid-client/lib/client.js:603:24)
at async oAuthCallback (/app/node_modules/next-auth/core/lib/oauth/callback.js:111:16)
at async Object.callback (/app/node_modules/next-auth/core/routes/callback.js:52:11)
at async AuthHandler (/app/node_modules/next-auth/core/index.js:208:28)
at async NextAuthApiHandler (/app/node_modules/next-auth/next/index.js:22:19)
at async NextAuth._args$ (/app/node_modules/next-auth/next/index.js:106:14)
at async Object.apiResolver (/app/node_modules/next/dist/server/api-utils/node.js:366:9)
at async NextNodeServer.runApi (/app/node_modules/next/dist/server/next-server.js:481:9) {
name: 'OAuthCallbackError',
code: undefined
},
providerId: 'jackson-saml',
message: 'outgoing request timed out after 3500ms'
}
Although, haven't debugged far enough to tell if it's an error with jackson, next-auth, or something else entirely. Would still be really grateful if you could take a look at the endpoints and config for jackson though if there might be something wrong/missing.
I'll share the jackson.ts, authorize.ts, acs.ts, token.ts, userinfo.ts and [...nextauth].ts codes here:
lib/jackson.ts
import type { JacksonOption, SAMLJackson } from '@boxyhq/saml-jackson';
import jackson from '@boxyhq/saml-jackson';
const samlAudience = process.env.AZURE_SAML_APPID;
const samlPath = '/api/auth/saml/acs';
const preLoadedConnection = 'lib/connections';
const opts: JacksonOption = {
externalUrl: `${process.env.NEXTAUTH_URL}`,
samlAudience,
samlPath,
preLoadedConnection,
db: { engine: 'mem' }
};
const g = global as any;
export default async function init() {
if (!g.jacksonInstance) {
g.jacksonInstance = await jackson(opts);
}
return g.jacksonInstance as SAMLJackson;
}
pages/api/auth/saml/authorize.ts
import { NextApiRequest, NextApiResponse } from 'next';
import jackson from '../../../../lib/jackson';
import { OAuthReq } from '@boxyhq/saml-jackson';
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
try {
if (req.method !== 'GET' && req.method !== 'POST') {
throw { message: 'Method not allowed', statusCode: 405 };
}
const { oauthController } = await jackson();
const requestParams = req.method === 'GET' ? req.query : req.body;
const { redirect_url, authorize_form } = await oauthController.authorize(
requestParams as unknown as OAuthReq
);
if (redirect_url) {
res.redirect(302, redirect_url);
} else {
res.setHeader('Content-Type', 'text/html; charset=utf-8');
res.send(authorize_form);
}
} catch (err: any) {
console.error('authorize error:', err);
res.redirect('/');
}
}
pages/api/auth/saml/acs.ts
import type { NextApiRequest, NextApiResponse } from 'next';
import jackson from '../../../../lib/jackson';
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
const { oauthController } = await jackson();
const { RelayState, SAMLResponse } = req.body;
const { redirect_url } = await oauthController.samlResponse({
RelayState,
SAMLResponse
});
console.log('redirect_url in ACS', redirect_url);
return res.redirect(302, redirect_url as string);
}
pages/api/auth/saml/token.ts
import type { NextApiRequest, NextApiResponse } from 'next';
import jackson from '../../../../lib/jackson';
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
const { oauthController } = await jackson();
const response = await oauthController.token(req.body);
return res.json(response);
}
pages/api/auth/saml/userinfo.ts
import type { NextApiRequest, NextApiResponse } from 'next';
import jackson from '../../../../lib/jackson';
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
const { oauthController } = await jackson();
const authHeader = req.headers['authorization'];
if (!authHeader) {
throw new Error('Unauthorized');
}
const token = authHeader.split(' ')[1];
const user = await oauthController.userInfo(token);
return res.json(user);
}
provider in pages/api/auth/[...nextauth].ts
{
id: 'jackson-saml',
name: 'Azure-SAML',
type: 'oauth',
checks: ['pkce', 'state'],
authorization: {
url: `${process.env.NEXTAUTH_URL}/api/auth/saml/authorize`,
params: {
scope: '',
response_type: 'code',
provider: 'saml'
}
},
token: {
url: `${process.env.NEXTAUTH_URL}/api/auth/saml/token`,
params: { grant_type: 'authorization_code' }
},
userinfo: `${process.env.NEXTAUTH_URL}/api/auth/saml/userinfo`,
profile: (profile) => {
return {
id: profile.id || '',
firstName: profile.firstName || '',
lastName: profile.lastName || '',
email: profile.email || '',
name: `${profile.firstName || ''} ${profile.lastName || ''}`.trim(),
email_verified: true
};
},
options: {
clientId: `tenant=${process.env.AZURE_SAML_TENANT}&product=${process.env.AZURE_SAML_PRODUCT}`,
clientSecret: 'dummy'
}
},
from jackson.
Could you try wrapping the token route with try catch ... and check for any errors in the token handler ? It could be that the token handler threw an error which is not handled, hence the timeout.
import type { NextApiRequest, NextApiResponse } from 'next';
import jackson from '../../../../lib/jackson';
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
try {
const { oauthController } = await jackson();
const response = await oauthController.token(req.body);
res.json(response);
} catch (err) {
console.error('token error:', err);
}
}
Also noticed that you are using the mem
db engine. Are you running the app locally or is it deployed somewhere? Do note that the mem db won't work in a serverless environment.
from jackson.
@niwsa I've wrapped the token and acs routes with try catch, but seems there's no error being thrown there. From what it seems, is that it hangs as it's trying to redirect. I can't tell if it's actually making the redirect request tbh, though the redirect url is there.
The app is deployed in AWS ECS. If I'm not mistaken the db is to store connection configs? I've set it up to preload the connection from a .js and .xml file though, would this suffice?
from jackson.
If I'm not mistaken the db is to store connection configs?
We also use it to conduct the Auth flow, as the OAuth 2.0 entities like code and token need to be persisted for some time.
Could you try increasing the HTTP timeout option inside the NextAuth Provider?
httpOptions: {
timeout: 30000,
},
from jackson.
@niwsa I've increased the timeout option, but doesn't seem to make a difference. We've had to drop this for awhile to handle some other tickets, but back on it now.
The last loggable event is still from the acs endpoint. We're getting the redirect url (https://<app-base-url>/api/auth/callback/jackson-saml?code=9ac638b03b03a87a61cc35bd5bc41d5e286e8a51&state=lMq9j_GpbQENA-2ZNPadcfUo7eKSrbw4cd4AGCkNFh8
), but hanging after that.
Do you have any other suggestions on what we could try?
from jackson.
@SacredMesa We can possibly connect over a call and sort out the issue if that's OK for you. You can ping me in the discord server: https://discord.com/invite/uyb7pYt4Pa.
from jackson.
@SacredMesa Closing this, please re-open if this continues to be an issue.
from jackson.
Related Issues (20)
- Critical dependency error in `typeorm` import trace HOT 6
- Update the README.md HOT 3
- Update the README.md HOT 5
- Star the Jackson Repository! 🚀 HOT 18
- Add a CONTRIBUTING.md to the Jackson repo HOT 4
- Break up npm into components to reduce size and dependencies
- Support Custom Postgres Schema HOT 2
- Make Setup Link Expiry Time Configurable HOT 5
- Provide method to close all connections opened by the npm library HOT 1
- Improve Well known URL pages (in both Jackson and Saas App) to categorize them into sections
- After using saml jackson and supplying the certs, application returns Invalid assertion signature on acs. HOT 1
- Can't authenticate when the server advertises authorization_response_iss_parameter_supported HOT 3
- mocksaml metadata doesn't have a SLO URL HOT 3
- Adding new SSO connections for Admin Portal uses build-time environment variables HOT 3
- Standardise pagination parameters across all APIs
- cleanup router warning message about query params
- Opt out from sending profile scope in OIDC Provider Authorization request
- SSO login is not working HOT 15
- Google directory sync does not include subdomains HOT 3
- Extend E2E tests for Jackson and Saas starter kit/SaaS app
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from jackson.