An Umbraco plugin to add an OAuth API endpoint to allow authenticated Members/Users via OAuth
AuthU is an add-on library to Umbraco providing a simplified OAuth2 endpoint from which you can authenticate Umbraco Members/Users and use it to protect your API controllers. Ideal for developing web/mobile apps.
PM> Install-Package Our.Umbraco.AuthU
In order to configure AuthU you will first of all need to create an Umbraco composer + compontent combination like so:
public class AuthUConfigComponent : IComponent
{
public void Initialize()
{
// Configuration goes here
}
public void Terminate() { }
}
public class AuthUConfigComposer : ComponentComposer<AuthUConfigComponent>
{ }
From within the Initialize
method, you can then configure your endpoint(s) via the OAuth.ConfigureEndpoint
helper like so:
...
OAuth.ConfigureEndpoint(...);
...
For the most basic OAuth implementation, the following minimal configuration is all that is needed:
OAuth.ConfigureEndpoint("/oauth/token", new OAuthOptions {
UserService = new UmbracoMembersOAuthUserService(),
SymmetricKey = "856FECBA3B06519C8DDDBC80BB080553",
AccessTokenLifeTime = 20, // Minutes
AllowInsecureHttp = true // During development only
});
This will create an endpoint at the path /oauth/token
, authenticating requests against the Umbraco members store, issuing access tokens with a lifespan of 20 minutes.
For a more advanced OAuth implementation, the following configuration shows all the supported options.
OAuth.ConfigureEndpoint("realm", "/oauth/token", new OAuthOptions {
UserService = new UmbracoMembersOAuthUserService(),
SymmetricKey = "856FECBA3B06519C8DDDBC80BB080553",
AccessTokenLifeTime = 20, // Minutes
ClientStore = new UmbracoDbOAuthClientStore(),
RefreshTokenStore = new UmbracoDbOAuthRefreshTokenStore(),
RefreshTokenLifeTime = 1440, // Minutes (1 day)
AllowedOrigin = "*",
AllowInsecureHttp = true // During development only
});
This will create an endpoint the same as the basic configuration with added support of refresh tokens and a client store.
umbracoReservedPaths
app setting, ie ~/oauth/
)UmbracoMembersOAuthUserService
and UmbracoUsersOAuthUserService
which authenticate against the Umbraco members and users store respectively. Custom sources can be configured by implementing the IOAuthUserService
interface yourself.InMemoryOAuthClientStore
which stores a fixed list of client credentials in memory and UmbracoDbOAuthClientStore
which stores the client credentials in a custom database table in the Umbraco database (AuthU does not provide an api for creating clients, so you'll need to configure these manually in the database, or write your own CRUD layer). Alternative implementations can be configured by implementing the IOAuthClientStore
interface.refresh_token
parameter which can be used to re-authenticate a user without needing to use their username / password credentials, allowing you to extend the lifespan of an access token. If null, refresh tokens will not be issued. Out of the box, AuthU comes with 1 implementation, UmbracoDbOAuthRefreshTokenStore
, which stores the refresh tokens in a custom database table in the Umbraco database. Alternative implementations can be configured by implementing the IOAuthRefreshTokenStore
interface.null
.true
during development, but it is strongly advised to disable this in the live environment.With an endpoint configured, initial authentication can be performed by sending an POST request to the endpoints url with a body of content type application/x-www-form-urlencoded
, containing the following key values:
Example (with client store and refresh token stores configured):
Request URL:
POST https://mydomain.com/oauth/token
Request Headers:
Content-Type: application/x-www-form-urlencoded
Request POST Body:
grant_type=password&username=joebloggs&password=password1234&client_id=myclient&client_secret=myclientsecret&device_id=edfb6f01-2342-47f8-a5ee-a520969539d0
Response:
{
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYW1laWQiOiIxMDgxIiwidW5pcXVlX25hbWUiOiJtZW1iZXIiLCJyb2xlIjoiTWVtYmVyIiwicmVhbG0iOiJkZWZhdWx0IiwiZXhwIjoxNDg3NDk2NzM3LCJuYmYiOjE0ODc0OTU1Mzd9.9uiIxrPggvH5nyLbH4UKIL52V6l5mpOyJ26J12FkXvI",
"token_type": "bearer",
"expires_in": 1200,
"refresh_token": "b3cc9c66b86340c5b743f2a7cec9d2f1"
}
A subsequent refresh token authentication request can be performed by sending a POST request to the endpoints url with a body of content type application/x-www-form-urlencoded
, containing the following key values:
Example (with client store and refresh token stores configured):
Request URL:
POST https://mydomain.com/oauth/token
Request Headers:
Content-Type: application/x-www-form-urlencoded
Request POST Body:
grant_type=refresh_token&refresh_token=b3cc9c66b86340c5b743f2a7cec9d2f1&client_id=myclient&client_secret=myclientsecret&device_id=edfb6f01-2342-47f8-a5ee-a520969539d0
Response:
{
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYW1laWQiOiIxMDgxIiwidW5pcXVlX25hbWUiOiJtZW1iZXIiLCJyb2xlIjoiTWVtYmVyIiwicmVhbG0iOiJkZWZhdWx0IiwiZXhwIjoxNDg3NDk2NzM3LCJuYmYiOjE0ODc0OTU1Mzd9.9uiIxrPggvH5nyLbH4UKIL52V6l5mpOyJ26J12FkXvI",
"token_type": "bearer",
"expires_in": 1200,
"refresh_token": "b3cc9c66b86340c5b743f2a7cec9d2f1"
}
If any authentication request fails, a status of 401 Unauthorized
will be returned containing error information in a JSON object.
With your endpoint working and issuing tokens, you can protect your API controllers by adding the OAuth
attribute to your classes, and then use the standard Authorize
attribute to restrict action access as follows:
[OAuth]
public class MyApiController : UmbracoApiController
{
[HttpGet]
[Authorize]
public string HelloWorld()
{
return "Hello " + Members.GetCurrentMember()?.Name;
}
}
The OAuth
attribute has a single optional parameter, Realm
, which allows you to define which realm this controller is associated with. If a realm is configured, only access tokens that were generated from the associated endpoint will be valid.
To access a protected action, an Authorization
header should be added to the request with a value of Bearer {access_token}
where {access_token}
is the value of the access token requested from the authentication endpoint.
Example:
Request URL:
POST https://mydomain.com/umbraco/api/myapi/helloworld
Request Headers:
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYW1laWQiOiIxMDgxIiwidW5pcXVlX25hbWUiOiJtZW1iZXIiLCJyb2xlIjoiTWVtYmVyIiwicmVhbG0iOiJkZWZhdWx0IiwiZXhwIjoxNDg3NDk2NzM3LCJuYmYiOjE0ODc0OTU1Mzd9.9uiIxrPggvH5nyLbH4UKIL52V6l5mpOyJ26J12FkXvI
Response:
"Hello Joe"
Presist and refreshing the token can be cumbersome. If you are using javascript you can use this small helper to handle and refreshing the token etc: https://github.com/tobbbe/authur
Anyone and everyone is welcome to contribute. Please take a moment to review the guidelines for contributing.
Copyright © 2018 Matt Brailsford, Outfield Digital Ltd
Licensed under the MIT License