Skip to content

AuthenticationProviders

Pierre Cauchois edited this page Dec 20, 2017 · 1 revision

Authentication Providers

A new concept introduced in version 1.3.x of the SDK is authentication providers. The general idea is that we need to separate how the client stores and gets credentials from the rest of the client and transport code.

Context

Up until version 1.2.x, the only way to pass credentials to the device client was through either the factory methods (fromSharedAccessSignature and fromConnectionString) or runtime methods (updateSharedAccessSignature and setOptions) to "update" the credentials used to authenticate with the Azure IoT Hub instance. This logic is limiting when thinking about secure storage of the credentials, typically using a hardware security module (eg. a TPM) and puts the onus on the SDK user to figure out how to read or generate credentials using secure storage, and how and when to pass them to the device client.

Concepts and Design

The idea of an authentication provider is that it's an object that is given to the client by the user, and the client can query the authenticate provider for credentials whenever it needs them. In case of token-based authentication (as opposed to certificate-based authentication) the authentication provider can also tell the client when a new token is available for it to use.

Azure IoT Hub supports 2 types of authentication mechanism for devices: security tokens, and x509 certificates (to learn more, go read the about Azure IoT Hub security). The difference is that security tokens need to be refreshed before they expire and each transport has a different way of re-authenticating the connection with the Azure IoT Hub instance.

Note: X509 certificates can expire too but their renewal is usually not nearly as frequent as security tokens. By default, security tokens are renewed every hour, whereas certificates have days, weeks or even years before expiry.

The basic AuthenticationProvider interface is defined here. It only has one method, getDeviceCredentials which takes a callback and that callback is called either with an error or the device credentials (including deviceId, IoT hub host name, and either a security token or a certificate). Any authentication provider should implement at least this.

On top of that, we added a type property that can either be AuthenticationType.Token or AuthenticationType.X509. We went that route instead of using different custom types to avoid a painful inheritance scheme.

Finally, authentication providers of type AuthenticationType.Token are expected to inherit from EventEmitter and emit the newTokenAvailable event before the expiry time of the token so that the device client can re-authenticate before it gets an UnauthorizedError from the Azure IoT Hub instance. You'll find below what the default authentication providers provided with the SDK do.

In the case of X509 authentication, the connection is authenticated only when established, so the device client only relies on the getDeviceCredentials call.

Default Authentication Providers

Since we hate breaking changes, we are keeping the existing fromSharedAccessSignature, fromConnectionString, updateSharedAccessSignature and setOptions call. so your existing code will work and take advantage of this new architecture, since we "hide" one of the default authentication providers below those.

SharedAccessKeyAuthenticationProvider

A shared access key is used to generate a security token either for an access policy, or a specific device. it's corresponds to the aptly named SharedAccessKey section of a connection string. The SharedAccessKeyAuthenticationProvider will keep a copy of this key in memory and will generate security tokens on a regular basis. How regularly? every 45 minutes by default, and each token will have a 1 hour expiry time. This default behavior can be overridden by passing a tokenValidTimeInSeconds and a tokenRenewalMarginInSeconds arguments to the fromConnectionString factory method. tokenValidTimeInSeconds is the time the token should be valid for. tokenRenewalMarginInSeconds is the number of seconds before expiry at which we should start the renewal process.

SharedAccessSignatureAuthenticationProvider

In the case of the SharedAccessSignatureAuthenticationProvider, the SDK is missing the shared access key to automatically renew the security token - therefore the user must call the SharedAccessSignatureAuthenticationProvider.updateSharedAccessSignature method to update the token. calling this method will immediately trigger a newTokenAvailable event for the client. No need to call updateSharedAccessSignature on the client anymore.

X509AuthenticationProvider

The X509AuthenticationProvider only implements the getDeviceCredentials method and calls the callback with the certificate and its private key that were passed when creating the X509AuthenticationProvider. For compatibility purposes with the legacy setOptions call of the client we also have a setX509Options method on this authentication provider but we do not recommend using it. it will NOT fire the newTokenAvailable event (it's not a token, and when using X509 the client does not support updating the certificates anyway).

Using authentication providers

In order to let SDK users create their own authentication providers as needed, or use the default ones, we've added a fromAuthenticationProvider factory method in the device client object. it simply takes an authentication provider and a transport as arguments.

Bonus question: What happens within the client and transports?

To be honest, the client does not really care about the authentication provider. the transports do. When the client instantiate the transport object, it'll pass the AuthenticationProvider object to the transport who knows what to do with it.

The transport will check if it's a token-based authentication provider or not. if it is, it will subscribe to the newTokenAvailable event.

When called upon to connect, the transport will call getCredentials to retrieve the credentials and use them to connect. It's pretty simple really.