Join us!
Want to join the team?

We would love to get to know you

Are you looking for an employer who cares about you as a person and where you feel involved in everything that concerns you? Welcome to JellyHive!
Who are we? We are a successful IT consultant company and our philosophy is that the company is our employees.
Who are you? You are a system developer (fullstack, frontend, backend), and/or maybe also a scrum master, test lead, devops etc.
What we offer you Participation in developing the company with generous benefits.

Upload your cv Supported filetypes are: .pdf, .doc and .docx

ASP.NET Core 2.0: Authenticating users via Harvest

At Advise we use Harvest for time tracking. On top of Harvest we have build a separate system that we use to keep track of statistics, vaccation periods and salary specifications. All information is fetched from Harvest. Login to the system is done using via Harvest.

We recently migrated this system to ASP.NET Core 2.0 and needed to update the type of authentication used the authentication process has been completely rewritten in ASP.NET Core 2.0.

To make it easier to use we put together a small library called Harvest Connect that helps with this integration. You can grab it from Nuget and the source code is available on Github. What follows is a how to guide on how to use Harvest Connect.

First of all you need to get a clientId and a clientSecret from Harvest. To do this visit the settings section of your Harvest site.

Once setup, grab the HarvestConnect package from Nuget:

dotnet add HarvestConnect

and modify your ConfigureServices method in your Startup.cs class. In the example we use cookies to keep login information for the user but you could just as well use JWT or some other type of storage.

public void ConfigureServices(IServiceCollection services) 
    services.AddAuthentication(options =>;
        options.DefaultAuthenticateScheme = HarvestOptions.Scheme;
        options.DefaultChallengeScheme = HarvestOptions.Scheme;
        options.DefaultSignInScheme = "auth";
        options.DefaultSignOutScheme = "auth";
    .AddCookie("auth", options =>;
        options.LogoutPath = "/logout";
    .AddHarvest(options =>
        options.ClientId = "<provided by Harvest>";
        options.ClientSecret = "<provided by harvest>";
        options.BaseUrl = "<base url of your site, e.g. http://localhost:13370>";
        options.Events = new HarvestEvents
            // Called on succesful login
            OnSuccessfulLogin = context =>;
                // Add the claims your app requires...
                context.Identity.AddClaim(new Claim(context.Identity.NameClaimType,

                if (context.WhoAmI.user.admin)
                    context.Identity.AddClaim(new Claim(context.Identity.RoleClaimType, "Administrator"));

                context.Identity.AddClaim(new Claim("Email",;

                // ... or do other stuff with the data received, e.g.:
                // await _db.UpdateAvatar(, context.WhoAmI.user.avatar_url);

                return Task.CompletedTask;
            // Called when login fails or the user denies the login attempt
            OnFailedLogin = async context =>
                await context.HttpContext.SignOutAsync();
                context.HttpContext.Response.Redirect("/home/logout?message=" + WebUtility.UrlEncode(context.FailureMessage));