Acceptable OAuth Flow for a decoupled frontend/Backend Architecture? - go

I have a NextJS frontend and Golang backend architecture with an authentication system using JWTs and an internal user/password database. I'm adding OAuth sign-in in addition to the JWT system, but all API calls will still be maintained using JWTs. I have a working prototype that uses the following OAuth flow:
User is directed to a NextJS page that displays various login options as buttons.
When a provider is chosen, the user is redirected to the backend at /auth/provider where they are then redirected to the provider with all required keys and callback links.
User logs in at the provider and the redirect is triggered to /auth/provider/callback.
The backend server retrieves the user data from the callback and connects the user email to the internal user data for generating a JWT.
The backend returns a page that stores the JWT in local storage and redirects to a NextJS page.
The NextJS page can then use the stored JWT to make API calls.
An additional step could be to exchange the JWT for a new, non-stored JWT or session cookie if the JWT is used twice (potential XSS attempt) and the new JWT is invalidated.
The above method works, but requires a locally stored JWT. Is this a concern, and is it possible to complete the final steps without the need for a locally stored JWT.
Does this flow make sense or am i going about it all wrong? Would swapping to PKCE be overkill?
For the current prototype I'm using the github.com/markbates/goth example code running as the golang backend and a basic NEXTjs server

In effect you have a form of backend for frontend there. It is worth browsing OAuth for browser based apps a little similar to section 6.2 of the above doc.
One option might be to host the backend at a URL like https://api.example.com, then make it write cookies for the Next.js app, hosted at a URL like https://www.example.com.
In this way the backend and frontend parts of the OAuth flow are decoupled, and you also avoid locally stored JWTs. Note the same domain prerequisite, needed for the cookie to be considered first-party, and therefore avoid being dropped by browsers later.

Related

Secure SPA - OAuth Confidential Client (BFF pattern)

i want to reach a confidential client for my backend-system.
The SPA is an angular app. The backend a spring-boot application with different rest-endpoints which stores the objects in a postgres-db.
Actual my SPA got a login page which are connected to the oauth-server. My SPA is currently a public client (client-credentials are stored there). I want to reach a confidential client.
I attached a picture above. The SPA triggers the login. The backend now takes over the authentication, so that the backend is now the client. The backend receives the access token and stores it in a session db. The backend then issues an httponly cookie to the SPA so that the session is secured accordingly.
Is my architecture possible? Are there any examples somewhere? I have no experience in session management and want to programming as less as possible to avoid mistakes and vulnerabilities.
Thanks for help!
yes, you can setup a reverse proxy in the backend that will perform the OAuth 2.0 BFF task, for example see:
https://hanszandbelt.wordpress.com/2017/02/24/openid-connect-for-single-page-applications/
https://github.com/zmartzone/mod_auth_openidc/wiki/Single-Page-Applications
https://curity.io/blog/token-handler-the-single-page-applications-new-bff/

How to access a secured API in the frontend?

There is a lot of good content on the internet that explains how to secure a Spring API with Keycloak: Create a Client that represents the API Service in Keycloak and use a link like the one below to get the access and refresh token:
<Domain>/auth/realms/<realm>/protocol/openid-connect/auth/{some parameters}
This yields both tokens. So far so good.
Now, however, I am not sure how the flow for the frontend accessing the API should look like.
Should the frontend directly access this endpoint and, therefore, obtain the access and refresh token? That would mean that the API can only have the access-type public because there is no way to store the client (the API) secret securely.
Or should there be a third server that somehow stores the refresh token for each user, that the user can call if his access token is no longer valid. This server would then use the client's refresh token (and the client secret that could be stored securely, since it would be in the backend) to get a new access token from Keycloak and would forward it to the user.
I guess the main question that I am asking is, whether the client/user should get the refresh token.
If one needs to implement a logic according to the second option, I would be interested in a link or description of how something like this can be done in Spring.
I think, in either case you need to use the Authorization Code Flow. The implicit flow, which was recommended for SPAs (frontends without a backend server) in former versions of OAuth2 must not be used anymore.
The best option is to have a backend server, so the user retrieves the auth code via redirection and the backend server exchanges this auth code with the access and refresh tokens (and keep them without forwarding them to the frontend).
If there is no backend in place and your frontend needs to retrieve and hold the tokens directly, I would recommend to use the Authorization Code Flow with a public client and the PKCE extension (which - put simply - ensures that the entity asking for the auth code is the same as the entity asking for the tokens and that the auth code was not stolen and used by a foreign entity). There are several sources with more detailed explanations, which might help you, for example: https://auth0.com/docs/flows/authorization-code-flow-with-proof-key-for-code-exchange-pkce
Hope this helps you with your architectural considerations.

