VB.Net WebApi OAuth Token Based Authentication + Angular Login Application - Part 1

Although I have focused my studies on Asp.Net/C# over the last three years, I have been working on a WebAPI project running VB.Net on backend and I would like to share with you, VB.Net developers, a token-based authentication solution using this verbose, effective and popular language.

What we’ll build?
In this series of articles, the backend will be built using WebAPI on top of OWIN and AngularJS as a client web application. Both projects, Backend and Frontend, will be available on my Github.
Source Code - Github

Go for it!

Backend implementation
The project structure is based on DDD. Some design patterns will not be implemented because they are not part of the focus of this article. A different approach implementing IoC, Dependency Injection and others patterns will be addressed in an upcoming post.

Before we start, take a look at what we will have done after the first step:
project structure

Step One - Structure project
1 - Create a Blank Solution on Visual Studio 2015
2 - Add new solution folders: "1-API", "2-Application Service", "3-Domain" and "4-Insfrastructure"
3 - Under the Application Service folder, create a Visual Basic Class Library project.
Creating class library
4 - Create library projects under "3-Domain" and "4-Insfrastructure" folders too.

WebAPI project
5 - Under the folder API, create a New Project
6 - In the Templates pane, select Installed Templates and expand the Visual Basic node. Under Visual Basic, select Web. In the list of project templates, select ASP.NET Web Application. Name the project "VBNetWebAPI.API" and click OK.
Creating WebAPI Project
7 - In the New ASP.NET Project dialog, select the Empty template. Under "Add folders and core references for", just check "Web API" and click OK.
Creating WebAPI Project

8 - Once the API project is crated delete Global.asax file and the class WebApiConfig.vb, that was created automatically under the folder App_Start.

Step Two - Installing and configuring OWIN
9 - In the Package Manager Console window, select VBNetWebAPI.API project as Default Project and run the following commands:
Creating class library
install-package Microsoft.Aspnet.Webapi.Owin
install-package Microsoft.Owin.host.systemweb
install-package microsoft.owin.security.oauth
install-package microsoft.owin.cors

Once the project's structure is created and all packages above are installed, let's add the OWIN startup class. The Startup class is the entry point into a OWIN-based application. It’s like Global.asax in a ASP.NET app. The Startup class must contain a method called Configuration.

10 - Add a class called Startup.vb to the root of API project

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
Public Class Startup
    Dim authenticateUser As New UserAppService()
    Public Sub Configuration(app As IAppBuilder)
        Dim config As New HttpConfiguration()
 
        With config
            .MapHttpAttributeRoutes()
            .Routes.MapHttpRoute(
                name:="DefaultApi",
                routeTemplate:="api/{controller}/{id}",
                defaults:=New With {.id = RouteParameter.Optional}
            )
        End With
 
        Dim formatters = config.Formatters
        formatters.Remove(formatters.XmlFormatter)
 
        ConfigureOAuth(app, authenticateUser)
        app.UseCors(Cors.CorsOptions.AllowAll)
        app.UseWebApi(config)
    End Sub
 
    Public Sub ConfigureOAuth(app As IAppBuilder, authenticateUser As UserAppService)
 
        Dim OAuthServerOptions As New OAuthAuthorizationServerOptions()
        With OAuthServerOptions
            .AllowInsecureHttp = True
            .TokenEndpointPath = New PathString("/api/security/token")
            .AccessTokenExpireTimeSpan = TimeSpan.FromDays(3)
            .Provider = New MyAuthorizationServerProvider(authenticateUser)
        End With
 
        app.UseOAuthAuthorizationServer(OAuthServerOptions)
        app.UseOAuthBearerAuthentication(New OAuthBearerAuthenticationOptions())
 
    End Sub
End Class

Lines 15 and 16: Removing XML and setting JSON as default format - this is optional
Line 27: enable or disable https
Line 28: setting the endpoint for client token request
Line 29: Token lifetime
Line 30: Instance of a class that inherits OAuthAuthorizationServerProvider and will be responsible for validate an username and password.

The Startup class has references to MyAuthorizationServerProvider and AuthenticationService classes. Let's create and implement both classes.

11 - Under the VBNetWebAPI.API project, creade a folder called "Security". Then create the class MyAuthorizationServerProvider.vb under it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
Public Class MyAuthorizationServerProvider
    Inherits OAuthAuthorizationServerProvider
 
    Private _userService As New UserAppService()
 
    Public Sub New(userService As UserAppService)
        Me._userService = userService
    End Sub
 
    Public Overrides Async Function ValidateClientAuthentication(context As OAuthValidateClientAuthenticationContext) As Task
        context.Validated()
        Await Task.FromResult(Of Object)(Nothing)
    End Function
 
    Public Overrides Async Function GrantResourceOwnerCredentials(context As OAuthGrantResourceOwnerCredentialsContext) As Task
        context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", New String() {"*"})
 
        Dim userLogin = _userService.Authenticate(context.UserName, context.Password)
        If userLogin Is Nothing Then
            context.SetError("invalid_user", "Invalid password or username")
            Exit Function
        End If
 
        Dim identity = New ClaimsIdentity(context.Options.AuthenticationType)
 
        context.Validated(identity)
        Await Task.FromResult(Of Object)(Nothing)
    End Function
 
End Class

12 - Create a class called UserAppService.vb under ApplicationService project. The purpose of an application service is to expose the functionality of the domain to API layer. In this case, the class MyAuthorizationServerProvider that we've created, just need to know the method exposed by application service class.

1
2
3
4
5
6
7
8
Public Class UserAppService
    Private _userRepository As New UserRepository()
 
    Public Function Authenticate(username As String, password As String) As User
        password = StringHelper.EncryptPassword(password)
        Return _userRepository.Authenticate(username, password)
    End Function
End Class

13 - Create a repository class under Infrastructure project

1
2
3
4
5
6
7
8
Imports Dapper
Public Class UserRepository
    Public Function Authenticate(username As String, password As String) As User
        Dim cmd = DBConnection.GetConnection()
        Dim sql = "SELECT name, email FROM Users where username = @usr and password = @pwd"
        Return cmd.QueryFirstOrDefault(Of User)(sql, New With {.usr = username, .pwd = password})
    End Function
End Class

Line 1 - I have used Dapper for data persistence, wich is a powerfull micro ORM. To install it, just run the command: Install-Package Dapper in the Package Manager Console on Infrastructure project.

Step Three - Running API and getting a token
I am using Postman to make request to API. The image below show how to make a request and get a token.
Creating class library

As configured in Startup class, a request to get a token will be received at “api/security/token" endpoint. As you can see at the image, all we need to send are three keys: grant_type, username and password. If all is done correct, a token will be returned from the API.

In the next article, we will see how to handle the token using sessionStorage on client-side builting a login application using AngularJS.

Thanks for reading!

3 thoughts on “VB.Net WebApi OAuth Token Based Authentication + Angular Login Application - Part 1

  1. Very well
    However, you forgot the tag above the GetTest method
    Thank you

  2. I got this error the compile the project:

    "error": "unsupported_grant_type"

Leave a Reply

Your email address will not be published. Required fields are marked *

This blog is kept spam free by WP-SpamFree.