JWT and CORS
Hi
I'm trying to use JWT authentication on a REST application in IRIS. The login API are correctly "injected" into the application. Login works fine with Postman and other REST clients, and subsequent calls to my REST API using the bearer token work fine (correctly authenticated). So far, so good.
The problem is that it doesn't work with Axios, so I can only test it, I cannot integrate it into my application. I found out the reason for this is that Axios is applying CORS whereas Postman and other REST test clients do not; that is, they don't send the "preflight" OPTIONS request, they send the POST request directly, and apparently IRIS is happy not having to deal with CORS in this case (in other words, it does not check the "allow origin" header, probably because there was no OPTIONS call?) Unfortunately the reverse is not true. Axios sends the OPTIONS preflight, to which IRIS responds with a 500 internal server error and no "Access-Control-Allow-Origin" response header. Axios still attempts to send the POST, but it is getting a NS_ERROR_DOM_BAD_URI error because it failed CORS validation.
As far as I can tell based on the CORS specification, Axios is right to apply CORS in this case, as this query does not (and CAN not) match the criteria for not using CORS (as described on MDN: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS). There does not seem to be a way to force Axios not to send the pre-flight when the situation is legitimate for CORS.
I have correctly configured the dispatch class to handle CORS; without JWT authentication, CORS is handled correctly. However the dispatch class is never invoked for the JWT authentication login API (not even OnPreHTTP). Apparently the CSP engine is handling the login API on its own and never delegates to the dispatch class. So as far as I can tell, there's no way to intercept the OPTIONS call to somehow ignore or accept it.
Is there a way to make this work in IRIS? Or conversely, does anyone knows of a (minimally invasive) way to force Axios to bypass the pre-flight for this specific call?
Thanks
Comments
Please double check the version. 2023.1.3 should have the fix for this case https://docs.intersystems.com/iris20231/csp/docbook/changes/index.html#CSP/ZEN_DP-423647
DP-423647: Process CORS request when handling requests with JWT Tokens
Category: CSP / ZEN
Platforms: All
Version: 2023.1.3
This change ensures that any request that handles JWT tokens also correctly process CORS requests, when applicable.
Though status 500 is strange by itself. Try enabling ISCLOG and see if any error is logged there
I'll do that, thanks for the feedback. 👍
A few things revealed by the ISCLOG logging:
- If "allowed authentication methods" is set to "password" only, the system seems to attempt to log in a user (during the OPTIONS interaction) and fails:
**CSPServer-2 2024-07-23 14:27:57.214638 ns=USER routine=%SYS.cspServer job=44424 tag=F20 sessionid=hgxRMlcT0W
[CSPLogin] Error: Reverting to prelogin security context. (822 )
¦0 6 USER (e^AuditLoginFailure+87^%SYS.SECURITY^1%e^UsersCSPLogin+135^%SYS.SECURITY^1!e^CSPLogin+102^%SYS.cspServer^1$e^CSPDispatch+883^%SYS.cspServer^1$d^CSPDispatch+881^%SYS.cspServer^1%d^ProcessRequest+1^%CSP.Session.1^1!d^Request+683^%SYS.cspServer2^1 d^Request+25^%SYS.cspServer2^1%d^ProcessRequest+1^%CSP.Request.1^1d^css+21^%SYS.cspServer2^1 d^SuperServer+60^%SYS.SERVER^2d^^^0**CSPServer-2 2024-07-23 14:27:57.2146733 ns=USER routine=%SYS.cspServer job=44424 tag=F20 sessionid=hgxRMlcT0W
[LoginFailed]Security error: 0 6 USER (e^AuditLoginFailure+87^%SYS.SECURITY^1%e^UsersCSPLogin+135^%SYS.SECURITY^1!e^CSPLogin+102^%SYS.cspServer^1$e^CSPDispatch+883^%SYS.cspServer^1$d^CSPDispatch+881^%SYS.cspServer^1%d^ProcessRequest+1^%CSP.Session.1^1!d^Request+683^%SYS.cspServer2^1 d^Request+25^%SYS.cspServer2^1%d^ProcessRequest+1^%CSP.Request.1^1d^css+21^%SYS.cspServer2^1 d^SuperServer+60^%SYS.SERVER^2d^^^0**CSPServer-2 2024-07-23 14:27:57.2147257 ns=USER routine=%SYS.cspServer job=44424 tag=F20 sessionid=hgxRMlcT0W
[LoginFailed]Redirecting to login page /csp/lspmanagement/login**CSPServer-2 2024-07-23 14:27:57.2147994 ns=USER routine=%CSP.Request.1 job=44424 tag=F20 sessionid=hgxRMlcT0W
[UpdateURL] Looking up: //localhost/csp/lspmanagement/login path found: //localhost/csp/lspmanagement/ Appl= /csp/lspmanagement/ :%All/csp/lspmanagementUSERLSP.REST.Management<
Then gets a <PROTECT> error:
**CSPServer-2 2024-07-23 14:27:57.2153425 ns=USER routine=%SYS.cspServer job=44424 tag=F20 sessionid=hgxRMlcT0W
[callPage] Return Status
0 á]<PROTECT>^%CSP.Login.1 ^|^^c:\intersystems\irishealth202312\mgr\user\|LSP.REST.Management.1 uUSER j^^%CSP.Login.1^0'e^ProcessCorsRequest+8^%CSP.Login.1^1e^zLogin+7^%CSP.REST.1^1$e^CSPDispatch+500^%SYS.cspServer^2$d^CSPDispatch+279^%SYS.cspServer^1%d^ProcessRequest+1^%CSP.Session.1^1!d^Request+683^%SYS.cspServer2^1 d^Request+25^%SYS.cspServer2^1%d^ProcessRequest+1^%CSP.Request.1^1d^css+21^%SYS.cspServer2^1 d^SuperServer+60^%SYS.SERVER^2d^^^0**CSPServer-2 2024-07-23 14:27:57.2154258 ns=USER routine=%SYS.cspServer job=44424 tag=F20 sessionid=hgxRMlcT0W
[HandleError]: ERROR #5002: ObjectScript error: <PROTECT>^%CSP.Login.1 ^|^^c:\intersystems\irishealth202312\mgr\user\|LSP.REST.Management.1
0 á]<PROTECT>^%CSP.Login.1 ^|^^c:\intersystems\irishealth202312\mgr\user\|LSP.REST.Management.1 uUSER j^^%CSP.Login.1^0'e^ProcessCorsRequest+8^%CSP.Login.1^1e^zLogin+7^%CSP.REST.1^1$e^CSPDispatch+500^%SYS.cspServer^2$d^CSPDispatch+279^%SYS.cspServer^1%d^ProcessRequest+1^%CSP.Session.1^1!d^Request+683^%SYS.cspServer2^1 d^Request+25^%SYS.cspServer2^1%d^ProcessRequest+1^%CSP.Request.1^1d^css+21^%SYS.cspServer2^1 d^SuperServer+60^%SYS.SERVER^2d^^^0
I would think that this attempt at login on the preflight call is incorrect?
- If "Allowed Authentication Methods" is set to "unauthenticated" only, I don't see these errors in ISCLOG, but it still doesn't work as the engine does not process the "allow origin" header. And besides, this is not an acceptable situation as (based on my tests) my API is accessible without authentication in this case.
- I see the same behavior if authentication is set to both unauthenticated and password. It appears to take the "path of least resistance", so no authentication errors in ISCLOG, but the result is the same ("allow origin" is not processed).
So I think we're looking at 2 issues here: the attempt at authentication of the OPTIONS call, which is probably not right? and the fact that the "allow origin" header is not processed.
BTW, how does that work anyway? Is any CORS origin supposed to be accepted for the login API?
I'll see if I can reproduce this on 2024.1, in case.
Good! CSPSystem user should have READ privilege on c:\intersystems\irishealth202312\mgr\user\ database
Give such privilege to that user via some role
Then restart the web server or close all connections from the web server to IRIS and try again
See IMPORTANT note here: https://docs.intersystems.com/iris20241/csp/docbook/DocBook.UI.Page.cls?KEY=GREST_specification#GREST_specification_cors_config
Well, it seems to have resolved the issue! Many thanks for your help Alexander, I appreciate it! 👍
I would say despite the "important note", it is not obvious this requirement applies to this situation, and it appears in a different part of the documentation from the one on JWT (https://docs.intersystems.com/iris20241/csp/docbook/Doc.View.cls?KEY=RO…), so linking the 2 articles is not immediate. A note in the JWT article would be nice.
I'm glad that helped!
Olivier -- for sure -- please use the Feedback button in the documentation. The documentation team is very good in making the documentation better
Exact same behavior on 2024.1, same traces in ISCLOG.
My client is on 2023.1 anyway, so the fix is not in there. Is there a way to make it work? Or is there a (reasonably simple) way to produce a JWT bearer token in the dispatch class' code (after password authentication)?
Thanks
It looks like I have the same issue. Version 2022.1
Are there no work arounds without having to update IRIS itself?
Thanks