Autorization Code Flow with REST API "backend" on a different domain

We are using OIDC and IdentityServer in an enterprise deployment where at the moment we control everything (OP, clients, resources, users).
We have an SPA client that connects to its "own" API and will go through it for everything it requires to do. They are however being served from two different domains. (Let's say the application runs on "my.apps/app" and the API in "my.apis/api").
In our current setup, we use Implicit Flow to have the user authenticated in the SPA and then call the API and verify the token within it. This works very well.
We treat our API as a "resource" even though we don't need to and we don't require the user to give consent.
As mentioned, the SPA needs to go through the API for everything it does and this also includes augmenting user properties upon authentication, so the client doesn't even really let users work with it without going through the API.
Given that scenario, our thinking was that we could even be using Authorization Code flow for our OIDC authentication (treating the API as a backend) and get the security "benefit" of the browser never having access to the tokens.
However, due tue the applications being hosted separately we think this would require us to either:
Initiate the authentication request in the SPA, get the Authorization Code in the fragment but pass it later to the API which will in turn request the tokens and have them live in a cookie or something along those lines.
Initiate the authentication request in the SPA but use redirect_uri to the API domain, thus giving the Authorization Code to it which will request the tokens, have them live in a cookie and then redirect to the SPA again.
Basically we want to know if this is a setup that you think would work, what are the security concerns if any, and if it would be recommended for us to go ahead with this or to keep using Implicit Flow instead (specially from a security standpoint).

How to protect REST API when using AJAX?

There are SNS application with 2 servers. Web backend server and REST API server.
The web server allows user login/logout with username/password, and show user information
The REST API server provides APIs like /topics, /comments, it should be stateless without session
The REST API will serve other web applications
There are some potential solutions, but neither is security.
Base Auth, the browser hold the username/password
Token with expiry timestamp, the problem is user could stay on the page until token expires
So, is there a way to protect the REST API when calling it from AJAX?
If I have understood your problem correctly I may suggest you use the Token solution. In order to maintain security you may generate new token on every request (& send it to client in response), which should be used to make next request, and disable token if it is once used or has expired.
Sorry, I meant to mention it as a comment, but I don't have enough reputation.

REST authentication, Best approach

Background:
We are building system that required login information for all pages. the application is designed to be Restful application using codeigniter as Phil Sturgeon library.
Scenario:
- username & password is required when a user called any page [Client]
- Authentication is needed where any Api call is fired
I a bit confused how to migrate or do the above scenario, And what are approach to authenticate the application.
A simple way to authenticate users in a RESTful API is using HTTP Basic or Digest Auth. In this setting the user credentials are sent via the Authorization header in a form of username:password as Base64 encoded hash to the server.
As the principles of REST state that the communication between client and server should be stateless, the client has to sent the authorization on every request. In practice this means that you often store the credentials in a session on the client side (as you don't want to the user to enter his credentials on every request). Please note that you should only do this via an secured connection using HTTPS!
To authenticate the application you could use a token based system, such as an API-Key. This means any request would be signed using additional request parameters. If the number of applications is finite and known, you could alternatively simply identify them by their IP.
You could also take a look at OAuth.
Request the login and password for every page is more suitable and more secure(that what I do in my projects), using 'virtual' and stored session in the database may be a second solution but not a good because it will be an additional charge for the DB.

Resources