How to integrate GitHub Actions OIDC with IdentityServer 4? - identityserver4

I'm trying to allow GitHub Actions to call my REST API that is protected with IdentityServer4. I take a look on GitHub docs about its OIDC and I understand that I can request for ID Token inside Actions. The question is how to get access token from IdentityServer4 with this ID Token so GitHub Actions can invoke my REST API?

For a client to get a ID-token, then a user must be involved to authorize the client so that you can get the ID/access token. (using the authorization code flow).
A better approach might be to use the client credentials flow, that is used for machine-to-machine communication and you can configure a client definition in IdentityServer that issues an access token to your GitHub action using a simple username/password (client/clientsecret). That is the simplest way to get it to work. In this flow there is no use/need for any ID-token.
see https://docs.duendesoftware.com/identityserver/v5/tokens/requesting/#machine-to-machine-communication

Related

Microsoft Graph - OAuth2.0 flow for React client and spring-boot backend

I am building a React-based SPA that communicates with a spring-boot backend via a REST API. I need the user to be able to log into their Microsoft account on the browser client (the SPA) and I need the backend service (spring-boot app) to be able to query Microsoft's Graph API on behalf of that user.
After reading up on the Oauth2 flows, the authorization code flow (not the PKCE flow, just the regular authorization code flow) seems the most appropriate. The browser client could let the user log into their Microsoft account, retrieve an authorization code, and send the authorization code to our backend service via HTTP request. The backend service (which is trusted and can safely store a client secret) can then request an access token, make requests to the Graph API directly (meaning that the SPA would never need to make any requests to the Graph API), and silently refresh the token as needed.
However, I cannot see any examples of anyone using this flow to access Microsoft's Graph API.
Looking at Microsoft's documentation, it seems like they recommend using the on-behalf-of flow. But this flow requires the browser client to request an access token and then use that to communicate with the backend service (which in turn can communicate with the Graph API). It doesn't make sense to me why the access token cannot be requested on the backend using a client secret. Wouldn't this be a more secure and preferred method than having the client retrieve the access token, as is done in the on-behalf-of flow?
The Oauth2.0 site, recommends that SPAs should either use the authorization code with PKE or the implicit flow, but I do not see an option to use the standard authentication code flow for SPAs. Should I take this as an indication that SPAs should not be using the standard authorization code flow as I described earlier?
Despite not finding a clear-cut example of the standard authorization code flow in Microsoft's documentation for a react frontend + java backend, I tried to go about doing this myself. However, using the #microsoft/mgt-react and #microsoft/mgt-element libraries to do this are not straight forward. For example, the #microsoft/mgt-element notion of a Provider supports a call to retrieve an access token, but doesn't clearly expose the authorization code. If I wanted to do the authorization code flow described earlier, it seems like I would need to use raw HTTP requests, which I know is not a recommended way of accomplishing this.
Summarizing my questions:
What OAuth2.0 flow should I be using: 1) authorization code (access token is retrieved by backend service using client secret), 2)
authorization code with PKE (access token is retrieved by client), or
3) on-behalf-of flow (access token is retrieved by client, seems to be an extension of PKE flow)?
If using the on-behalf-of flow, does the SPA just include the access token in the header (marked as 'bearer') and the backend service just
includes that same header to query the Graph API, or does the backend
service need to request another token before querying the Graph API?
Agree with #ch4mp to call graph api directly in SPA if it's allowed. If not, then I recommend you using on-behalf-flow or client credential flow based on your requirement.
Let's come back to your requirement -- call ms graph api in a springboot api project. First, let's see one of the graph api getting user api. You can see permission types here: Delegated which means call graph api on behalf of the user, Application which means calling api on behalf of the application(your spingboot api project) itself. If you want to call api behalf of the user, then you have to use on-behalf-of flow. This is because the api project which will be considered as a daemon application, so the project itself doesn't have a UI page to let users enter username/password to sign in and get authenticated.
You can certainly use ROPC flow which have to pass the username/password to api but I really think it unsafe, so I don't recommend.
If it's not necessary for you to call graph api on behalf of user, you can certainly take client credential flow into consideration. But pls note here, application type api permission is a "large" api permission which always have name like User.ReadWrite.All, Mail.ReadWrite.All and it always means the application can not only query user information but also be able to modify user information.
If you want to use on-behalf-flow, then you may review this answer and it explained the whole progress...
I would use authorization-code flow (with PKCE) to get an access-token and then refresh-token flow to "maintain" this token, both from client.
Authorizing the request to your resource-server with this token only makes sense if Microsoft authorization-server is your main authorization-server. Otherwise (user also logged in with an authorization-server of your own or not using OAuth2 betwean React and backend), you can still send Microsoft access-token in request body.
In any case, when issuing requests in the name of the user from the backend, do as you suggest: just set the access-token sent by the client as Bearer Authorization header (token is retrieved either from Spring security context or request body). Backend fetches a new access-token (using client-credentials flow) when issuing requests in its own name (without the context of a user).
Side note: have you considered calling Microsoft API directly from React client? If you don't have to store the result of that call on your resource-server (i.e. call graph API to display data and store only what user selected from that data), that would save quite some latency on the client and costs (network and CPU) on the backend.

