Use Azure Active Directory (AD) OAUTH2 authentication with PASOE

This page describes setting up PASOE to use Azure AD for authentication, using OAUTH2 authentication mechanism. It is important to remember that PASOE itself does not act as a client application and so cannot perform a login itself; this means that another application (the client application, Azure itself) must provide the OAUTH2 bearer token.

This page describes the identity provider (Azure AD) and service provider (PASOE) configuration. It does NOT describe the client application.

Documentation links

Documentation links


This configuration was tested with OpenEdge 11.7.15 (should work 11.7.2+).

The configuration has changed between 11.7 , 12.0 and 12.5 . See the Progress doc for details


Before setting up Azure Active directory you will need to know some information about the PASOE instance and webapp(s) that will use Azure for authentication.

  1. The instance’s host and port. This can be localhost and/or inside the firewall. In this page we are using http://localhost:8810 or https://localhost:8811 .

  2. The webapp that needs to be setup to use SAML SSO. In this page we are using the ROOT webapp.

  3. An application URL. In this page, we are using http://localhost:8810/web/hello . This page is configured to simply “echo” the request using a particular webhandler.

Set up Azure Active Directory (AD)

You need to have administrative access to the AD tenant. This example uses a domain on the free tier of Office365, called .


Ensure you have some users in the domain / AD tenant.

Set up a Registered Application

From the Dashboard, select Enterprise Applications. Register a new applicaiton by clicking the application registrations link


Create a new registered application

Select the New Registration link


Give the application a name and make sure to specify a redirect URI. This should point to the preruisite URL

Click the Register button at the botton of the screen. This creates a new Enterprise Application and a registered app and takes you to the App Registration overview. Important here are the Endpoints link, and the Application (client) ID information.

Update the Authentication data

Select the Authentication link in the Manage group.

The platform configuration has defaulted to “Web”due to the addition of the redirect URI earlier.

Select (at least) the ID tokens checkbox. These are the only token types supported by PASOE in 11.7.

Click Save .

Upload a public key certificate

Create a public key certificate (self-signed). See for instructions.

Upload it to the app, using the Certificates & secrets link.

Gathering information required for PASOE

The PASOE configuration needs 2 main pieces of information: the JWK keystore location, and the application id .

Keystore location URL

The keystore URL is available as part of the OpenID Connect metadata. The application-specific URL for that document is available from the Overview > Endpoints link.

Get that URL (in a browser or other tool). The URL returns JSON data,

{ "token_endpoint": "", "token_endpoint_auth_methods_supported": [ "client_secret_post", "private_key_jwt", "client_secret_basic" ], "jwks_uri": "", "response_modes_supported": [ "query", "fragment", "form_post" ], "subject_types_supported": [ "pairwise" ], "id_token_signing_alg_values_supported": [ "RS256" ], "response_types_supported": [ "code", "id_token", "code id_token", "id_token token" ], "scopes_supported": [ "openid", "profile", "email", "offline_access" ], "issuer": "", "request_uri_parameter_supported": false, "userinfo_endpoint": "", "authorization_endpoint": "", "device_authorization_endpoint": "", "http_logout_supported": true, "frontchannel_logout_supported": true, "end_session_endpoint": "", "claims_supported": [ "sub", "iss", "cloud_instance_name", "cloud_instance_host_name", "cloud_graph_host_name", "msgraph_host", "aud", "exp", "iat", "auth_time", "acr", "nonce", "preferred_username", "name", "tid", "ver", "at_hash", "c_hash", "email" ], "kerberos_endpoint": "", "tenant_region_scope": "EU", "cloud_instance_name": "", "cloud_graph_host_name": "", "msgraph_host": "", "rbac_url": "" }

The URI is contained in the jwks_uri property.

The application ID is a GUID value, available in the Overview page.

PASOE configuration

Update security properties

The webapps/ROOT/WEB-INF/ file contains the majority of the configuration information for securing the webapp using OAuth2.

The properties listed below need to be changed (or saved as a file overwriting webapps/ROOT/WEB-INF/ ).

