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.
- Realm : string
[optional, default:"default"]
A unique alias for the configuration, allowing you to configure multiple endpoints. - Path : string
[optional, default:"/oauth/token"]
The path of the endpoint (IMPORTANT! Be sure to add the base of the path to theumbracoReservedPaths
app setting, ie~/oauth/
) - UserService : IOAuthUserService
[optional, default:new UmbracoMembersOAuthUserService()]
The service from which to validate authentication requests against. Out of the box AuthU comes with 2 implementations,UmbracoMembersOAuthUserService
andUmbracoUsersOAuthUserService
which authenticate against the Umbraco members and users store respectively. Custom sources can be configured by implementing theIOAuthUserService
interface yourself. - SymmetricKey : string
[required]
A symmetric key used to sign the generated access tokens. Must be a string, 32 characters long, BASE64 encoded. - AccessTokenLifeTime : int
[optional, default:20]
Sets the lifespan, in minutes, of an access token before re-authentication is required. Should be short lived. - ClientStore : IOAuthClientStore
[optional, default:null]
Defines a store for OAuth client information. If not null, all authentication requests are required to pass valid client credentials in order for authentication to be successful. If null, client crendetials are not required to authenticate. Out of the box AuthU comes with 2 implementations,InMemoryOAuthClientStore
which stores a fixed list of client credentials in memory andUmbracoDbOAuthClientStore
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 theIOAuthClientStore
interface. - RefreshTokenStore : IOAuthRefreshTokenStore
[optional, default:null]
Defines a store for OAuth refresh token information. If not null, authentication responses will include arefresh_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 theIOAuthRefreshTokenStore
interface. - RefreshTokenLifeTime : int
[optional, default:1440]
Sets the lifespan, in minutes, of a refresh token before it can no longer be used. Can be long lived. If a client store is configured, this will get overridden by the client settings. - AllowedOrigin : string
[optional, default:"*"]
Sets the allowed domain from which authentication requests can be made. If developing a web application, it is strongly recommended to set this to the domain from which your app is hosted at to prevent access from unwanted sources. If developing a mobile app, it can be set to wildcard "*" which will allow any source to access it, however it is strongly recommended you use a client store which requires a secret key to be passed. If a client store is configured, this will get overridden by the client settings. If you are managing CORS headers yourself and you don't want AuthU to set the allowed origins header for you, you will need to explicitly set this tonull
. - AllowInsecureHttp : bool
[optional, default:false]
Sets whether the api should allow requests over insecure HTTP. You'll probably want to set this totrue
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:
- grant_type = "password"
- username = The users username
- password = The users password
- client_id = A valid client id (Only required if a client store is configured)
- client_secret = A valid client secret (Only required if a client store is configured, and the client is "secure")
- device_id = An optional device id to associate the token with, allowing login from multiple devices
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:
- grant_type = "refresh_token"
- refresh_token = The refresh token returned from the original authentication request
- client_id = A valid client id (Only required if a client store is configured)
- client_secret = A valid client secret (Only required if a client store is configured, and the client is "secure")
- device_id = An optional device id to associate the token with, allowing login from multiple devices
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