Is it safe to have a frontend button that links directly to backend?

I am creating a full stack application with a React/TS frontend and FastAPI Python backend both on different domains/origins. For my first API endpoint (an auth endpoint), I cannot use axios.get(/login) as I planned as I'm using a 3rd party API in my backend that doesn't work with redirects to my frontend. The solution seems to be to have a login button with an a tag that directly links to http://backend_url/login. This does work, but it feels weird/unsafe to literally send users on the frontend to the literal url of my backend as opposed to just calling HTTP requests to the backend. Is this bad practice? Is there a better way to accomplish this? I appreciate any direction.
The question is more on how to deal with a 3rd party API that a user needs to authorize, see comments on OP.
You can redirect directly from your frontend to the /authorize endpoint of Spotify. They will call the returnUrl that you gave when you registered your application with them, and provide a authorization code. If this is in your frontend (e.g. http://frontend.com/oauth/callback, that can take that authorization code and feeds it to your backend (for example, to http://backend/api/auth). That endpoint can exchange the authorization code for access tokens (calling the /token endpoint of Spotify, of something similar) using the client credentials that you received when you registered your application with Spotify. The backend can store and use those access tokens, and your frontend can call the backend.

PCKE implementation for React SPA and REST API

I need to implement a system where the frontend is a pure SPA made with react (by pure I mean it is only hosted as a bunch of static files) and a nodejs REST API made with express. I can not use any 3rd party authentication providers like Auth0, etc. so everything must work locally.
The app must have authentication and it must be more or less up to modern standards. I am looking to implement PKCE flow with short-lived JWT auth tokens and long-lived refresh tokens.
There is one thing I am confused about. Every guide on PKCE flow always mentions redirects from one URL to another during the auth flow. In my setup, however, redirects are highly unwelcome.
I want to check and find out whether it is OK to implement PKCE flow using pure XHR requests to communicate between the SPA and API. Is it appropriate to do so? What major risks are there compared to a setup with redirects?
EDIT: to make this question more specific, what should be the PKCE authentication flow if you can only use SPA and XHR (and must avoid redirects)?
There is one thing I am confused about. Every guide on PKCE flow always mentions redirects from one URL to another during the auth flow. In my setup, however, redirects are highly unwelcome.
The whole point with OAuth 2.0 is the delegation (redirect) to the ID Provider, such that the user always send his password to the ID Provider instead of sending the password to each application. So you will always need to redirect the user to sign in - but hopefully the user is already signed in, so he immediately becomes redirected back to your app. There are techniques to check if the user is signed-in using XHR, that can be used until he need to sign in.
what should be the PKCE authentication flow if you can only use SPA and XHR (and must avoid redirects)?
In the Authorization Code flow, the client typically does two request to the ID provider. The request to authorization endpoint typically is done through a redirect (e.g. in case the user need to authenticate), but the second request, to token endpoint can typically be done in the background using XHR or fetch using appropriate CORS configurations.

React SSO using SAML without web server

I have a web app developed using Create-react-app
I host it on IIS, the IIS only response to load the app, there is no server side logic on it (no Express or any other web server)
The app is using a RESTful API on the same IIS, it is out of my control (I cannot make change).
Now one of my client request to add SAML SSO to our app.
I would like to know:
in normal situation, which one is the Service Provider? My IIS Web server? or the API service?
For my case, I cannot implement SAML to API service, my web service only used to load my app without server side logic, how can I implement SAML?
Could any one give me some React implement SAML SSO tutorial or article for reference?
Thanks for any help, any information or suggestion are welcome!
in normal situation, which one is the Service Provider? My IIS Web server? or the API service?
I assume the client wants to authenticate the users using their internal IdP. So your application is the SP. But you will have to define different token service (details below).
With SPA (a single-page-applications) I see the problem, in SAML the user is redirected or posted away from the SAML request and SAML response.
I have a login page to enter id/pw, post them to API server Login endpoint to authenticate and get back a JWT token. After that we use that token in API calls for authentication
The API services are using a JWT token issued based on the provided username/password. I'd recommend to extend the token service (or use a different service) to issue a JWT token based on the provided SAML response - a token swap service. In many OAuth implementations it's called SAML grant type.
I cannot implement SAML to API service, my web service only used to load my app without server side logic, how can I implement SAML?
Usually after the authentication the user is redirected or posted to the SAML ACS endpoint URL, where the server can create sort of session (cookie, parameters, token, ..) and the user is redirected to a URL returned the web page with the session information.
If you are using an SPA, you could use a popup window or SAML with redirect (not with post), where the page could read the SAML response parameters (assertion, signature, ..) and use them in the token swap service mentioned above.
When processing the SAML response, try to use some mature, known, out-of-box libraries, it's a security service and not doing it properly may cause security weaknesses. But you need to do that on the server side, as at the end you need the JWT token consumed by the APIs.

Authentication and Authorization in React app

In a .NET app I can add authentication and authorization using web.config and/or IIS. I can also use [Authorize (Roles = "RoleABC")] in a MVC app's controller or action. And even extend the AuthorizationAttribute
I'm looking into creating a React app for intranet use, and reading these tutorials (ReactJS and MS), but can't find authentication/authorization details.
Even though the app will be Single Page App, I still would like to authenticate and authorize users for certain options within the app, just like I can do in MVC app.
Is the only option to do that way is creating Blazor app instead?
For authentication and authorization, you should use auth tokens (like JWT). Your backend should create an auth token when a client logs in to the system and sends it to the client. Your server also should send the authenticated user information to the client (react app) so that you can render correct pages according to the user type. For example, you can render the admin page for an admin type of user, and the guest page for a guest type of user. You can save this user data as JSON in Redux. Hence you can access the user data from any component of your react. Also, in your backend, you must restrict the endpoints according to the auth token which is sent by the client. In the backend of my app, I follow the below steps:
Authentication check -> Authorization check -> controller (endpoint) -> result
React isn't opinionated on this, so it's up to you to design the implementation. A basic way to do this is:
Log in and obtain an authorized JWT token from the backend and include the account ID when you sign it
Store the JWT token in localStorage, store the account info in Redux
Conditionally limit routes based on account info (ie. admin group) on the front end
Have every auth-required API call include the JWT token in the x-auth-token header, then on the backend use middleware to check if it's still valid. You can then also decode the account ID in order to check its privileges so that you can limit API access
This may be helpful: https://medium.com/#faizanv/authentication-for-your-react-and-express-application-w-json-web-tokens-923515826e0#5f52
Not sure whether you still need this - I personally feel we should have something bridging the authZ gap between server and client to make it easy. So I spent a few days on a github project for this purpose, here it is: authzyin.
What I tried to do is to leverage policy based authorization from asp.net core - which I think it's very cool - and automatically bring the same definition to the client to use in React via hooks.
For authentication I am using msal.js against AAD - so authN is done on the client and jwt bearer token auth is used for all requests.
It has a client lib and a server lib which can be used together or separately. Of course it might still be lacking some features - please feel free to take it as a reference (contribution is also welcome).

Resources