A single-page application is a "no back-end" application
There are several architectures for creating single-page applications. The trend is the "light server" architecture, which installs on the user agent (usually the user’s browser) the initial page containing Javascript code. This code will provide logic and state transitions for the application as it gets its RESTful API data protected by OAuth 2.0. In this configuration, the application resides on the user agent and not on the server : a single-page application is therefore a "no back-end" application.
SPAs can (now ?) implement Authorization Code Grant
There are many configurations in which the application hosts and the service endpoints are located on different servers : authentication server, protected resources (RS) or APIs.
Single-page apps are a good example.
In normal web usage, this multi-host or, more accurately, "multi-origin" approach is restricted for good security reasons. Declarations of cross-origin resource sharing ( Cross-Origin Resource Sharing, CORS ) make it possible to circumvent the constraint.
Browsers have improved since the design of the implicit flow. The CORS implementation to allow token request from JavaScript is now available, along with the necessary cryptography APIs to validate the JWT token signature.
It is therefore technically possible to use the authorization code flow for the authentication and authorization of applications without a back-end, including for single-page applications.
Does this mean that the use of this flow, in this configuration, guarantees data security ?
With SPAs, authentication security issues remain
SPAs are "no-back-end" applications. Their code is on the user agent, so anywhere, unlike applications "with back-end" whose unique code is protected within a server. As such :
Are exposed in the code, in a more or less accessible way to the public :
- the identifier and the secret of the application,
- access or identity tokens.
With the identifier and the secret, a malicious application can obtain tokens. With the tokens, it could request data on behalf of the real application.
The redirection URL is that of the application, therefore that of its host, ie the user-agent. It cannot be registered on the server and must be provided by the application.
If we are in the case of workstation user-agents ( desktops ) located in a trusted space (one or more known domains), it is still possible to compare this URL to a model saved on the server authorization. But even in this case, if the malicious application is on the same host [1], the distinction is impossible. If we are dealing with a mobile application, it becomes really risky.
In the case of a mobile application, the token request at the Token entry point and the response do not circulate in a connection from server ( that of the application ) to server ( the authentication server ) in which both ends are identified, but between different unidentified mobiles and the authentication server. Thus disappears one of the recognized qualities of the authorization code flow applied to customers with back-end.
There are many additional methods allowing the tokens to be linked to the user-agent or to the TLS connection identifier (TLS Token Binding). This makes it possible to prove that the user-agent (eg the end-user’s browser) is the one with which the authentication was performed and the token created. But this does not make it possible to discriminate between the good application and malware running on the same TLS link. In the same vein, the proof of possession technique Proof of Possession (PoP) seems to lead to the same conclusion.
In particular, the "Proof Key for Code Exchange, PKCE" method, applied to applications without a back-end as part of the Authorization Code flow, strengthens security by preventing authorization code hijacking. With this technique, the secret of the application is not used, which makes it possible not to disclose it. However, this prohibits identifying the application. PKCE makes it possible to ensure that the application which presents the authorization code is indeed the one in which the end user identification procedure was carried out, whatever this application may be.
In the case of a SPA as in that of any application without a back-end [2], it is not possible to ensure that the application presenting the token is indeed the expected application, and not malware.
Encapsulate encrypted data in a Javascript class ???
With SPAs, it is not possible to store credentials using traditional methods, such as access tokens in cookies and session storage. Instead, we imagine keeping sensitive data in JavaScript variables.
Some then recommend using a JavaScript class to store and provide these variables. This method receives the pretty name of "encapsulation" which gives a serious and innovative aspect to a method that is however very banal.
However, this is only an obfuscation method whose effectiveness is insufficient against a determined attacker. A simple web debugger (all modern browsers include one) allows you to execute the code step by step and see the variables pass.
Why do the specs confirm questionable practice ?
We can read in the document Health Relationship Trust Profile for OAuth 2.0 [3]
2.1.3. In-browser client with user delegation
This client type applies to clients that act on behalf of a particular resource owner and require delegation of that user’s rights to access the protected resource. Additionally, these clients are integrated with a web browser and effectively share an active session between systems.
These clients use the implicit flow of OAuth 2 by sending a resource owner to the Authorize endpoint for authorization. The user MUST authenticate to the Authorize endpoint. The user’s web browser is then redirected to a URI hosted by the client, from which the client can directly obtain an access token. Since the client itself never authenticates to the server and the token is made directly available to the browser, this flow is only suitable for clients embedded in a web browser, such as a JavaScript client without a backend server component. Whenever possible, preferred to use authorization code flow due to its superior security properties.
This type of client MUST NOT request or receive a refresh token. Access tokens issued to this type of client MUST be short-lived and SHOULD be discarded when the user’s authenticated session with the client expires.
It is therefore well recognized that there is a problem that the authorization code flow will not solve. This flow is arguably "higher security", but in the case of applications without a back-end it fails to authenticate the application, which may be overridden by malware located on the user agent.
Still, the wording of the paragraph suggests that the authorization code flow will do better than the implicit flow. And we avoid the exposure of the application’s secret in a simple way, and for good reason : "the client itself never authenticates with the server".
In this context, talking about the security offered by the "Authorization Code" flow is a masquerade : n.f. hypocritical comedy, deceptive staging.
An article presenting the cons and concluding on the pros
Here is an interesting article for the analysis that is made : SECURELY USING THE OIDC AUTHORIZATION CODE FLOW AND A PUBLIC CLIENT WITH SINGLE PAGE APPLICATIONS.
The author advocates the use of authorization flow with code for public SPAs, but provides a detailed analysis that highlights the multiple shortcomings of the configuration. Contrary to the title "Securely..." and the conclusion of the article, here is another ambiguity.
By titling on public apps, the author avoids at least disclosing the app’s secrecy, since there is none. This will facilitate the work of malicious applications ! we’re not going to ask for protected data like that.
Incompetence or marketing lie ?
Our article was motivated by reading this one : https://www.ubisecure.com/single-si....
The red thread of this article is simple :
1. Advances in browsers (CORS and cryptography) allow JavaScript to implement the authorization code flow.
2. So we no longer need to implement the implicit flow with the SPAs, but the Authorization Code flow.
Understood : since you know that the Authorization Code flow is the one to use with OIDC, and that you were told that the implicit flow was of questionable security, you understand that everything is fine now.
3. Of course, we have to store the tokens. You have to encapsulate them in a class, so they will be well hidden.
So, incompetence or intox ? Wouldn’t it be a question of making people believe in a new system and thus crediting the existence of a comparative advantage over the competition ?
Why distort the truth ?
OpenID Connect has a good image, it sells well. Too bad if the data is only secure in the case of classic web applications (with back-end). Want to keep up with the mobile app trend ? Then marketers will sell you OIDC without telling you about the limitations.
Better still : they will highlight complementary methods, such as PKCE or POP, suggesting that they provide the solution to the problem of authentication of a client application without a back-end.
What about headless servers ?
The "headless server" configuration is an architecture that allows writers to produce and organize content, while providing developers with structured data that can be displayed using a separate system on the frontend of a site. web or app.
We often end up, on the front-end, in an SPA.
But, since the data is served by an application with back-end, there is a way to ask the end user for OIDC authentication on this application, registered as a client of the OIDC server. If this gives a guarantee on the authorization of the user to access the data, it will not make it possible to identify the SPA and what it does with the data.
So there is no hope of securing SPAs ?
There is an interesting track with applications installed on mobile in Progressive Web App (PWA) mode. Under certain conditions, the code and data of PWAs are maintained, on the mobile side, identical to their model on the server side. Such a SPA - Headless Server architecture (see SPIP CMS headless + Gatsby) could therefore be suitably secured with OIDC.
i-Tego accompanies you
i-Tego (heiress of DnC) provides advice and assistance. We help our customers to implement their own OAuthSD server. We support Dev/Ops by transferring our skills to them, which results in using OIDC only in secure configurations.
And we fully recognize the work of IT to protect access to the network, and thus create the "trusted space" required for the correct application of OpenID Connect.