If you want to generate JWT from x509 cert/key, any operation (including reading) on %SYS.X509Credentials requires U on %Admin_Secure resource.%Admin_Secure is required because %SYS.X509Credentials is persistent, and it's implemented this way to prevent all users from accessing private keys.
If %Admin_Secure resource is not available at runtime, you can use the following workaround.
Upon reviewing the code for JWT generation, I discovered that the JWT code utilizes %SYS.X509Credentials solely as a source of runtime data for PrivateKey, PrivateKeyPassword, and Certificate. As a workaround, you can use a runtime non-persistent implementation of the X.509 interface, exposing just these properties. If you're using interoperability Cert/PK can be stored in credentials for secure access:
Class User.X509 Extends %RegisteredObject
{
Property PrivateKey As %VarString
Property PrivateKeyPassword As %String
Property Certificate As %VarString
Property HasPrivateKey As %Boolean [ InitialExpression = {$$$YES} ]
ClassMethod GetX509() As User.X509
{
set x509 = ..%New()
set x509.PrivateKey = ..Key()
set x509.Certificate = ..Cert()
quit x509
}
ClassMethod GetX509FromCredential(credential) As User.X509
{
set credentialObj = ##class(Ens.Config.Credentials).%OpenId(credential,,.sc)
throw:$$$ISERR(sc) ##class(%Exception.StatusException).ThrowIfInterrupt(sc)
set x509 = ..%New()
set x509.PrivateKey = credentialObj.Password
set x509.Certificate = credentialObj.Username
quit x509
}
ClassMethod Key()
{
q "-----BEGIN RSA PRIVATE KEY-----"_$C(13,10)
_"YOUR_TEST_KEY"_$C(13,10)
_"-----END RSA PRIVATE KEY-----"
}
ClassMethod Cert() As %VarString
{
q "-----BEGIN CERTIFICATE-----"_$C(13,10)
_"YOUR_TEST_CERT"_$C(13,10)
_"-----END CERTIFICATE-----"
}
}
And you can generate JWT the following way:
ClassMethod JWT() As %Status
{
Set sc = $$$OK
Set x509 = ##class(User.X509).GetX509()
Set algorithm ="RS256"
Set header = {"alg": (algorithm), "typ": "JWT"}
Set claims= {"Key": "Value" }
#
Set sc = ##class(%Net.JSON.JWK).CreateX509(algorithm,x509,.privateJWK)
If $$$ISERR(sc) {
Write $SYSTEM.OBJ.DisplayError(sc)
}
#
Set sc = ##class(%Net.JSON.JWKS).PutJWK(privateJWK,.privateJWKS)
If $$$ISERR(sc) {
Write $SYSTEM.OBJ.DisplayError(sc)
}
Set sc = ##Class(%Net.JSON.JWT).Create(header,,claims,privateJWKS,,.pJWT)
If $$$ISERR(sc) {
Write $SYSTEM.OBJ.DisplayError(sc)
}
Write pJWT
Return sc
}
Alternatively you can use dynamic object to skip class creation, in that case it would look like this:
ClassMethod JWT(credential) As %Status
{
Set sc = $$$OK
Set credentialObj = ##class(Ens.Config.Credentials).%OpenId(credential,,.sc)
throw:$$$ISERR(sc) ##class(%Exception.StatusException).ThrowIfInterrupt(sc)
Set x509 = {
"HasPrivateKey": true,
"PrivateKey": (credentialObj.Password),
"PrivateKeyPassword":"",
"Certificate":(credentialObj.Username)
}
Set algorithm ="RS256"
Set header = {"alg": (algorithm), "typ": "JWT"}
Set claims= {"Key": "Value" }
#
Set sc = ##class(%Net.JSON.JWK).CreateX509(algorithm,x509,.privateJWK)
If $$$ISERR(sc) {
Write $SYSTEM.OBJ.DisplayError(sc)
}
#
Set sc = ##class(%Net.JSON.JWKS).PutJWK(privateJWK,.privateJWKS)
If $$$ISERR(sc) {
Write $SYSTEM.OBJ.DisplayError(sc)
}
Set sc = ##Class(%Net.JSON.JWT).Create(header,,claims,privateJWKS,,.pJWT)
If $$$ISERR(sc) {
Write $SYSTEM.OBJ.DisplayError(sc)
}
Write pJWT
Return sc
}