client.login.model=oauth2 ## An encrypted value can be generated using 'genpassword' OEClientPrincipalFilter.domain=azure OEClientPrincipalFilter.key=azure-dac jwtToken.keystore.type=jwk # This value is taken from the jwks_uri property from the metadata jwtToken.keystore.jwkurl= oauth2.resSvc.tokenServices=jwt # The application (client) ID oauth2.resSvc.audience=49b8af06-8920-44a7-b36c-6c00813a4a1f

The OEClientPrincipalFilter domain and key are used to seal the client-principal that’s sent to the PASOE agent. This domain is not the domain used by the Azure tenant.

Update authorization rules

There are no “scopes” defined for this app in Azure, so we need to allow remove all authorization. Edit the webapps/ROOT/WEB-INF/oeablSecurityJWT.csv file so that it either only includes the lines below, or that all other lines are commented out.

# Allow all for testing; not a good practice for production "/**","*","permitAll()"

Configure “echo” webhandler

The request echo webhandler is a webhandler that returns information about the request as a JSON payload (similar to what does). It is publicly available at . If run with a ?debug query parameter, additional information is returned.

In this example, all /web requests are hanbdled by this webhandler, including /web/hello that's used as the application URL.

[oepas1.ROOT.WEB] adapterEnabled=1 defaultCookieDomain= defaultCookiePath= defaultHandler=RequestEchoHandler srvrAppMode=development srvrDebug=1 wsRoot=/SamlSSO/static/webspeed


Start the instance

If there are format/syntax issues with the configuration, errors will be reported in the instance’s session manager (“dated”) log.


From a web browser, run the following request. The URL is the value of the OAuth 2.0 authorization endpoint (v2) field in the Endpoints screen.

Documentation on the URL is at

The client_id value is the application ID taken from the Overview page.

The redirect_uri value is the same (must be) value from the initial setup; it must also be URL encoded.

The response_type must be id_token . ?client_id=49b8af06-8920-44a7-b36c-6c00813a4a1f &response_type=id_token &state=7698 &scope=openid &nonce=678910 &redirect_uri=http%3A%2F%2Flocalhost%3A8810%2Fweb%2Fhello &response_mode=form_post


Paste the URL into the browser URL bar ; before hitting enter, make sure that you enable developer tools in the browser (right-click > Inspect ) and select the Network tab.

Now hit enter; you will be promted for your Azure credentials, and on successful authentication, be redirected to the /web/hello page configured as the redirect URI.

This returns an error, along the lines of.

<oauth> <error_description>An Authentication object was not found in the SecurityContext</error_description> <error>unauthorized</error> </oauth>

In the response data, there’s an id_token field . Copy the value of that field.

You can validate that it’s a proper JWT at .

Once the id token data is obtained, it will be added to a request to the PAS instance as a header.

Using the OAuth2 token to request application data

A request can now be made to the PAS application. The SAML data must be sent as the Authorization header, with the value in the format Bearer <id-token> .

An example using curl is

// Curl doc at curl http://localhost:8810/SamlSSO/web/hello -H "Authorization: Bearer <id-token>"

A JSON response should be returned. Note the user property, which contains information about the Azure enterprise application user.

{ "method": "GET", "uri": "http:\/\/localhost:8810\/web\/hello", "origin": "", "pathParameters": { "FINAL_MATCH_GROUP": "\/", "TEMPLATE": "\/hello" }, "args": {}, "headers": { "COOKIE": "x-ms-gateway-slice=estsfd; stsservicecookie=estsfd; JSESSIONID=CDDC5F263BD1F4684E4795436040817449F8A721A29A.http-client-tracing", "USER-AGENT": "insomnia\/2022.5.1", "ACCEPT": "*\/*", "HOST": "localhost:8810", "REFERER": "", "PORT": "8810" }, "cookies": { "JSESSIONID": "JSESSIONID=CDDC5F263BD1F4684E4795436040817449F8A721A29A.http-client-tracing; Path=", "stsservicecookie": "stsservicecookie=estsfd; Path=", "x-ms-gateway-slice": "x-ms-gateway-slice=estsfd; Path=" }, "user": { "qualifiedUserId": "pnH6-Xugnl3uTaYqCe4VZlvaIPUsJQPj7Gh1z4OokHI@azure", "domainType": "OEApplication", "loginState": "SSO", "sealAt": "2022-09-21T15:04:35.000-04:00", "expireAt": "2022-09-21T16:01:46.000-04:00", "loginHost": "", "clientTty": "", "sessionId": "0", "roles": [], "properties": [ {"aud": "49b8af06-8920-44a7-b36c-6c00813a4a1f"}, {"ver": "2.0"}, {"nbf": "1663786606"}, {"aio": "AWQAm\/8TAAAAbmfIlqUFSg3o3PiHmSBNG6OiF22P2cHnTdV33oSDRqBxepDqu7TiBTOJE\/4qeGWxwUYqborSSe5uwxgg2+5gN2lB6NrpsgPJ8mwZk9vRNXGouQl\/Uj00YCcDEFty2sLd"}, {"rh": "0.AYIATruW6FJz3EOe4QEwfMrobQavuEkgiadEs2xsAIE6Sh-VAGw."}, {"iss": "https:\/\/\/e896bb4e-7352-43dc-9ee1-01307ccae86d\/v2.0"}, {"uti": "mf8lUHZxHEyb4gWEwwoBAA"}, {"token_type": "Bearer"}, {"iat": "1663786606"}, {"nonce": "678910"}, {"tid": "e896bb4e-7352-43dc-9ee1-01307ccae86d"} ] }, "data": {} }


