This is a repository for providing a secure based API to perform backoffice actions using JWT Auth tokens
They are an auth token that allows you to send a piece of JSON encoded as a token and are the more modern approach to deal with auth in applications especially as we build applications across different devices. The videos below will do a lot better trying to explain it than I can do.
I needed to create this POC for an upcoming pet project I am currently hacking & building. I needed a way to authenticate to any Umbraco backoffice using the same credentials as the Umbraco backoffice user & ensure they have access to specific section/s on that user. The user will only need to login once and we then store the auth token in local storage or cookies and use that token from storage or cookie for any future secured/protected API calls.
NG Europe talk from 0Auth.com guys
https://www.youtube.com/watch?v=lDb_GANDR8U&list=UUEGUP3TJJfMsEM_1y8iviSQ
Another good talk on JWT
https://www.youtube.com/watch?v=vIGZxeQUUFU#t=83
Debugger tool
http://jwt.io
Single Class File Library & Nuget Package I use for JWT dedcoding
Authored by FireBase, Twilio & others
http://www.nuget.org/packages/JWT/
https://github.com/johnsheehan/jwt/blob/master/JWT/JWT.cs
-
A user will do a HTTP post of their backoffice Umbraco username & password to a normal API Controller
-
Controller verifies credentials
-
If a token already exists for the user (matches against user id) in custom PetaPoco DB table
-
If no token exists create a new token for the user & store in the DB table
-
Return existing or newly created token in the response
-
A user can then store that token say in LocalStorage or Cookie
-
User calls secured API sends bearer auth token in HTTP header for request (From LocalStorage or cookie)
-
Server finds token in request
-
Tries to decode the token with secret
-
If token not encoded with same secret Send 401
-
If token can be decoded correctly find user id in JSON
-
Check if user has the same token stored in the DB
-
If so process method on API controller
-
User changes password in Umbraco backoffice
-
If no token exists in DB - nothing happens
-
If token exists in DB - generate new token with new datetime stamp to make it unique from last time
The payload of the JSON object in the JWT can be decoded easily, paste in a token into jwt.io and you can see it easily. However the part to do with JWT is that we verify that the AuthToken is using the signed secret/string to ensure our server created the JWT & it's validity.
So in my implementation I only store the username, user ID, user role and Created Date of the token. The date ensures that the token is different every time a new one is generated for easy revoking.
My implementation allows the tokens to work indefinitely until the user in the Umbraco backoffice changes their password. Which creates a new token and thus revoking access to the API for any clients or services using it.
However it is easily possible to store an expiry date in the JSON payload of the Auth Token and when decoding it verifying the expiry date on it.
Here are some simple instructions on how to use this to secure an API Controller in your Umbraco website with JWT Auth Tokens.
You will need to implement the following class UmbracoAuthTokenApiController
similar to how you would use UmbracoApiController
or UmbracoAuthorizedApiController
See the Umbraco Documentation for Umbraco API Controller Reference:
http://our.umbraco.org/documentation/Reference/WebApi/
http://our.umbraco.org/documentation/Reference/WebApi/authorization
Implementing the UmbracoAuthTokenApiController
in conjuction with the UmbracoAuthToken
attribute to decorate the API class allows us to access a new property in the Web API controller called AuthorisedBackofficeUser
which is the authorised Umbraco backoffice user from the JWT token, this can be used with the normal Umbraco Services APIs to Create Content and assign the correct user to the creation of that node.
In this project there is a built in Web API URL route for you to do a HTTP POST with the Username and Password. Your application to gain a JWT token must POST to this URL: http://yoursite.co.uk/umbraco/TokenAuth/SecureApi/Authorise
The following is a very simple secured Umbraco API controller, obviously your needs and uses will be much better than the very basic example shown here.
The UmbracoAuthToken
attribute has an optional parameter HasAccessToSections
which is an string array of Umbraco backoffice section aliases that the attempted backoffice Umbraco user should have access to.
For example this checks the following user has access to the content
and the settings
sections, if they do not have access to both sections then the WebAPI will return 401 Unauthorised HTTP Error Code.
[UmbracoAuthToken("content", "settings")]
using System;
using System.Web.Http;
using Umbraco.Core.Models;
using Umbraco.Web.Mvc;
using UmbracoAuthTokens.Attributes;
using UmbracoAuthTokens.Controllers;
namespace UmbracoAuthTokens.TestApi
{
[PluginController("Secured")]
[UmbracoAuthToken("content", "settings")]
public class ContentApiController : UmbracoAuthTokenApiController
{
/// <summary>
/// A simple GET that shows the backoffice user's name & email address from the JWT Auth Token
/// </summary>
/// <returns></returns>
[HttpGet]
public string SecurePing()
{
return string.Format("Secure Pong from {0} {1}", AuthorisedBackofficeUser.Name, AuthorisedBackofficeUser.Email);
}
/// <summary>
/// Note this is NOT a great example. As you would POST data to create a node.
/// As opposed to a GET with this hardcoded values
/// </summary>
/// <returns></returns>
[HttpGet]
public IContent CreateNewRootNode()
{
var newNodeName = string.Format("New Node {0}", DateTime.Now.ToShortDateString());
var parentNodeId = -1;
var contentTypeAlias = "Home";
return Services.ContentService.CreateContentWithIdentity(newNodeName, parentNodeId, contentTypeAlias, AuthorisedBackofficeUser.Id);
}
}
}
- 1.0.0.0 - Initial Release
- 1.1.0.0 - Update to DB schema and adds abbility to use JWT's with members as well now