I am thinking of using IdentityServer4 for a new project. I am new to this and have done some reading and seen some of the demo clients in action.
Most of the clients in the samples allow login as a User and issue a token.
Requirement
I have multiple applications and the are for example, MVC/SPA/Mobile etc. I wish to allow each application to be a client and call an API.
I need a setup where applications can call a protected API without a user being logged in. So the API is protected based on scopes.
I know I can use client_credentials flow to get access_token and call my API. Which is fine for apps like the MVC as the secret will never be exposed.
I read that this flow is not recommended for mobile/SPA apps and to use Authorization Code flow, but I can't seem to get a token without it asking to login as a User.
Question
What other flow can I use to get only access_token without logging in the user and keeping my app secure?
Or, should I just use client_credential flow in my mobile apps and SPA's?
Related
Context
We are transitioning our Spring Boot application (with Angular frontend) from Spring's build in OAuth2 based security to Azure-AD. This is working well for clients we can update right away (mainly the B2B clients). However some (most B2C) clients can not easily be updated at the moment. In time this will happen, just not now. So I need a solution for the mean time.
Our idea
We proxy the request for the Azure tokens via the Spring Boot backend. From the client's point of view, it would look like the old solution. Username and password would be authenticated against the backend's database. Upon successful authentication, a certificate would be looked up for the user and this would be used to aquire an access and refresh token from Azure-AD B2C containg also a token for B2B.
That token would be wrapped into Spring's old OAuth2AccessToken and sent back to the client. The refresh request would be proxied in a similar way.
I have the refresh part working based on this: Web sign in with OpenID Connect in Azure Active Directory B2C -> Refresh Token
The problem
Using Microsoft's Graph API I can get an access token, but the part of the MsalToken extends AccessToken that is public (AuthenticationResult implements IAuthenticationResult) does not let me access the refresh token even if I request scope offline_access and if it is contained in the result.
Questions
Are there security concerns that make this idea a fundamentally bad idea? I'm aware that this requires trusting the backend, but that was the case so far. To me that does not seem to make it worse.
Is there a way to get an access- and refresh-token for a user be presenting the users certificate (or another none-interactive method - but we do want to use MFA as well for updated clients). I tried using Microsoft's Graph API, but a direct web-request is fine too.
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.
I am having difficulty understanding Hybrid flow with mobile application. I am using code id_token Hybrid flow provided by Identity Server 4 in .Net.
Here is my scenario.
All mobile request will go to backend server and backend server will forward request to different APIs on user behalf.
When user first time login
He will be redirected to identity server
A mobile web view will be opened
User will sign in using credentials
identity server will send Id Token and Access Code to Back end
Server
Back end Server will swap Access code for Id Token and Access Token
What token will be returned to mobile application to provide that user is valid. And is it responsibility of Back end server to get new access token without prompting user to re login until user sign out?
Is there any step wrong in above scenario ?
For mobile clients its recommended to use Authorisation code flow along with PKCE. Please read through these two answers to grasp some idea why its suggested Link-1 & Link-2.
Also, RFC8252 provide some best practices application for Native Apps (mobile clients are native apps.!). In that, it recommend not to use web-views.
here is a quote from RFC8252-overview
Previously, it was common for native apps to use embedded user-agents
(commonly implemented with web-views) for OAuth authorization
requests. That approach has many drawbacks, including the host app
being able to copy user credentials and cookies as well as the user
needing to authenticate from scratch in each app
By using web-view, you loose the true essence of OAuth 2.0. You client app get the ability to grasp end user credentials. So use the browser instead of web-view. (Please read more about embedded users agents from this link)
In your architecture, you could enable all of these, PKCE, Authorization code flow and usage of browser instead of web-view. But once the backed receives tokens, it should pass them to your client. That will be a challenge if you stick to this architecture.
But if you can make your mobile application to complete whole flow, you avoid that complexity. Once tokens are received, you may create a connection between backed server by validating tokens. Also, when tokens expire, mobile app will use refresh token to obtain new tokens.
I am quite new to the django-rest-framework and building APIs, and I am thinking of way to secure my APIs.
My question is:
How to allow only your front-end application(AngularJS) to call specific (django-rest-framework's)API endpoints?
For the time being I have set permission to all my Views to be IsAdminUser. Also I have created superuser account(for the front-end app). First step is that my front-end app sends requests to login endpoint which authenticates an app, and if successfull, it sends back user token to allow futher API calls. Then user is able to register and/or login, and as soon as he authenticates using his own details, further requests are executed using his own token.
It is working however it is quite spoof. Can someone with more experience advise me on how to allow my APIs to be called only by my front-end client?
Inside my servlets, this is how I authenticate user
UserService userservice=UserServiceFactory.getUserService();
User user = userservice.getCurrentUser();
if(user == null){
response.redirect(userservice.createLoginURL("../userhome"));
}
More recently, in the same project I used Google Cloud Endpoints with authentication to access data using a JS client. The JS client authorizes using Oauth
gapi.auth.authorize(...);
Although they belong to the same App Engine Project and share the same credentials, the servlet and JS client ask the user to sign in independent of each other - as if they were two different applications.
I want a single sign in for the whole application. How do I do this?
Here are some points:
It is important that you have authentication at both the levels. This is a good practice and does not leave your functionality open for execution without any authentication mechanism.
When you are doing the authentication on the client side, the whole authentication layer passes this User object to your Google Cloud Endpoints code. So, it is good if you could inject the User object in your Cloud Endpoints method to extract out the information of the user and do your own authorization if needed.
In summary, you are not really doing an authentication again at the Server side if you notice. You are only checking if the authentication is done or not and then proceeding forward.