Okta SAML API integration

Hi,

I am trying to automate the Okta SAML integration for an app. I am able to create the SSO app succesfully using the api/v1/apps endpoint. However, the response does not include the IDP SSO URL, and the IDP Issuer URL.

Where can I retrieve this data without going through the UI?

Thanks,

One way is to grab from XML, if you hit https://your_okta_domain/app/your_app_id/sso/saml/metadata

Maybe people can suggest something else to get those values directly. But to be honest, they always follow the same rule:

where your_app_name = application name from API call for your_app_id

here’s what we do with Ruby

like @phi1ipp mentioned, you can grab the metadata. I then use a library from onelogin to parse out the xml into a Hash

# frozen_string_literal: true

require 'oktakit'
require 'ruby-saml'

module Osso
  class OktaConfiguration
    attr_accessor :client, :identity_provider

    def self.perform(args)
      new(**args).perform
    end

    def initialize(access_token: ENV['OKTA_ACCESS_TOKEN'], identity_provider:)
      @identity_provider = identity_provider
      @client = Oktakit.new(access_token: access_token, organization: 'dev-162024')
    end

    def perform
      app = create_app
      assign_user(app)
      configure_identity_provider(app)
    end

    private

    def configure_identity_provider(app)
      metadata, status = client.preview_saml_metadata_for_application(app[:id], { content_type: 'application/xml', accept: 'application/xml'})
      idp_metadata_parser = OneLogin::RubySaml::IdpMetadataParser.new
      settings = idp_metadata_parser.parse_to_hash(metadata)
      # { :idp_cert => '', :idp_sso_target_url => '' }
      identity_provider.update(
        sso_url: settings[:idp_sso_target_url],
        sso_cert: settings[:idp_cert]
      )
    end

    def assign_user(app)
      user = client.get_user('me')&.first
      client.assign_user_to_application_for_sso(app[:id], { id: user[:id]})
    end

    def create_app
      response = client.add_application(
        label: 'Custom SAML via API',
        signOnMode: 'SAML_2_0',
        "visibility": {
          "autoSubmitToolbar": false,
          "hide": {
            "iOS": false,
            "web": false
          }
        },
        "settings": {
          "signOn": {
            "defaultRelayState": "",
            "ssoAcsUrl": identity_provider.acs_url,
            "idpIssuer": "http://www.okta.com/${org.externalKey}",
            "audience": identity_provider.sso_issuer,
            "recipient": identity_provider.acs_url,
            "destination": identity_provider.acs_url,
            "subjectNameIdTemplate": "${user.userName}",
            "subjectNameIdFormat": "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified",
            "responseSigned": true,
            "assertionSigned": true,
            "signatureAlgorithm": "RSA_SHA256",
            "digestAlgorithm": "SHA256",
            "honorForceAuthn": true,
            "authnContextClassRef": "urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport",
            "spIssuer": nil,
            "requestCompressed": false,
            "attributeStatements": [
                {
                    "type": "EXPRESSION",
                    "name": "id",
                    "namespace": "urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified",
                    "values": [
                        "user.id"
                    ]
                },
                {
                    "type": "EXPRESSION",
                    "name": "email",
                    "namespace": "urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified",
                    "values": [
                        "user.email"
                    ]
                }
            ],
            "allowMultipleAcsEndpoints": false,
            "acsEndpoints": []
          }
        }
      )
      Array(response).flatten.first # returns an array for some reason

      rescue => e
        puts e
    end
  end
end