DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Related

  • What D'Hack Is DPoP?
  • Configuring Anypoint Platform as an Azure AD Service Provider SSO
  • Configuring SSO Using WSO2 Identity Server
  • Introduction to Building Desktop Applications With Electron

Trending

  • How To Build Resilient Microservices Using Circuit Breakers and Retries: A Developer’s Guide To Surviving
  • Vibe Coding With GitHub Copilot: Optimizing API Performance in Fintech Microservices
  • Developers Beware: Slopsquatting and Vibe Coding Can Increase Risk of AI-Powered Attacks
  • Enforcing Architecture With ArchUnit in Java
  1. DZone
  2. Software Design and Architecture
  3. Integration
  4. Adding Authentication to a Native Desktop C# App With JWTs

Adding Authentication to a Native Desktop C# App With JWTs

In this tutorial, you'll build a native desktop C# app and get up and running with JWT authentication.

By 
Prosper Otemuyiwa user avatar
Prosper Otemuyiwa
·
Jun. 06, 16 · Tutorial
Likes (3)
Comment
Save
Tweet
Share
20.5K Views

Join the DZone community and get the full member experience.

Join For Free

There are different frameworks for building native desktop C# apps. We have WPF (Windows Presentation Foundation) and Universal Windows. Universal Windows apps enable you to target every Windows device in one solution. You develop once, share most of your code, and deploy on Windows, Windows Phone, or Xbox. It reduces the effort needed in building and maintaining an app for each type of device.

The limitation of Universal Windows right now is that it only works from Windows 8 and above. Meanwhile, WPF has been around for a very long time. It was introduced with .NET Framework 3.0. It uses Direct3D rendering, which employs graphics cards to render the output on the screen. Thus, the drawing in the form will be smooth and there is also a chance to utilize the hardware capabilities installed in your machine. WPF controls are actually drawn over the screen, hence you can totally customize controls and modify their behavior when required.

We'll be building the desktop app with WPF (Windows Presentation Foundation) using Visual Studio 2015 and .NET Framework 4.6.1.

Let's Get Started

  1. Open your Visual Studio. You can download it from here.
  2. Create a new project and choose "WPF Application" as the project type.
  3. Under Templates at the left-hand side, select Visual C#, and in the middle panel, select WPF Application.
  4. Choose a folder for your project and give it a name. Then press "OK." Two files are created by default. One is the XAML file (MainWindow.xaml) and the other one is the CS file (MainWindow.xaml.cs).

In a WPF application, there are two ways to design a UI for your application. One is to simply drag and drop UI elements from the toolbox to the design window. The second way is to design your UI by writing XAML tags for UI elements. Visual Studio handles XAML tags when the drag and drop feature is used for UI designing.

Setting Up the UI

MainWindow.xaml.cs

<Window x:Class="WpfClient.MainWindow"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
      xmlns:local="clr-namespace:WpfClient"
      mc:Ignorable="d"
      Title="WPF Client" Height="350" Width="525">
  <Frame x:Name="frame" Content="Frame" Margin="0" Source="/WpfClient;component/Pages/LoginPage.xaml" NavigationUIVisibility="Hidden"/>
</Window>

Take a good look at the Frame control and the Source attribute. I have linked the source attribute to another page. So, go ahead and create a directory called Pages. Right click on the folder. Click the add menu item and select page. Call it LoginPage. Now, this means when you run our application, the main window will load the content of the LoginPage.

Open up the LoginPage.xaml file and configure it like so:

<Page x:Class="WpfClient.Pages.LoginPage"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
      xmlns:local="clr-namespace:WpfClient.Pages"
      mc:Ignorable="d"
      d:DesignHeight="485" d:DesignWidth="715"
      Title="Login">

    <Grid>
        <StackPanel HorizontalAlignment="Center" Margin="0" VerticalAlignment="Center" Width="300">
            <TextBlock Text="Welcome to Auth0" HorizontalAlignment="Center" FontSize="36" />
            <TextBlock Text="Username:" Margin="0,5,0,0" />
            <TextBox x:Name="tbxUsername" Padding="5" />
            <TextBlock Text="Password:" Margin="0,5,0,0" />
            <PasswordBox x:Name="pbxPassword" Padding="5" />
            <Button x:Name="btnLogin" Content="LOGIN" Padding="5" Margin="0,5,0,0" Click="btnLogin_Click" />
            <Button x:Name="btnRegister" Content="REGISTER" Padding="5" Margin="0,5,0,0" Click="btnRegister_Click" />
        </StackPanel>
    </Grid>
</Page>

