I'm trying to create SSO in my Nest.js application using Okta as Identity Provider and passport-saml library. I read documentation of Nest authentication and passport-saml. I have no problems with understanding of examples, but I really need to use SAML strategy with different configuration which depend on request body value of POST api/auth/saml
. In other words, I have one strategy, but with different entryPoint, issuer, cert params for my custom LoginSSOStrategy class which extends PassportStrategy class of Nest.js. Any ideas how can I handle this?
I'm not quite sure if this is a good approach, but if you want, you can make the class request scoped and inject the request via the constructor, then have access to the request object and be able to work with a new instance of your passport strategy each request. You can use the request to pass req.whatever
to the super()
class's constructor.
@Injectable({ scope: Scope.REQUEST })
export class LoginSSOStrategy exends PassportStrategy(Strategy) {
constructor(@Inject(REQUEST) request: Request, ...) {
super({/* options matching to request.field */});
}
validate(/* validate params*/) {
/* validate functionality */
}
}
This seems like something you'll want to do a lot of testing around and making sure it works with concurrent requests, but overall it could work, in theory at least.
I think this issue is similar to this GitHub issue. Due to the global nature of Passport.js and the fact that Nest is unable to determine which routes use a Passport passport strategy it is not possible to create a request scoped Passport strategy by using @Injectable({ scope: Scope.REQUEST })
.
Recently, I had to implement a Azure Active Directory login with a dynamic redirect URL based on some data from the incoming request. Depending on the Strategy you use, you might be able to overwrite some options when calling the authenticate
method of a Passport Strategy by using the (undocumented) extraAuthReqQueryParams
property.
One way to know wether or not you're able to overwrite some options is to check the documentation, if you're feeling lucky you could look in the source code of the Passport strategy you're using. After reading about the undocumented feature and seeing these lines in the source code of the Azure AD Passport strategy (in particular lines #1355 and #1374) I was able to change the value I previously specified in the redirectUrl
property by using the redirect_uri
property (note the slight difference here).
@Injectable()
export class AzureOIDCStrategy extends PassportStrategy(OIDCStrategy,'AzureOIDC') {
constructor() {
super({
// Even though it is overwritten in the 'authenticate' method the Passport Strategy expects this to be set to a valid URL.
redirectUrl: `https://your-backend-domain.com/auth/azure/callback`,
// This ensures we have access to the request in the `authenticate` method
passReqToCallback: true,
});
}
authenticate(req: Request, options: Record<string, any>): void {
return super.authenticate(req, {
// `options` may contain more options for the `authenticate` method in Passport.
...options,
extraAuthReqQueryParams: {
// This overwrites the `redirectUrl` specified in the constructor
redirect_uri: `https://${req.headers.host}/auth/callback`,
},
});
}
}
I hope you will be able to apply this 'strategy' to update the entryPoint
, issuer
and cert
params.
In an Express app you could do something like this:
app.get('/login',
(req, res, next) =>
passport.authenticate('azure-ad', {
extraAuthReqQueryParams: {
redirect_uri: `https://${req.headers.host}/auth/callback`,
},
})(req, res, next)
);
© 2022 - 2024 — McMap. All rights reserved.