I've got a mobile app that uses a native oauth flow via react-native-oauth (which makes use of an inAppBrowser) to complete the oath flow for ios. When it's complete, I have the tokens and idToken natively.
What I'd like to do now is to pass these to my backend web server, so that I can kick start some calendar sync process for this user. However, my backend is using MSAL.NET with a custom TokenCache, so expects the tokens to be present in this cache. To achieve this on the web app, there is an oauth flow baked into the web app that is hooked into this MSAL setup, and thus works:
// Hook the auth code up to the token cache, that will ensure it gets into the database (msal_token_cache)
TokenCache cache = new MsaldbTokenCache(userId, db).GetMsalCacheInstance();
ConfidentialClientApplication cca = new ConfidentialClientApplication(opts.ClientId,
settings.Core.BaseUrl.UrlCombine(redirectUrl),
new ClientCredential(opts.ClientSecret),
cache,
null);
AuthenticationResult result =
await cca.AcquireTokenByAuthorizationCodeAsync(code, new[] {"Calendars.ReadWrite"});
I've no idea how to do this with my ios-authed tokens. I can't allow the web server to acquire the tokens via auth code exchange since it was initiated in IOS...
Can anyone help?
I would design the solution to be architecturally separated so that it supports both web and mobile, which should work fine as long as both clients use the correct scopes for OAuth redirects:
A Rest API triggers the calendar sync process for the user received in the access token
One client of the Rest API is the back end of a web app - which uses MSAL.Net - and perhaps issues cookies to the browser
Another client of the Rest API is the mobile app - which uses React Native OAuth
I would avoid aiming to mix the 2 clients together though. If the web back end requires auth cookies then the mobile client will not be able to provide them.
The back end for the mobile app needs to a Rest API endpoint and it's possible that the existing back end may need to be refactored a little, to separate web client concerns from API concerns.
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 am using the ADAL3 for authenticating on the Azure AD app. Then I use the AuthenticatedClient Async for logging into the Azure backend.
What is the correct strategy for consuming Azure backend and working with token? Do you call AuthenticateClientAsync before each call to the backend to be sure that if the session expires on the backend the token will be used to start the session automatically? What append if the memory save token is expired, do you manually ask users to login again?
Someone has a sample of an app that popup a login page then call some service and popup a new login page if needed?
Thanks for your help.
According to your description, I assumed that Azure Mobile Apps would be the approach for you to work as your mobile backend. And you could authenticate your customers with AAD and leverage the client SDKs provided by Azure Mobile Apps to communicate with your azure mobile app backend.
I would recommend you follow this tutorial for creating your Azure Mobile App and download the sample project for getting started. Then, you could configure your mobile app to use AAD login, details you could follow here. Moreover, more details about how to use the client SDKs for Azure Mobile Apps in your xamarin project you could follow here.
Someone has a sample of an app that popup a login page then call some service and popup a new login page if needed?
After logged via MobileServiceClient.LoginAsync, you would retrieve a JWT token issued by your mobile app backend and you could get it by accessing MobileServiceClient.CurrentUser.MobileServiceAuthenticationToken. And you could cache the token for reusing it. You could wrap the operations against your mobile app backend and catch the exception when the token is expired and manually call LoginAsync to ask the user for logging again or validate the token in your client side and re-login if the token is invalid before you send requests to your mobile app backend. For caching the token and validate the token, you could follow adrian hall's book about Caching Tokens. For wrapping the table operations, you could follow here.
I have an API proxy that do the rest of my business login, identityserver for authorization and Android Client.
I using implicit flow with the android client.
I request an access token from idsrv then make a request including this token to contact with the api and every things works correctly.
Now i want an API or any way to register new user instead of the default web page so i can use this APIs to create new users from my proxy or from my android app.
What is the better way to do that?
This is, by design, out of the scope of IdentityServer. You can build your own API that can update the user database for user provisioning.
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.
I'm building a mobile application (that might also later become a web application). The server side is a ASP.NET MVC + Web API application and I'm thinking about ways how I could implement the service's user management and authentication.
How should I implement the registration/login screen in the app? Offer native app forms, that will send just API requests to the service or is it preferable to show a web browser component and display the website's login page and then extract a token after the user logs in? I see the first option is more user friendly, but the second one will let me change the login / registration page (like for example adding external authentication providers) without breaking older versions of the app.
My second question is regarding the external authentication providers. ASP.NET Identity has good support for them and it is quite possible to let users register using Facebook or some other OAuth2 provider. Does it make sense to add support for external authentication providers when I plan to expose the app's API publicly? Are there any reasons why that is not a good idea?
Your first option is best if you believe your users will trust you to manage their passwords. You make a secure call to your service, have the service produce a bearer token as the result. That would be an anonymous call. I used the answer from this question to get me going down that path:
Get IPrincipal from OAuth Bearer Token in OWIN
If your users are less likely to trust you with their credentials, then the web view and external provider is a good alternative. You would need to work with providers that support the "Implicit Grant Flow" since don't want to share the apps clientid and client secret on the mobile device. This approach involves using a web view to login in, and then capturing the token on the client uri fragment on the response. I think it is on a location header, but don't have a working example in front of me. Something like:
https://your.domain.com/#access_token = 8473987927394723943294
you would pass that token with each api call afterwards .
Good luck!