Here, we have two TextBlocks, one TextBox, one PasswordBox, and two Buttons for Login and Register simultaneously.

Go ahead and create the RegisterPage just like we created the LoginPage.

Open up the RegisterPage.xaml and configure it like so:

<Page x:Class="WpfClient.Pages.RegistrationPage"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
      xmlns:local="clr-namespace:WpfClient.Pages"
      mc:Ignorable="d"
      d:DesignHeight="300" d:DesignWidth="300"
      Title="RegistrationPage">

    <Grid>
        <StackPanel HorizontalAlignment="Center" Margin="0" VerticalAlignment="Center" Width="300">
            <TextBlock Text="Create Account" HorizontalAlignment="Center" FontSize="36" />
            <TextBlock Text="Username:" Margin="0,5,0,0" />
            <TextBox x:Name="tbxUsername" Padding="5" />
            <TextBlock Text="Password:" Margin="0,5,0,0" />
            <PasswordBox x:Name="pbxPassword" Padding="5" />
            <TextBlock Text="Firstname:" Margin="0,5,0,0" />
            <TextBox x:Name="tbxFirstname" Padding="5" />
            <TextBlock Text="Middlename:" Margin="0,5,0,0" />
            <TextBox x:Name="tbxMiddlename" Padding="5" />
            <TextBlock Text="Lastname:" Margin="0,5,0,0" />
            <TextBox x:Name="tbxLastname" Padding="5" />
            <TextBlock Text="Age:" Margin="0,5,0,0" />
            <TextBox x:Name="tbxAge" Padding="5" />
            <Button x:Name="btnReg" Content="REGISTER" Padding="5" Margin="0,5,0,0" Click="btnReg_Click" />
            <Button x:Name="btnBack" Content="BACK" Padding="5" Margin="0,5,0,0" Click="btnBack_Click" />
        </StackPanel>
    </Grid>
</Page>

We have the UI set up. Great! Let's add functionality to these forms and buttons.

Setting Up the Back End

We are using our efficient Csharp-jwt-authentication-sample functional C# Web API backend. Check out the README on how to run it. It can exist in the same top level project directory our desktop app resides, but it'll be run as a web app.

Setting Up the Data Model

You might be aware of the MVC/MVVM concept that is popular amongst frameworks. We'll use MVC in our app to allow for clean logic and easy separation of concerns. Here, we need to set up a data model for this app. The model only holds the in-memory state in a structured format. Create the Models directory and add a User model to the directory.

User.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WpfClient.Models
{
    class User
    {
        public int Id { get; set; }
        public string Username { get; set; }
        public string Firstname { get; set; }
        public string Middlename { get; set; }
        public string Lastname { get; set; }
        public int Age { get; set; }
        public string access_token { get; set; }
    }
}

We have the User model with the necessary attributes we need for this app. That's the only model we need.

Setting Up the Operation class

Create an Operations directory and add a new class called ApiOperations. Add the contents below to the class.

ApiOperations.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

using WpfClient.Models;
using Newtonsoft.Json;

namespace WpfClient.Operations
{
    class ApiOperations
    {
        /**
         * Base Url @string
         */
        private string baseUrl;

        public ApiOperations()
        {
            this.baseUrl = "http://localhost:5000/api";
        }
    }
}

In the constructor, we have added the baseUrl where our web API actually runs.

The Newtonsoft.Json is there as a result of a module you'll have to install now.

Go to packages.confi and add the package name like so and install:

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="Newtonsoft.Json" version="8.0.3" targetFramework="net461" />
</packages>

If the package is not found, it will be downloaded the first time the app is run. Check here for more information on theNewtonsoft.Json nugget.

Let's add the first method to the ApiOperations class. Add this method below:

/**
 * Authenticate user with Web Api Endpoint
 * @param string username
 * @param string password
 */
public User AuthenticateUser(string username, string password)
{
    string endpoint = this.baseUrl + "/users/login";
    string method = "POST";
    string json = JsonConvert.SerializeObject(new
    {
        username = username,
        password = password
    });

    WebClient wc = new WebClient();
    wc.Headers["Content-Type"] = "application/json";
    try
    {
        string response = wc.UploadString(endpoint, method, json);
        return JsonConvert.DeserializeObject<User>(response);
    }
    catch (Exception)
    {
        return null;
    }
}

In this AuthenticateUser method, we are taking in the username andpassword arguments.

JsonConvert.SerializeObject converts the username and password to a valid JSON. WebClient is an available class that allows for making web requests easily in .NET. We are using its UploadString method in the try and catch to authenticate a user. If the user exists, it returns details about the user, or else it returns null.

