In general, rich client apps use OAuth flow to obtain authorization tokens to a web service. However, that flow may not be available from the authentication servers. In the following I am using an alternative approach: WS-Federation, well supported by ASP.NET web services. The solution consists of a web service, often used to provide REST services to rich client apps (Windows Store or .NET WPF, WinForms, etc.) and an authentication server (STS), e.g. Windows Azure Active Directory.
The basic approach is to:
- Establish WS-Federation trust between the STS
and the web service (e.g. http://msdn.microsoft.com/en-us/library/windowsazure/dn151790.aspx). - Host a web browser control in the rich client
application, use it to allow passive WS-Federation redirection between the web
service and the authentication service (STS). - Detect the final redirection from the
authentication server to the web service and verify that it includes
authentication token - Re-use authentication cookies returned by the
web service in any subsequent REST calls to the web service.
For the Windows Store 8.1 app I used the WebView control for the WS-Federation passive redirection exchange. Simplified code-behind used to detect completion of the authentication flow is shown below (errors and exception are ignored; the xaml page contains a WebView control called _login and a TextBlock called _result). The GetValues method shows a call to the web service.
string _webApp = protected override void { _login.Source = new } bool _isAuthenticated = private async void { if { if { await } } } async Task GetValues() { var client = new Microsoft.Web.Http.HttpClient(); // NOT System.Net.Http.HttpClient var values = await _result.Text = } |
Unlike any other .NET http client Microsoft.Web.Http.HttpClient shares its cookie store with other WinINet based code in your app, in this case with the browser control. Hence the GetValues method REST call will include the FedAuth cookies returned earlier during the authentication exchange through the WebView control.
In a .NET client (WPF or WinForms) http clients (HttpClient, WebClient, HttpWebRequest) do not share cookies with each other or other clients (browser controls) and therefore additional code needs to be provided to copy the cookies returned as part of the passive browser authentication to the http client making subsequent REST calls. Following code shows such an implementation in a WPF client:
public partial class MainWindow : Window { static extern bool static int static extern int
public MainWindow() { InitializeComponent(); } private void { if (args.Uri.ToString() { _login.Source = new } } Cookie GetCookie(string { UInt32 length = 2024; StringBuilder cookie = if { var error = throw new } var cookieValue = return new } string _webApp = CookieCollection async Task GetValues() { var handler = new handler.UseCookies = var client = new string values = try { values = await } catch (Exception ex) { } _result.Text = values; } private void { _progressBar.Visibility _login.Source = new }
private async void { _login.Visibility = await GetValues(); } } |
The xaml page for the WPF app looks as follows:
<Window x:Class="WpfTestClient.MainWindow" <Grid> <StackPanel <Button <Button </StackPanel> <Border <TextBlock </Border> <WebBrowser <ProgressBar </Grid> </Window> |
The approach, as outlined allows for the initial authentication flow. It should be expanded to include token renewal and logout support.
Image may be NSFW.
Clik here to view.