Can I send a url, or some other value, to the IdP that will get
round-tripped and POSTed back in the response SAML? And if so, how can
I access it in my /login/callback route?
To round-trip a value via the IdP you need to use RelayState
. This is a value that you can send to the IdP and, if you do, they are obliged to send it back without alterations.
Here is the what the SAML specifications has to say:
3.1.1 Use of RelayState
Some bindings define a “RelayState” mechanism for preserving and
conveying state information. When such a mechanism is used in
conveying a request message as the initial step of a SAML protocol, it
places requirements on the selection and use of the binding
subsequently used to convey the response. Namely, if a SAML request
message is accompanied by RelayState data, then the SAML responder
MUST return its SAML protocol response using a binding that also
supports a RelayState mechanism, and it MUST place the exact
RelayState data it received with the request into the corresponding
RelayState parameter in the response.
To use this with passport-saml you must add it as an additionalParams
value. The code below shows this happening.
saml = new SamlStrategy
path: appConfig.passport.saml.path
decryptionPvk: fs.readFileSync(appConfig.passport.saml.privateKeyFile)
issuer: appConfig.passport.saml.issuer
identifierFormat: tenant.strategy.identifierFormat
entryPoint: tenant.strategy.entryPoint
additionalParams:{'RelayState':tenant.key}
,
(profile, next) ->
# get the user from the profile
The code above is from a multi-tenant saml implementation so I am sending my tenant.key
as the RelayState
param. I then retrieve this value from the body of POSTed return from the IdP and use it to re-establish all the state I need.
getTenantKey: (req, next) ->
key = req.body?.RelayState ? routes.match(req.path).params.tenentKey
next null, key
Your case might be simpler. You will probably want to store the final-destination url in a time limited cache and then send the cache-key as the RelayState
param.
For what it is worth, you can avoid using RelayState
altogether if you just use the original SAML request-id as your cache key. This value is always sent back to you via the InResponseTo
field.