Autorization Code Flow with REST API "backend" on a different domain - asp.net-web-api

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).

Related

Is this a secure authentication flow (with Auth0 and SvelteKit)?

As there is currently no Auth0 SDK for SvelteKit, I am learning (or at least trying to learn) far more about authentication than I originally intended when setting out to incorporate Auth0 into my SvelteKit app (including server side authentication). The documentation is a little confusing (or maybe it is just massive, or maybe I am just not that bright), so I was hoping to describe my auth flow here for critique (in the hope that this will be helpful to others in the future).
I have reviewed this great post about SPA auth as well as Auth0's educational offerings. Still I am not sure I am connecting the dots properly. Here is my flow. All of this occurs over SSL only.
I create an Auth0 client on the client side using their client SDK (#auth0/auth0-spa-js). That client performs authentication via the Auth0 popup.
Once authenticated, everything works as expected on the client side. But if I want to control access to routes on the server side, I need to get information back to the server. So...
After authenticating, Auth0 creates an ID token (a signed JWT) which is stored in the browser's local storage. I save it as a session cookie (with SameSite=strict; HTTPOnly; Secure; options set) so that it gets passed back to the server with requests for route authorization.
So let me pause right here...I understand that (at least according to some including the Auth0 educational video linked above) the ID token is not supposed to be used for authentication and should never be passed around. That is what an access token is for. However, in this scenario where the exchange is all first party (my client, my server), it is my understanding that it is "ok".
However, it does make me nervous that the Auth0 SDK is not setting the cookie itself. This makes me wonder if I am Doing It Wrong™.
On the server I validate the id_token using a public key, and can then save user details, etc. on the backend if I wish, and allow access to appropriate routes (via hooks.server.js in the case of my SvelteKit app).
When the user logs out, or if the token expires, the cookie is removed.
(As a side note, I have yet to figure out how to refresh the ID token when it expires as the Auth0 client SDK does not seem to ever update the ID token in the browser storage even if it is expired.)
Is that a secure and typical way of going about it?
(For a work in progress working example, see my svelteauth0 repo.)

Acceptable OAuth Flow for a decoupled frontend/Backend Architecture?

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.

Elixir Phoenix Absinthe GraphQL API authentication in both web and mobile app's

I'm working on an Absinthe GraphQL API for my app. I'm still learning the procedure(so please go easy on me).
I've a Absinthe/GraphQL MyAppWeb.schema.ex file in which I use for my queries and mutations. My question is how do I use this API for authenticating the user on both Mobile and Web app?
How do set a cookie(httpOnly & secure) in my web app and access/refresh tokens in a single Absinthe API to serve my website and mobile app. Basically what I'm trying to learn is how do I authenticate the user based on specific platform.
If my question sounds bit confusing, I would be happy to provide more information related to my question. I would really be grateful if someone could explain the procedure, I've been very stuck on this for a while.
I would avoid using authentication mechanisms provided by absinthe(if there are any). Depending on what front-end you are using, I would go with JSON API authentication. The flow on server goes the following way:
Create a endpoint for login that will receive a user and password and will return a refresh token.
Create a endpoint for exchanging refresh token for access token.
Use a library like guardian to generate your refresh/access tokens.
Create a phoenix plug for authentication that will check your tokens, guardian has some built-in plugs for this.
Now on device you have to implement:
Ability to save refresh and access token on device.
Have a global handler for injecting access token on authorized requests.
Have a global handler for case when access token is expired. (you usually check if your request returns Unauthorized, then you should request a new access token from the server using your refresh token)
This seems like a crude implementation, however I would advise in implementing your system instead of using a black box library that you have no idea how it works under the hood.

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.

Malicious requests detecting/validating requests

Application has front-end and back-end modules, front-end calls rest services from the backend written on Java/Spring.
Is there any best practices how to detect malicious request generated not by the front-end (if some user try to call service direcly from the back-end via rest client)?
Maybe generating some hash value for every request on front-end and decrypt this value on back-end validating this request?
What you need is authentication. The backend needs to authenticate either the frontend web app, or the user itself.
Probably the most common way is authenticating the frontend, which practically means that frontend and backend have a shared secret, authentication takes place upon each call, and the backend trusts the frontend. This can be achieved in countless ways from http basic auth (over https of course) to some kind of an api key mechanism (signing requests, etc.) You don't have to reinvent the wheel, depending on your usecase and threat model, http basic auth over https may very well be enough.
Another way to do things is to delegate user credentials to backend services. This is most often achieved by passing single sign-on tokens from the user to the backend, effectively impersonating the user when the frontend calls backend services. Arguably this is more secure, as for instance it does not need that level of trust between web and app, but services still need to trust the SSO component that issued the token. The point is that there is no secret for an adversary to steal (let alone from the frontend server, which may be an easier target), so it may be more difficult for an attacker to issue requests to backend services, even if some backend and/or frontend servers are already compromised.
So while I think an answer here is not the right format to go into details about how exactly to do this authentication (there really are multiple good solutions, and in every case, implementation details matter very much), at least conceptually these are your options I think.

Resources