Client Authentication

Working with client sessions

After opening a secure channel, the client needs to create a session. The client will receive a set of endpoints and a list of supported user identity token policies in response.

local session, err = client:createSession("test_session", 3600000)
if err ~= nil then
  error("Creating session failed: "..err)
end

local tokenPolicy
for _, endpoint in ipairs(session.ServerEndpoints) do
  for _, policy in ipairs(endpoint.UserIdentityTokens) do
    if policy.TokenType == ua.UserTokenType.UserName and
      (policy.SecurityPolicyUri == nil or policy.SecurityPolicyUri == ua.SecurityPolicy.None)
    then
      tokenPolicy = policy
      goto found
    end
  end
end

::found::
if not tokenPolicy then
  error("cannot find endpoint with username token.")
end

local userName = "admin"
local password = "12345"
local resp, err = client:activateSession(tokenPolicy.PolicyId, userName, password)
if err ~= nil then
  error("Activating session failed: "..err)
end

Full source

Each token policy contains several fields. These fields are common to all policy types:

Field

Description

PolicyId

Server-assigned policy identifier. The client sends it back so the server can interpret the user token.

TokenType

Token type: Anonymous, UserName, Certificate, or IssuedToken.

SecurityPolicyUri

Security policy URI used to secure the token.

Additional fields are specific to each token type and will be covered in the following sections.

Anonymous

An anonymous token basically means the absence of authentication, which means anyone can connect to and work with the server. This type of authentication is usually enabled for testing purposes only.

You can pass the identifier of the anonymous policy, which is taken from the response of CreateSession. No additional parameters are required for the anonymous token.

-- Create session with name "test_session" and with life time
-- 1 hour (3600000 ms)
local session, err = client:createSession("test_session", 3600000)
local tokenPolicy
for _, endpoint in ipairs(session.ServerEndpoints) do
  for _, policy in ipairs(endpoint.UserIdentityTokens) do
    if  policy.TokenType == ua.UserTokenType.Anonymous
    then
      tokenPolicy = policy
      goto found
    end
  end
end

::found::
if not tokenPolicy then
  error("cannot find endpoint with anonymous token.")
end
-- Passing id of anonymous token policy.
local resp, err = client:activateSession(tokenPolicy.PolicyId)

Full source

User Name

Depending on the server configuration, a password can be sent encrypted or unencrypted, which depends on the token policy configuration on the server.

The Username token policy has these parameters:

Field

Description

PolicyId

Server-assigned policy identifier.

TokenType

ua.UserTokenPolicy.UserName.

SecurityPolicyUri

Security policy used to encrypt the password. If absent or set to None, the password is not encrypted by the token policy. If the secure channel also does not encrypt packets, the password is sent as-is.

The following example demonstrates how to authenticate with a server using a username and password:

local session, err = client:createSession("test_session", 3600000)
if err ~= nil then
  error("Creating session failed: "..err)
end

local tokenPolicy
for _, endpoint in ipairs(session.ServerEndpoints) do
  for _, policy in ipairs(endpoint.UserIdentityTokens) do
    if policy.TokenType == ua.UserTokenType.UserName and
      (policy.SecurityPolicyUri == nil or policy.SecurityPolicyUri == ua.SecurityPolicy.None)
    then
      tokenPolicy = policy
      goto found
    end
  end
end

::found::
if not tokenPolicy then
  error("cannot find endpoint with username token.")
end

local userName = "admin"
local password = "12345"
local resp, err = client:activateSession(tokenPolicy.PolicyId, userName, password)
if err ~= nil then
  error("Activating session failed: "..err)
end

Full source

x509 certificate

To authenticate with a certificate, you need to find the ID of the policy with the type ua.UserTokenPolicy.Certificate.

This policy has these parameters:

Field

Description

PolicyId

Server-assigned policy identifier.

TokenType

ua.UserTokenPolicy.Certificate.

SecurityPolicyUri

Security policy that controls whether the client sends a signature. The signature is calculated with the user’s private key and proves ownership of the certificate. If absent or set to None, only the certificate is sent.

When activating a session with certificate-based authentication, the ActivateSession call should include these parameters:

Field

Description

PolicyId

Certificate token policy identifier.

TokenType

ua.UserTokenPolicy.Certificate.

Certificate

User certificate sent to the server.

PrivateKey

Private key for the user certificate. Used to calculate the signature.

ActivateSession accepts certificate and private key in PEM or DER format, or a path to files can be passed.

The following example shows how to authenticate using a certificate:

  error("Opening secure channel failed: "..err)
end

local session, err = client:createSession("test_session", 3600000)
local tokenPolicy
for _, endpoint in ipairs(session.ServerEndpoints) do
  -- Select certificate token policy with security policy Basic128Rsa15
  for _, policy in ipairs(endpoint.UserIdentityTokens) do
    if  policy.TokenType == ua.UserTokenType.Certificate then
      tokenPolicy = policy
      goto found
    end
  end
end

::found::
if not tokenPolicy then
  error("cannot find endpoint with certificate token policy.")
end

local certificate = mako.cfgdir.."/../certs/client.pem"
local privateKey = mako.cfgdir.."/../certs/client.key"
local resp, err = client:activateSession(
  tokenPolicy.PolicyId, certificate, privateKey)

Full source

JWT, OAuth2, Azure

OPC UA allows authentication using third-party tokens, which are also known as Issued Tokens.

To authenticate with such tokens, you need to search for the policy that uses the token type ua.UserTokenPolicy.IssuedToken. This type of token is commonly used for all third-party tokens. To distinguish between token formats, the policy includes an additional parameter called IssuedTokenType.

The IssuedToken policy has these parameters:

Field

Description

PolicyId

Issued-token policy identifier.

TokenType

ua.UserTokenPolicy.IssuedToken.

IssuedTokenType

Token format: ua.IssuedTokenType.JWT, ua.IssuedTokenType.OAuth2, or ua.IssuedTokenType.Azure.

IssuerEndpointUrl

URL of the identity server that issued the token.

SecurityPolicyUri

Security policy used to encrypt the token. If absent or set to None, the token is not encrypted by the token policy. If the secure channel also does not encrypt packets, the token is sent as-is.

The following example shows how to authenticate with issued token:

  error("Opening secure channel failed: "..err)
end

local session, err = client:createSession("test_session", 3600000)
local tokenPolicy
for _, endpoint in ipairs(session.ServerEndpoints) do
  for _, policy in ipairs(endpoint.UserIdentityTokens) do
    -- Select JWT token policy. There also Azure, OAuth2 and OPCUA.
    if  policy.TokenType == ua.UserTokenType.IssuedToken and
        policy.IssuedTokenType == ua.IssuedTokenType.JWT
    then
      tokenPolicy = policy
      goto found
    end
  end
end

::found::
if not tokenPolicy then
  error("cannot find endpoint with certificate token policy.")
end

local jwtHeader = { alg="HS256"}
local jwtPayload = {
  sub = "1234567890",
  name = "John Doe",
  iat = 1516239022
}
local token = require"jwt".sign("my-secret", jwtPayload, jwtHeader)
local resp, err = client:activateSession(tokenPolicy.PolicyId, token)

Full source