The receiving of the ID token and constructing the appropriate HTTP request to the application is typically the responsibility of the client application.

Additional configuration

More information can be added to the ID token, such as the user’s email address and client IP address.

To do so, select the Token configuration option. Add optional claims


In order to have this data returned, a profile scope needs to be added to the authorization request, as a space-delimited value, eg. &scope=openid profile . The email address is returned as a preferred_user property in the client-principal.

{ "method": "GET", "uri": "http:\/\/localhost:8810\/web\/hello", "origin": "", "pathParameters": { "FINAL_MATCH_GROUP": "\/", "TEMPLATE": "\/hello" }, "args": {}, "headers": { "COOKIE": "x-ms-gateway-slice=estsfd; stsservicecookie=estsfd; JSESSIONID=CDDC5F263BD1F4684E4795436040817449F8A721A29A.http-client-tracing", "USER-AGENT": "insomnia\/2022.5.1", "ACCEPT": "*\/*", "HOST": "localhost:8810", "REFERER": "", "PORT": "8810" }, "cookies": { "JSESSIONID": "JSESSIONID=CDDC5F263BD1F4684E4795436040817449F8A721A29A.http-client-tracing; Path=", "stsservicecookie": "stsservicecookie=estsfd; Path=", "x-ms-gateway-slice": "x-ms-gateway-slice=estsfd; Path=" }, "user": { "qualifiedUserId": "pnH6-Xugnl3uTaYqCe4VZlvaIPUsJQPj7Gh1z4OokHI@azure", "domainType": "OEApplication", "loginState": "SSO", "sealAt": "2022-09-21T17:05:54.000-04:00", "expireAt": "2022-09-21T18:05:27.000-04:00", "loginHost": "", "clientTty": "", "sessionId": "0", "roles": [], "properties": [ {"ver": "2.0"}, {"aio": "AVQAq\/8TAAAABCQ50yv\/E6\/js77ddd6kF7UnPMcfqE0sR4F5PT\/0ZskN36VuZiqKw6DCMgO92WdmGuu\/6qd08HGfIqrsCghZZGMCNmeIWFT+a+y6e5+ZxBU="}, {"iss": "https:\/\/\/e896bb4e-7352-43dc-9ee1-01307ccae86d\/v2.0"}, {"oid": "c661f958-4c82-4387-9d3e-6aa8654e2dc7"}, {"preferred_username": ""}, {"uti": "h9zcFHDMn0agS6UHLTQGAQ"}, {"token_type": "Bearer"}, {"nonce": "678910"}, {"tid": "e896bb4e-7352-43dc-9ee1-01307ccae86d"}, {"aud": "49b8af06-8920-44a7-b36c-6c00813a4a1f"}, {"nbf": "1663794027"}, {"rh": "0.AYIATruW6FJz3EOe4QEwfMrobQavuEkgiadEs2xsAIE6Sh-VAGw."}, {"ipaddr": ""}, {"iat": "1663794027"} ] }, "data": {} }

Troubleshooting / debugging