Let's add another method to the ApiOperations class. Add this method below:

/**
 * Get User Details from Web Api
 * @param  User Model
 */
public User GetUserDetails(User user)
{
    string endpoint = this.baseUrl + "/users/" + user.Id;
    string access_token = user.access_token;

    WebClient wc = new WebClient();
    wc.Headers["Content-Type"] = "application/json";
    wc.Headers["Authorization"] = access_token;
    try
    {
        string response = wc.DownloadString(endpoint);
        user = JsonConvert.DeserializeObject<User>(response);
        user.access_token = access_token;
        return user;
    }
    catch (Exception)
    {
        return null;
    }
}

This method fetches the user details from the API based on the user id. It takes in the User Model as an argument, then makes a get request using the WebClient DownloadString method.

wc.Headers["Authorization"] = access_token sends the access JSON Web Token as the form of authentication. Without this token, we can't retrieve the user details from the WEB API. Every other protected resource will be accessed this way.

The Authorization header which contains the key is very important.

JWT also provides the ability to do fine-grained access control. You can check here for more information on that.

Let's add yet another method to the ApiOperations class. Add this method below:


/**
 * Register User
 * @param  string username
 * @param  string password
 * @param  string firstname
 * @param  string lastname
 * @param  string middlename
 * @param  int    age
 */
public User RegisterUser(string username, string password, string firstname,
    string lastname, string middlename, int age)
{
    string endpoint = this.baseUrl + "/users";
    string method = "POST";
    string json = JsonConvert.SerializeObject(new
    {
        username = username,
        password = password,
        firstname = firstname,
        lastname = lastname,
        middlename = middlename,
        age = age
    });

    WebClient wc = new WebClient();
    wc.Headers["Content-Type"] = "application/json";
    try
    {
        string response = wc.UploadString(endpoint, method, json);
        return JsonConvert.DeserializeObject<User>(response);
    }
    catch (Exception)
    {
        return null;
    }
}

The RegisterUser method takes in all the user details, converts them into a valid JSON with the help of JsonConvert and does a POST request with help from the WebClient.UploadString.

Note: The Content-Type has been set to application/json.

With all of that done and out of the way, we'll soon see how everything works together. Let's connect the GUI (WPF) to the Model and ApiOperations class.

Setting Up the Registration Form

Open up the RegistrationPage.xaml.cs file. We'll add functionality to the register and back buttons.

RegistrationPage.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

using WpfClient.Models;
using WpfClient.Operations;

namespace WpfClient.Pages
{
    /// <summary>
    /// Interaction logic for RegistrationPage.xaml
    /// </summary>
    public partial class RegistrationPage : Page
    {
        public RegistrationPage()
        {
            InitializeComponent();
        }

        /**
         * Register method to handle the Register Button
         * @param object sender
         * @param RoutedEventArgs e
         */
        private void btnReg_Click(object sender, RoutedEventArgs e)
        {
            string username = tbxUsername.Text;
            string password = pbxPassword.Password;
            string firstname = tbxFirstname.Text;
            string lastname = tbxLastname.Text;
            string middlename = tbxMiddlename.Text;
            int age = int.Parse(tbxAge.Text);

            ApiOperations ops = new ApiOperations();
            User user = ops.RegisterUser(username, password, firstname, lastname, middlename, age);
            if (user == null)
            {
                MessageBox.Show("Username already exists");
                return;
            }

            Globals.LoggedInUser = user;
            MessageBox.Show("Registration successful");
            NavigationService.Navigate(new DetailsPage());
        }

        /**
         * Method to handle going back to the previous screen
         * @param object  sender
         * @param RoutedEventArgs e
         */
        private void btnBack_Click(object sender, RoutedEventArgs e)
        {
            NavigationService.GoBack();
        }
    }
}

In the btnReg_Click method, we are obtaining the user's information from the form via the name attributes.

Remember, tbxUsername, pbxPassword,tbxFirstname, tbxLastname, tbxMiddlename and tbxAge are name attributes we gave the form during the UI setup.

Then we called the RegisterUser method from the ApiOperations class we defined earlier. If the user already exists, it gives an error message, otherwise, it registers the user and navigates to a new page to show the User details. NavigationService does the navigation.

In the btnBack_Click method, the GoBack method of the NavigationService takes the user back to the previous screen.

screen shot 2016-05-22 at 7 22 40 pm

screen shot 2016-05-22 at 7 23 24 pm

Setting Up the Login Form

Open up the LoginPage.xaml.cs file. We'll add functionality to the login buttons.

