OCI offers IAM Domains integration with OpenID provider as IDP (for older tenants its IDCS instead of OCI IAM). In this case the authentication is delegated to an OpenID Provider. The benefit of an integration on the IAM instance level (an instance is either IAM domain or IDCS) is that all integrated services like OCI Console, Analytics Cloud and further OCI PaaS and also some Oracle SaaS services can use this integration ootb. 

OCI IAM offers further integrations as leading authentication which can be bound to conditions e.g. domains or network sources. An integration is no absolute decision, several authentication mechanisms can work in parallel with either a selection through the user during login process or a predestination through IAM. Predestination is based on rules.

For more information on the IAM topic in OCI see https://docs.oracle.com/en-us/iaas/Content/Resources/Assets/whitepapers/best-practices-for-iam-on-oci.pdf

For OpenIDConnect several integration templates are prebuild. The appropriate one can be selected during the configuration. As OCI follows  an API first approach it can be done either with Rest Calls, CLI (encapsulated Rest Calls) or UI. Terraform and other infrastructure automation is also possible.

The ootb providers (Oct 2024) are and have been:

Figure: Screenshot ootb OpenID templates

 

If your provider is in the list and you have in your OpenID provider the default config then you can go with the template. After selection you get asked about the needed configuration values. As OpenIDConnect is built upon of OAuth you may recognize parameters like ClientID and Client Secret. Further values are provided through the template, e.g. scopes. Therefore, they are not listed.

 

Figure: Screenshot about needed or optional configurations (IAM domains UI)

Remark: An IDCS Interface User may not see the JIT and Custom Attribute section as the dialog was extended.

See here for documentation on configuration of template and values for the IDP like callback URL. OpenID is classified in OCI as Social Identity Provider: https://docs.oracle.com/en-us/iaas/Content/Identity/identityproviders/add-social-identity-provider.htm

 

If more information is needed in OCI have a look at the API reference. As OCI IAM is OCI native and PaaS like service (you can use OCI IAM domain standalone e.g. for a custom applications) there is a OCI native API which is based on signature and an IAM based API which is based on OAuth. Here the OAuth based which is used in the rest of the blog for OpenID provider: https://docs.oracle.com/en/cloud/paas/iam-domains-rest-api/api-social-social-identity-providers.html

And here the overall options with OpenID : https://docs.public.oneportal.content.oci.oraclecloud.com/en-us/iaas/Content/Identity/api-getstarted/usingopenidconnect.htm

 

There are a lot of samples and blogs out to see how this usually works.

 

Custom OpenID Provider

 

For this blog the assumption is that none of the provided templates works. To overcome this you can either patch an existing provider or create a custom OpenID template. The patching has a limited scope as the provider config relies on the template which delivers some behavior also for a created provider. You may see this if you use the Rest API to recall the config you did e.g. via UI.

To do this, go for a list of providers and the pick the config of the one of interest like this:

curl --location 'https://idcs-xxxx.identity.oraclecloud.com/admin/v1/SocialIdentityProviders' \ --header 'Authorization: Bearer eyJ4NXQjUzI1NiI…’

select the IDP (here xID) of interest and request the detailed config:

curl --location 'https://idcs-xxxx.identity.oraclecloud.com/admin/v1/SocialIdentityProviders/xID' \ --header 'Authorization: Bearer eyJ4NXQjUzI1NiI…’

As a sample of not included values are the parameters for the authorization, token and userinfo phase. These are only in the referenced template.

In the following some non-standard cases are briefly discussed. Some are already provided as sample. Let’s start with okta and github as they provided in the official documentation. Please go there to see full templates.

https://docs.oracle.com/en-us/iaas/Content/Identity/api-getstarted/customSocialIDPs.htm

The first section is declaring the template for a login flow, enabling the template and defining the matching attribute, means how to match to the username of IAM domain. You may see this allows not like SAML to define different target attributes for matching.

"status": "enabled",
"idAttribute": "<attribute from OpenID provider which identifies the user>",
"capabilities": [
  "login"
], 

The further sections of the template (see previous link) specify the different phases: authorizePhase, tokenPhase, userInfoPhase. The OpenID Connect Authorization Code Flow with Confidential Clients contains two steps in the Authorization Code flow:

  • Request the Authorization Code
  • Request the Token
  • Optional retrieve user information/claims from InfoPoint

