I have 2 ASP .Net projects each with its own database:
Identity App: acts as an authorization server with its own database that contains user info. Uses identity 4: Oauth 2.0 and OpenId (code flow)
Resource App: Api that returns access to multiple resources. (database doesn't include anything about users)
Our front end communicates with the resource app mainly and uses the identity app for authorization. Now we are developing the functionality to add a user from the front end and to get all the users.
My questions:
Should the frontend communicate directly with the Identity App to get the users?
If not, how can I get the user info through the resource app?
I tried the following flow for adding a user but it didn't work:
Frontend posts user to resource API (Note: the user is already
authenticated using the authorization server)
I use the authorization header in that request to build a rest sharp request
to the authorization server
The authorization server isn't recognizing the bearer token
I'd recommend storing the majority of user data in the resource app's database.
Over time this will contain lots of fields that are nothing to do with OAuth, such as app specific preferences.
Meanwhile you also need to store a few fields related to login in the identity app: name, password etc.
My write up may help you to understand the separation and achieve your goals: https://authguidance.com/2017/10/02/user-data/
Related
Context
I'm building a hybrid native/web app. Part of it will be API driven, and part of it will be webviews showing an existing website.
Once logged in with my OIDC SDK (Amplify/AppAuth), I can access the user's id_token and access_token.
However, because the webviews used in the SDK are not controllable, I cannot reuse the cookies generated by my identity server.
Question
For the reason above, I'm trying to login a user from their id_token or their access_token. (both are JWTs)
I believe this isn't supported by IdentityServer4, but I am looking to implement something myself.
What I have found so far:
1) id_token_hint
OpenID Connect Core 1.0, Section 3.1.2.1, id_token_hint parameter:
OPTIONAL. ID Token previously issued by the Authorization Server being passed as a hint about the End-User's current or past authenticated session with the Client. If the End-User identified by the ID Token is logged in or is logged in by the request, then the Authorization Server returns a positive response; otherwise, it SHOULD return an error, such as login_required. When possible, an id_token_hint SHOULD be present when prompt=none is used and an invalid_request error MAY be returned if it is not; however, the server SHOULD respond successfully when possible, even if it is not present. The Authorization Server need not be listed as an audience of the ID Token when it is used as an id_token_hint value.
If the ID Token received by the RP from the OP is encrypted, to use it as an id_token_hint, the Client MUST decrypt the signed ID Token contained within the encrypted ID Token. The Client MAY re-encrypt the signed ID token to the Authentication Server using a key that enables the server to decrypt the ID Token, and use the re-encrypted ID token as the id_token_hint value.
According to this optional spec of OpenID, I should be able to use the id_token on the /authorize endpoint to login the user. I know this isn't implemented in IdentityServer4, but I'm looking at AddCustomAuthorizeRequestValidator to do that. However I'm not sure how to "get a user from their id_token" in the code. Do you have any pointers?
2) using AddJwtBearerClientAuthentication
This method sounds like I could authenticate from my access_token, but I can't find much documentation on how to use it.
THE PROBLEM
Let me know if I am misunderstanding requirements, but it feels like you have 2 different apps and are trying to make them feel like a single integrated set of screens.
The default behaviour will be as follows since web views are private browser sessions and cannot use system browser cookies. You want to prevent the second step since it is a poor user experience:
User signs in to the mobile app
Whenever a secured web view is invoked, there is a new private browser session with no auth cookie, therefore requiring a new login
COMMON APPROACH: SUPPLY A TOKEN TO THE WEB VIEW
It can be common to forward the mobile token to the web view, if the two apps are part of the same user experience. If required, extend the mobile app's scopes to include those for the web app.
You should not need to issue any new tokens or change the security model of either app. But the mobile and web apps need to work together on a solution.
POSSIBLE WEB VIEW SOLUTION FOR A SERVER SIDE WEB APP
This might be the simplest option:
Provide new .Net Core web back end entry point URLs that require tokens instead of cookies
The mobile app could then call those endpoints from web views, and supply its own token in the Authorization Header of the web view request
The web back end could then forward mobile web view requests to your Web APIs
The code to add the Authorization Header to a web view request may be a little tricky but there are ways to do it:
Android
iOS
POSSIBLE WEB VIEW SOLUTION FOR AN SPA
An option that works for Cookieless SPAs is for the web view to ask the mobile host app for an access token via a Javascript bridge. Some code of mine does this for a cookieless SPA:
Web UI Code to Call the Mobile Host
Android Code
iOS Code
You can clone / run the mobile github repos from your local PC to see the solution. I will be writing up some notes on this in my blog's Mobile Web Integration Post.
I have project with Angular-WebApi architecture, I need to add IS to authorize users, but I don't need mvc with redirect, I would like to send user creds from Angular App to IS API, get JWT, and use this JWT, to get data from Resource API. I can't find any examples of it.
You can use angular-auth-oidc-client for your angular app
you can refer here for sample how to do it - https://github.com/damienbod/angular-auth-oidc-client
for Idp sample, Identityserver4 did provide sample for configuration under JavaScriptClient project. You can refer here, https://github.com/IdentityServer/IdentityServer4/tree/master/samples/Quickstarts/4_JavaScriptClient
You can also refer to my project which use angular, IS4 and resource server
https://github.com/firdausng/testnt
but I don't need mvc with redirect, I would like to send user creds from Angular App to IS API, get JWT, and use this JWT, to get data from Resource API.
Normally user will be redirect to Identity Server and enter credential in login page , in Angular application , you can use Authorization Code Flow with PKCE .
But if you want to collect user's credential in Angular and send credential to IDS , you can use the Resource Owner Password Flow with Identity Server . But that is not recommended because The ROPC flow requires a high degree of trust and user exposure and you should only use this flow when other, more secure, flows can't be used.
Architecture of my application is something like this.I have a application which is hub for many other applications which allows user to pass credentials. After credentials are checked, Hub application presents one or more applications which the user is allowed to use. If user has only one application it redirects directly to the application. How do i maintain the authorized state of the user passed in hub application and access them again in the children application?
There is no "one way" to do this. But one way to do this is to provide a Javascript Web Token (JWT) back to the client if they log in successfully. The server can then know, authentically, who the user is that made the request if the client provides the JWT as a request header (typically "Authorization: Bearer JWT- goes-here). You can keep the JWT in some kind of local storage like IndexDB to share between applications (assuming same domain URL) and delete it if the user logs out.
Also, in case it's not obvious, definitely use HTTPS. There is no excuse not to in 2019, with the existence of LetsEncrypt.
if you are using Express.js use express-jwt and jsonwebtoken packages to accomplish this scheme.
I'm following the guide and example provided by Microsoft here and I'm able to get the demo working, with the authentication happening in a console app, then making a request to a Web API with the correct token.
I'm looking to use this but the code in the console app would need to move to a Web App. Essentially: external server tries to access secure Web API, providing Azure AD username/password in the Authentication header of a HTTPS request. I pick up these credentials in the first insecure Web API, and attempt to authenticate the credentials against AD, obtaining the token. From here, I would then call the [Authorize]-protected Web API by making a request with the AD token.
At this point I'm using the same code from the example linked above, simply moving the code in the Console app up into the first insecure Web API controller, but I'm having no luck. I read on CloudIdentity that "You can only use those flows from a native client. A confidential client, such as a web site, cannot use direct user credentials.". Is this true? If so, is there another way to achieve my aim? I need to use the credentials as it may be likely that more services would use the API in the future, so each of these would need their own credentials to use that could be managed within Azure.
EDIT: In reading more around this, should I actually be aiming to use Client authentication, creating an "Application" within the Azure AD, and providing the client ID to each external service looking to call the API, to then authenticate with that, rather than credentials?
Yes, your edit is correct. The Resource Owner Password Credentials grant is meant to authenticate users, not applications. Typical use would be from an application that prompts you for username and password and then retrieves a token from Azure AD.
You can use the Client Credentials grant to get a token from Azure AD from a confidential client to call an API without user context. This flow requires that you register the application in Azure AD and generate a key (which will be used as the client secret). You can then use the ADAL library to ge a token from AAD as shown here.
I have a question regarding the best standard architecture of Authorization in web application that is written in Asp.Net Web Api on the backend and and has an angularjs client side.
According to what I had seen before, the "Resource Owner Credentials" flow is what would be used in such cases, where the webapp would send the user's credentials to the server and obtain access token (and refresh token) and then using an interceptor, every call to the backend apis would contain the access token in the header.
However, I have recently seen arguments about it being a bad idea, as it gives the user's credentials to the client app.
What is the best flow for a scenario when you have javascript client directly calling you WebApis? What is the best way to secure it using Identity Server?
You could also consider implicit flow or hybrid flow, when the client app (angular) is redirecting the user to login on the openid identity provider (Identity Server) an upon a successful authentication, this returns an access/identity token which can be used in subsequent calls to the Apis.
In this case the client app is never touching client credentials, it always has to manage tokens.
see also https://www.scottbrady91.com/OpenID-Connect/OpenID-Connect-Flows