LoginPage.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

using WpfClient.Models;
using WpfClient.Operations;

namespace WpfClient.Pages
{
    /// <summary>
    /// Interaction logic for LoginPage.xaml
    /// </summary>
    public partial class LoginPage : Page
    {
        public LoginPage()
        {
            InitializeComponent();
        }

        /**
         * Login Method to handle Login Button
         * @param  object sender
         * @param  RoutedEventArgs e
         */
        private void btnLogin_Click(object sender, RoutedEventArgs e)
        {
            string username = tbxUsername.Text;
            string password = pbxPassword.Password;

            ApiOperations ops = new ApiOperations();
            User user = ops.AuthenticateUser(username, password);
            if (user == null)
            {
                MessageBox.Show("Invalid username or password");
                return;
            }

            Globals.LoggedInUser = user;
            MessageBox.Show("Login successful");
            NavigationService.Navigate(new DetailsPage());
        }

        /**
         * Method to direct user to Register Page
         * @param object sender
         * @param RoutedEventArgs e
         */
        private void btnRegister_Click(object sender, RoutedEventArgs e)
        {
            NavigationService.Navigate(new RegistrationPage());
        }
    }
}

In the btnLogin_Click method, we are obtaining the user's information from the form via the name attributes. Remember tbxUsername, pbxPassword are name attributes we gave the form during the UI setup. Then we call theAuthenticateUser method from the ApiOperations class we defined earlier.

If the user doesn't exist, it gives an appropriate Invalid Username or Passwordmessage, else logs the user in and navigates to a new page to show the User details. NavigationService does the navigation.

You must be wondering what Globals.LoggedInUser = user; is doing there in both the Login and Register Classes. I'll explain in a bit.

Setting Up Globals Model

The Globals Model provides the ability to easily store and retrieve the details of a logged-in user in a structured way.

Create a new Model called Globals and add this:

Globals.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using WpfClient.Models;

namespace WpfClient
{
    class Globals
    {
        public static User LoggedInUser { get; set; }
    }
}

screen shot 2016-05-22 at 7 21 42 pm

screen shot 2016-05-22 at 7 22 27 pm

screen shot 2016-05-22 at 7 25 39 pm

Setting Up the Details Page

Create a new Page called DetailsPage like you did with the Register page.

The DetailsPage.xaml should look like so with eight Textblocks and Grid Rows & Columns:

<Page x:Name="detailsPage" x:Class="WpfClient.Pages.DetailsPage"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
      xmlns:local="clr-namespace:WpfClient.Pages"
      mc:Ignorable="d"
      d:DesignHeight="455" d:DesignWidth="640"
      Title="DetailsPage" Loaded="detailsPage_Loaded">

    <Grid>
        <StackPanel Margin="0" VerticalAlignment="Center">
            <TextBlock x:Name="tbkWelcome" Text="Welcome" HorizontalAlignment="Center" FontSize="36" />
            <Grid HorizontalAlignment="Center" Width="200">
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="Auto" />
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="100" />
                    <ColumnDefinition Width="Auto" />
                </Grid.ColumnDefinitions>

                <TextBlock Text="Firstname:" Grid.Row="0" Grid.Column="0" />
                <TextBlock Text="Middlename:" Grid.Row="1" Grid.Column="0" />
                <TextBlock Text="Lastname:" Grid.Row="2" Grid.Column="0" />
                <TextBlock Text="Age:" Grid.Row="3" Grid.Column="0" />

                <TextBlock x:Name="tbkFname" Text="Firstname" Grid.Row="0" Grid.Column="1" />
                <TextBlock x:Name="tbkMname" Text="Middlename" Grid.Row="1" Grid.Column="1" />
                <TextBlock x:Name="tbkLname" Text="Lastname" Grid.Row="2" Grid.Column="1" />
                <TextBlock x:Name="tbkAge" Text="Age" Grid.Row="3" Grid.Column="1" />
            </Grid>
            <Button x:Name="btnLogout" Content="Logout" Width="100" Click="btnLogout_Click" Margin="0,10,0,0" />
        </StackPanel>
    </Grid>
</Page>

Now, Open up the DetailsPage.xaml.cs. It should have the following methods like so:

DetailsPage.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

using WpfClient.Models;
using WpfClient.Operations;

namespace WpfClient.Pages
{
    /// <summary>
    /// Interaction logic for DetailsPage.xaml
    /// </summary>
    public partial class DetailsPage : Page
    {
        public DetailsPage()
        {
            InitializeComponent();
        }