For details: https://docs.public.oneportal.content.oci.oraclecloud.com/en-us/iaas/Content/Identity/api-getstarted/usingopenidconnect.htm#openidconnectauthcode

It is per vendor and configuration options of vendor which phases and protocols it allows e.g. post vs get etc. The OpenID spec is not singular means it allows different flows. Also it might be that e.g. an infophase is not possible with the provided token or attributes are not delivered with the ID token as they have to be requested explicit as scope (e.g. email).

New Templates

To create a new template which is then also visible in the UI Rest Calls have to be used. To be able to use a custom template you first have to create a template and then instantiate one provider based on this template. This sample uses email as identity attribute which is requested in the scope section. You may remember that there is a consent question to the user if he wants to pass here the email.

curl --location 'https://idcs-xxxx.identity.oraclecloud.com/admin/v1/SocialIdentityProviderMetadata' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer eyJ4xxxx’\
--data '{
    "type": "OpenIDwithEmail",
    "status": "enabled",
    "idAttribute": "email",
    "capabilities": [
        "login"
    ],
    "authorizePhase": {
        "loginScopes": "openid email",
….

More here: https://docs.public.oneportal.content.oci.oraclecloud.com/en-us/iaas/Content/Identity/api-getstarted/customSocialIDPs.htm

 

Github and okta

The documentation contains sample config for github: https://docs.public.oneportal.content.oci.oraclecloud.com/en-us/iaas/Content/Identity/api-getstarted/customSocialIDPs.htm#customSocialIDPs__custom-social-idp-github-example

From there:

...
"idAttribute": "email",
"capabilities": [
                "login"
               ],
"authorizePhase": {
               "loginScopes": "user user:email",
               "url": "http://github.com/login/oauth/authorize"
...

The template has specified email as matching attribute and aligned the loginscopes to the github spec.

In a test with interception of browser calls you will see the calls according to this specification.

http://github.com/login/oauth/authorize?client_id=<client-id>&response_type=code&redirect_uri=<client-redirect-uri>&scope= user%20user%3Aemail&state=1234

 

And the okta sample from the documentation:

https://docs.oracle.com/en-us/iaas/Content/Identity/api-getstarted/customSocialIDPs.htm#customSocialIDPs__custom-social-idp-okta-use-case

...
"idAttribute": "email",
"capabilities": [
                "login"
               ],
"authorizePhase": {
                   loginScopes": "openid profile email",....

Forgerock

As of now there are no OCI samples for ForgeRock and you need to check what OpenAM expects. You can visit the documentation first and then compare the Forgerock configuration of the OpenID client with OCI.

The Authorize phase requires according to this older doc:
https://backstage.forgerock.com/docs/am/6.5/oidc1-guide/#proc-auth-code-browser-oidc

 Request as post command and
 client_id=your_client_id
  response_type=code
  redirect_uri=your_redirect_uri
  scope=openid profile

The ForgeRock client which will be used in OCI config has to be created accordingly
Confidential client with ClientID and Secret  and
 Scopes: openid profile
 Response Types: code
 Grant Types: Authorization Code
 Token Endpoint Authentication Method: client_secret_basic (ForgeRock standard auth method is client_secret_post so has to be changed to client_secret_basic *)

For the Token phase its listed here
https://backstage.forgerock.com/docs/am/6.5/oidc1-guide/#proc-auth-code-token-oidc

curl --request POST “token endpoint”
--data "grant_type=authorization_code"
--data "code=g5B3qZ8rWzKIU2xodV_kkSIk0F4"
…
--data "redirect_uri=https://www.example.com:443/callback"  

Be sure that all these are in your template like (effected by *)

…   
"tokenPhaseHeaders": [
        {
            "value": "application/x-www-form-urlencoded",
            "name": "Content-Type"
        },
        {
            "value": "Basic ${clientCredentials}",
            "name": "Authorization"
        }
    ],
"tokenPhaseParameters": [
        {
            "value": "${authorizationCode}",
            "name": "code"
        },
        {
            "value": "authorization_code",
            "name": "grant_type"
        },
        {
            "value": "${redirectUri}",
            "name": "redirect_uri"
        }…

 

Azure BtoC

Azure BtoC delivers some doc about OpenID here:
https://learn.microsoft.com/en-us/azure/active-directory-b2c/openid-connect
You may recognize that Azure expects in the scope the ClientID. So the section looks then like this with d283119b-e1111-555-baf9cc-adsfsd8e as ClientID:

…
"authorizePhase": {
       "loginScopes": "openid profile d283119b-e1111-555-baf9cc-adsfsd8e",…

And the method of token phase has to fit to parameter, so in case of post:

"tokenPhaseParameters": [
      {
           "value": "${socialIdentityProvider.consumerKey}",
           "name": "client_id"
       },
       {
           "value": "${socialIdentityProvider.consumerSecret}",
           "name": "client_secret"
       },
       {
           "value": "${redirectUri}",
           "name": "redirect_uri"
       }
       {
           "value": "${authorizationCode}",
           "name": "code"
       },
       {
           "value": "authorization_code",
           "name": "grant_type"
       }

Also the mapping may be different, her in case the UID from Azure should be used:

… "idAttribute": "uid",…

 

PingFederate

PingFederate works like the other templates. It is more a setup at provider side

  • which scopes are allowed, mandatory
  • what methods are allowed for client (post/get,…)
  • what authorzation has to be used in which phase
  • which attributes can be retrieved.

So e.g. in a minimal scope with only openid      (  “loginScopes”: “openid” ) only the sub can be used as matching the username.

Troubleshooting

OCI IAM domain error messages in case of OpenID are generic. The IAM diagnostics may not help in this case. Also the extended message setting (screen) does not provider further info.

Toggle Content of Errormessage

 

Most common errors are

 

  • URL bar contains “invalid scopes” as response
    Means that config of OAuth client at IDP has not allowed the requested scopes; adjust either the IDP client config or the OCI IAM provider (via patch command, not possible in UI)

     
  • There is a problem with your Account (splash screen)
    Means the OpenID provider Auth was somehow successful but the further steps can not be executed; either the id does not contain the needed values (e.g. mapping), nmappng could not be achieved (no account in OCI IAM), credentials for infophase not authorized, protocols and paramter do not match (get vs post etc.) 
  • URL bar you may get additional info like this
    The+Identity+Provider+Test+is+unable+to+log+you+in.+Please+try+later.
    This is more a hint that something in the tokenphase or infophase is not working. You may check protocols (post/get) and parameter (e.g if redirect_uri is missing).

     

 

Here the steps to validate your config:

Assumption is you can create a Social IDP, means you have the sufficient entitlements (policies / roles) assigned.

First check would be if the endpoints are provided, either with the direct links or with the “well-known/openid-configuration”. Both work in the OCI config.

Second check is if scopes would work. Again compare it with the “well-know” endpoint the “supported scopes section”. And check if the OpenID provider require additional scopes in the request, e.g. the ClientID or a GUID. Both values are created when defining the openid client at the IDP. In addition supported response types (standard would be code) and supported grant types (standard would be authorization_code) must fit to the sequence
The Standard OIDC template requests these scopes which may be too much:  
“scope”: [ “address”, “phone”, “openid”, “profile”, “email” ]

Third, if possible, check the config of the OpenID client at the OpenId provider. Basic config like is the client active, can public access and if the scopes fit.

Forth check the documentation of the enterprise or the vendor which phase of openid flow requires which parameters. And if they fit to your template. E.g. Redirect URL needed in tokenphase or not.

Here the steps to go through the OpenID flow:

Try to start the OpenID flow and intercept every step. Usually you get a clear message back if scopes do not fit. This is in the response of the IDP. If scopes and client is ok then you should get the code. This code can be exchanged for a token.  If this exchange does not work, try it manually to get more error information back and compare with the tokenphase configured in the template.

If all is checked and does not work, go for a manual flow with a Rest Client or Curl. You probably need to change the IDP config of redirect URL to localhost:

1. Get the Code (here for openid and profile):

POST <IDP Endpoint for  authorize>?response_type=code&scope=openid+profile&client_id=<client_id>&redirect_uri=<IDCS>

 2. Use the Code to get the token (post):

POST '<IDP Endpoint for  token>/' \
--header 'Authorization: Basic <base 64 of clientid:secret>' \
--header 'Content-Type: application/x-www-form-urlencoded \
--data-urlencode 'code=xxx==' \
--data-urlencode 'grant_type=authorization_code'

 3.  use the token for /oauth2/v1/userinfo

GET '<IDP Endpoint for userinfo>' \
--header 'Authorization: Bearer <token from step 2>'

If this works check your template for userInfoAttributeMappings and delete the section.

 

Extending SSO

Extend the login flow to Provisioning:

Supporting Social JIT Provisioning with Group Membership Support (oraclecloud.com)