I have a single page application written in angular 7 which communicates with my ASP.Net Core 2.2 Web API server.
On login, the user sends his credentials to my authorization server (connect/token) using "resource owner password credentials" grant.
I am trying to add 2-factor authentication (SMS), but I can't find any example describing how to do this. All the examples I found were written with MVC using cookies authentication.
I was thinking about this flow but it feels to me there should be a much better way
A user enters his user name & password
If the user has 2 factors enabled I will send him an SMS with a code. In addition, a limited access_token and id token will be sent to the client. this access_token will be valid only to enable the user to send the 2-factor code.
if id-token will have a claim for 'two factors': 'on', I will redirect the user to an SMS confirmations code.
The user will send a post request with the code. If the code matche, I will return to the client a new access_token with all the claims.
2FA is a very bad fit for the resource owner password credentials grant (at least, not the standard flavor).
An interactive flow like the code or implicit flows will allow to easily implement that using ASP.NET Core Identity and its default controllers/Razor pages, in a completely standard way.
Related
I have created a new Blazor WebAssembly project with a separate API project. My WebAssembly project will
query this WebAPI for data.
I have included Identity in my app and this seems to work. I can register a new user and use the below code to log in a user on my Web API.
Code used to log someone in:
var result = await _signInManager.PasswordSignInAsync(model.UserName, model.Password, false, lockoutOnFailure: false);
if (result.Succeeded)
{
//I arrive here, so login was succesful
return true;
}
So Identity seems to be working.
What I'm wondering now is:
my user logs on in the web assembly app
this app uses HttpClient to send a request to my server to authenticate the user, using a username and password
the server checks the username and password and uses _signInManager.PasswordSignInAsync(username, password) which works
How does my client know which user has been authenticated? How can I display more information about this user, check his roles, ...
Does anyone have any guidance or best practices on this please?
Since Blazor WASM is entirely executed on the client, there are two different authentication models: Cookies and Token. (There are more). The basic idea, though, is the same. With each HTTP request sent by HttpClient, an additional header is sent to the server.
Personally, I think Token authentication is a much smarter way supported in different libraries and can be implemented very quickly.
In a nutshell:
With a token-based approach - to be more precise with OpenId Connect -,, you provide an identity service, and your Blazor application will become a client. The token, unlike a cookie, can be read easily by a client. If configured properly, it contains information (claims) like the user's name or email address.
The identity service is an MVC/Razor page application with special libraries handling the authentication flow.
The authentication flow (very, very briefly):
A user wants to login into your Blazor application. If there is no token available, the authentication process starts. The Blazor application redirects the user to the "authentication flow" part of your identity service. It is an endpoint without any "visual" result. The result is another redirect to your MVC/Razor page login view. You can implement any authentication logic here. If the user has been authenticated successfully (based on your logic), the user is redirected back to your Blazor application with a valid token in the URL. This token is extracted and can be used to access an API.
It sounds a bit complicated, and it is a lot to learn and understand. However, you will get a reliable, widely used, and safe way to do authentication and authorization.
As a starting point for reading
https://identityserver4.readthedocs.io/en/latest/quickstarts/0_overview.html
https://identityserver4.readthedocs.io/en/latest/topics/signin.html#login-workflow
https://learn.microsoft.com/en-us/aspnet/core/blazor/security/webassembly/standalone-with-authentication-library?view=aspnetcore-5.0
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 am trying to implement WEB API 2 (for Single Page App, not as part of Visual Studio project) OAuth2.0 protocol. As per Which OAuth 2.0 flow should I use, using refresh tokens is not an option. However, I am not sure I understand Implicit Grant flow with eventual Silent Authentication.
Does Implicit Flow mean only issuing normal access tokens? In that case, how do we allow user to stay logged in for long time? How should Silent Authentication endpoint look like, what should it receive and return to client? Is using refresh token really an issue - most of people have their usernames / passwords saved in browser?
Does Implicit Flow mean only issuing normal access tokens? Yes.
In that case, how do we allow user to stay logged in for long time? You can set timeout using "expires_in" parameter.
Refer for Complete Detail here: https://oauth2.thephpleague.com/authorization-server/implicit-grant/
How should Silent Authentication endpoint look like, what should it receive and return to client? Upon authentication of the user during login, the server sends & set the authentication key in the session/browser. So, during every page call, only authentication key is send to server. You shall find many examples of implementation online.
Is using refresh token really an issue - most of people have their usernames / passwords saved in browser? No, it's not an issue. If token expires, you can easily reissue token after authentication. Password & username is not saved in the browser. Only authentication key is stored.
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
I have a RESTful API written in ASP.Net that implements OAuth 2 for authentication, and it's currently accessed through a web application. I've also got a legacy desktop client that accesses the same resources directly (not through the RESTful API and without OAuth, but using the same login credentials and hitting the same database). The requirement I'm trying to meet right now is to allow a user to click a link in the desktop application in order to open the web app to a specific screen, and when they do, to have the web app authenticate automatically so that they don't have to manually log into it (since they've already logged into the desktop app).
I'm trying to work out how I can handle this within the constraints of the framework. I'm not too familiar with OAuth 2 in general, but from what I understand I shouldn't share tokens between clients and there are no flows specifically for this kind of hand-off (unless I'm missing something). Worst case scenario, I could generate a temporary token outside of OAuth that's used by the web client to authenticate rather than a username and password, but I'm hoping to avoid stepping outside of what's already in the framework to do what I need to do.
So the question is this: is there some decent way built into the OAuth 2.0 framework to handle this sort of "handshake" between two applications, or should I just build my own method of dealing with it?
Using temporary one-time tokens is actually part of OAuth spec (authorization_code grant type). In this case this short-lived code can be exchanged for access_token (and refresh_token). You will have to implemenent generating and validating of this authorization_code.
If you are using OWIN OAuth middleware:
You can generate the code at separate API endpoint accessed by your desktop client app.
After receiving token, pass it to your browser and direct it to auth endpoint with grant_type=authorization_code over secure connection. Example: call Process.Start("https://example.com/ExternalLogin/authorization_code_goes_here"). At the webpage redirect user to your OAuth Token endpoint with grant_type=authorization_code.
AuthenticationTokenProvider.Receive will be called, in which you will validate your token. (Example code here).
After successful validation OAuthAuthorizationServerProvider.GrantAuthorizationCode will be called, in which you will process the authenticated user in the same way you process it with grant_type=password.
Remember that your token validation logic should ensure that your tokens are short-lived, usable only once and transmitted over secure connection.
This is sometimes called "single sign-on" if you want to research this topic further.