        /**
         * Details Page Loaded
         * @param  object  sender
         * @param  RoutedEventArgs e
         */
        private void detailsPage_Loaded(object sender, RoutedEventArgs e)
        {
            FetchUserDetails();
            ShowUserInfo();
        }

        /**
         * Fetch User Details
         */
        private void FetchUserDetails()
        {
            ApiOperations ops = new ApiOperations();
            User user = ops.GetUserDetails(Globals.LoggedInUser);
            if (user == null)
            {
                MessageBox.Show("Session expired");
                // Navigate back to login page
                NavigationService.Navigate(new LoginPage());
            }

            Globals.LoggedInUser = user;
        }

        /**
         * Show User Info on the Screen
         */
        private void ShowUserInfo()
        {
            tbkWelcome.Text += " " + Globals.LoggedInUser.Username;
            tbkFname.Text = Globals.LoggedInUser.Firstname;
            tbkMname.Text = Globals.LoggedInUser.Middlename;
            tbkLname.Text = Globals.LoggedInUser.Lastname;
            tbkAge.Text = Globals.LoggedInUser.Age.ToString();
        }

        /**
         * Logout Method to be called on the logout Button
         * @param  object sender
         * @param  RoutedEventArgs e
         */
        private void btnLogout_Click(object sender, RoutedEventArgs e)
        {
            Globals.LoggedInUser = null;
            NavigationService.Navigate(new LoginPage());
        }
    }
}

The detailsPage_Loaded method is called once the Page loads up.

The FetchUserDetails method passes the LoggedInUser model to theGetUserDetails method of the ApiOperations class. If it returns null, it means the token has expired else the user info is stored in memory. The token has an expiration date of one day.

The ShowUserInfo method simply assigns the details to the text field onDetails Page.

The btnLogout_Click method clears the LoggedInUser Global Model of any data and navigates the user to the login page.

screen shot 2016-05-22 at 7 23 37 pm

Aside: Using Auth0 with WPF

Auth0 issues JSON Web Tokens on every login for your users. This means that you can have a solid identity infrastructure, including single sign-on, user management, support for social identity providers (Facebook, Github, Twitter, etc.), enterprise identity providers (Active Directory, LDAP, SAML, etc.), and your own database of users with just a few lines of code.

We can easily set up authentication in our native desktop C# apps by using the Lock Widget.

Auth0 Lock Widget

Step 1: Include Auth0's Lock Widget

Use NuGet to install the library like so:

  Install-Package Auth0.WinformsOrWPF

Step 2: Instantiate Auth0Client and Use Lock Widget in Login.xaml.cs


...

// Import the Auth0 library
using Auth0.WinFormsOrWPF;

namespace WpfClient.Pages
{
    /// <summary>
    /// Interaction logic for LoginPage.xaml
    /// </summary>
    public partial class LoginPage : Page
    {
        public LoginPage()
        {
            InitializeComponent();
        }

        /**
         * Login Method to handle Login Button
         * @param  object sender
         * @param  RoutedEventArgs e
         */
        private void btnLogin_Click(object sender, RoutedEventArgs e)
        {
           // Instantiate Auth0Client
           var auth0 = new Auth0Client("{YOUR_AUTH0_DOMAIN}","{YOUR_CLIENT_ID}");

           // Trigger Login with Lock Widget and save the user's JWT on a successful login
           auth0.LoginAsync(this).ContinueWith(t =>
           {
             Globals.LoggedInUser = t.Result.Profile
           },
           TaskScheduler.FromCurrentSynchronizationContext());

           MessageBox.Show("Login successful");
           NavigationService.Navigate(new DetailsPage());

        }
    }
}

Did you expect it to be difficult? Sorry to disappoint you! Auth0 Lock Widget is dead simple to use.

Wrapping Up

Visual Studio is a complete IDE. We have witnessed how easy it was to create pages in our desktop app and just add code behind the controls to make it work. C# is a great language to work. If you are coming from a Java background, then you'll sure have the fun time of your life working with it.

As we saw in this tutorial, we can easily add authentication to our desktop apps using JWTs. Also, the inbuilt WebClient class makes it trivial to send requests with an Authorization header.

Related Refcard:

C# Development

app Desktop (word processor) authentication csharp JWT (JSON Web Token) Web API Form (document) application Windows Presentation Foundation Attribute (computing)

Published at DZone with permission of Prosper Otemuyiwa, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • What D'Hack Is DPoP?
  • Configuring Anypoint Platform as an Azure AD Service Provider SSO
  • Configuring SSO Using WSO2 Identity Server
  • Introduction to Building Desktop Applications With Electron

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!