Written by
Gautam Zalpuri (gzalpuri@us.ibm.com) - Product Management, IBM Cloud Security Services
Enrico Regge (reggeenr@de.ibm.com) - Software Architect @ IBM Cloud Code Engine
----------------------------------
Introduction
As Enterprises increasingly adopt serverless and container based platforms like IBM Cloud Code Engine to modernize and scale operations, they gain scalability and operational simplicity. However, alongside of these benefits comes a critical challenge: securely managing user identities and protecting application access.
For Developers building APIs, microservices, or web applications on Code Engine, implementing authentication and authorization from scratch is complex and error prone. In the Agentic Coding world we are in today a coding agent could implement a login flow - but with it comes the question of ensuring it is secure, compliant and maintaining it. This is where IBM Cloud App ID provides essential and significant value. It offers a fully managed identity and access solution that integrates seamlessly with cloud-native workloads.
Previously we had explored how OIDC can be integrated with Code Engine in this blog. However, there is complexity from the number of things/moving parts that get introduced and require management - the IdP, the configuration, the management of user authorizations etc. This blog explores how App ID secures user identities for applications deployed on Code Engine, and why it should be foundational to your architecture.
The Identity Challenge in Serverless Environments
Code Engine abstracts infrastructure management, allowing developers to focus on code. Developers do have to ensure they consider key security concerns:
- Public endpoints for apps and apis need protection
- User authentication flows (registration, login, password reset, federation with Enterprise or Social Identity Providers) must be implemented
- APIs and microservices must be protected with token based security
- Identity solution must scale with elastic workloads
Without a managed identity service, teams often end up with
- Writing custom authentication logic
- Managing user credentials
- Handling custom implementations of oauth flows
- Managing integrations, deployments and operational lifecycle with unmanaged identity providers
- Maintaining session and token lifecycles
This increases both development and operational overhead and risk.
What is IBM Cloud App ID?
IBM Cloud App ID is a cloud-native identity and access management service designed for application developers. It provides:
- Identity and authentication as-a-service
- Built in OAuth 2.0 and Open ID Connect (OIDC) support
- Multiple identity providers:
- Scalable integrated cloud native directory (Cloud Directory)
- Social login providers (Facebook and Google)
- Enterprise federated identities (SAML 2.0)
- Custom
- Token based access control using JWTs
- User profiles
App ID removes the need to build and operate identity infrastructure, enabling developers to integrate secure authentication with minimal effort.
Why App ID + Code Engine is a Powerful Combination?
Standards based security (OAuth 2.0 + OIDC /SAML)
App ID uses industry standards
- Oauth 2.0 for authorization
- OIDC for authentication
- SAML for Federation with Identity Providers (Enterprise workforce and user directories etc)
Benefits
- Interoperability with modern frameworks
- Easy integration with frontend apps (React, Angular, mobile)
- Compatibility with API gateways and service meshes
For Code Engine microservices, this means stateless, token-based security—ideal for scaling workloads.
Built-in User Management
App ID provides a managed, scalable, cloud-native user directory, eliminating the need to build or integrate one.
- User signup and login flows
- User profiles
- Password policies and password reset
- E-Mail verifcation
- Multi-factor Authentication (MFA)
This is especially valuable for Code Engine apps because:
- You don’t need a separate user database
- You avoid handling sensitive credentials directly
- Identity scales automatically with demand
Secure API Access with JWT Validation
Code Engine applications often expose APIs. App ID enables:
- JWT-based API protection
- Role-based access control (RBAC) via claims
- Token introspection and validation
Example Flow
- Client login via App ID and receives JWT
- Client calls API on Code Engine with bearer token authorization
- API validates signature and claims and grants access
You can implement validation using:
- App ID SDKs
- Standard JWT libraries
- Middleware in Node.js, Python, Java, etc.
Social and Enterprise Identity Federation
App ID allows users to authenticate using:
- Social identities (Google, Facebook)
- Enterprise identity providers (SAML, workforce or user directory SSO)
This is powerful for Code Engine apps that need to:
- Support external users (customers, partners)
- Integrate with enterprise systems
- Avoid managing separate authentication systems
- Want to combine multiple Identity flows without introducing complexity in applications
Reduced Operational Overhead
In a serverless model like Code Engine, operational simplicity is key. App ID complements this by:
- Eliminating identity infrastructure management
- Providing high availability out of the box
- Automatically scaling with usage
This aligns perfectly with the event-driven and elastic nature of Code Engine.
Reference Architecture
In this section will describe the reference architecture to integrate Code Engine and App ID. Similarly like already applied in Part2: Utilize An OIDC Proxy to protect your Code Engine Apps, we’ll front the origin application with a oauth2-proxy application, which takes care of triggering the authentication flow toward App ID.
Install and configure the IBM Cloud CLI
- Install the IBM Cloud CLI including the Code Engine plugin as described in the Code Engine documentation
- Perform all necessary login steps to IBM Cloud
Setup App ID
Create the App ID instance
APPID_REGION=eu-de
APPID_NAME=auth-appid
ibmcloud resource service-instance-create $APPID_NAME appid graduated-tier $APPID_REGION
Obtain the CRN of the App ID instance
APPID_INSTANCE_ID=$(ibmcloud resource service-instance $APPID_NAME --output JSON|jq -r '.[0]|.id')
Create a service credential and setup the authentication config
APPID_CREDS=$(ibmcloud resource service-key-create appid-creds --instance-id $APPID_INSTANCE_ID --output JSON)
APPID_TENANT_ID=$(echo "$APPID_CREDS"|jq -r '.credentials.tenantId')
-
APPID_APP=$(curl -s -X POST "https://$APPID_REGION.appid.cloud.ibm.com/management/v4/${APPID_TENANT_ID}/applications" \
-H "Authorization: $(ibmcloud iam oauth-tokens --output JSON|jq -r '.iam_token')" \
-H "Content-Type: application/json" \
-d "{\"name\": \"my-app\", \"type\":\"regularwebapp\"}")
-
APPID_APP=$(curl -s -X GET "https://$APPID_REGION.appid.cloud.ibm.com/management/v4/${APPID_TENANT_ID}/applications" \
-H "Authorization: $(ibmcloud iam oauth-tokens --output JSON|jq -r '.iam_token')")
APPID_APP_CLIENT_ID=$(echo "$APPID_APP"|jq -r '.applications[0].clientId')
APPID_APP_CLIENT_SECRET=$(echo "$APPID_APP"|jq -r '.applications[0].secret')
APPID_APP_SERVER_URL=$(echo "$APPID_APP"|jq -r '.applications[0].oAuthServerUrl')
APPID_APP_DISCOVERY_ENDPOINT=$(echo "$APPID_APP"|jq -r '.applications[0].discoveryEndpoint')
Deploy A Sample Application
Create or select a Code Engine project
ibmcloud ce project create --name appid-sample or
ibmcloud ce project select --name <yourProjectName>
Obtain some Code Engine project information. We’ll need them later on
CE_DOMAIN=$(ibmcloud ce project current --output json|jq -r '.domain')
CE_PROJECT_NAMESPACE=$(ibmcloud ce project current --output json|jq -r '.kube_config_context')
Furthermore, we’ll define the name of the origin app, as well as the user-facing oauth-proxy application
USER_FACING_APP_NAME=hello
USER_FACING_APP_DOMAIN=${USER_FACING_APP_NAME}.${CE_PROJECT_NAMESPACE}.${CE_DOMAIN}
ORIGIN_APP_NAME=hello-internal
Deploy a sample application; e.g. a simple "Hello World" application provided in the Code Engine samples under https://github.com/IBM/CodeEngine/tree/main/helloworld
ibmcloud ce app create \
--name $ORIGIN_APP_NAME \
--image icr.io/codeengine/helloworld \
--visibility project
Configure OAuth Proxy
With the information provided by the AppID application configuration we have all configuration values at hand, let us create the Code Engine secret:
RANDOM_CHARS=$(dd if=/dev/urandom bs=32 count=1 2>/dev/null | base64 | tr -d -- '\n' | tr -- '+/' '-_' ; echo)
ibmcloud ce secret create \
--name oauth2-oidc-credentials \
--from-literal COOKIE_SECRET=$RANDOM_CHARS \
--from-literal PROVIDER=oidc \
--from-literal CLIENT_ID=$APPID_APP_CLIENT_ID \
--from-literal CLIENT_SECRET=$APPID_APP_CLIENT_SECRET \
--from-literal OIDC_ISSUER_URL=$APPID_APP_SERVER_URL
Also, we’ll create a Code Engine configmap, which controls how the oauth-proxy should function
ibmcloud ce configmap create --name oauth2-config \
--from-literal REDIRECT_URL=https://${USER_FACING_APP_DOMAIN}/oauth2/callback \
--from-literal UPSTREAMS=http://${ORIGIN_APP_NAME}.${CE_PROJECT_NAMESPACE}.svc.cluster.local \
--from-literal SKIP_PROVIDER_BUTTON=true \
--from-literal SSL_UPSTREAM_INSECURE_SKIP_VERIFY=true \
--from-literal PASS_HOST_HEADER=false \
--from-literal PROXY_WEBSOCKETS=true \
--from-literal REVERSE_PROXY=true \
--from-literal EMAIL_DOMAINS="*"
Finally, we’ll create OAuth2 Proxy app and attach the secret and the configmap which both contains configuration properties
ibmcloud ce app create --name $USER_FACING_APP_NAME \
--image quay.io/oauth2-proxy/oauth2-proxy:latest-amd64 \
--port 4180 \
--memory 0.5G \
--cpu 0.25 \
--min-scale 1 \
--env-from-secret OAUTH2_PROXY_=oauth2-oidc-credentials \
--env-from-configmap OAUTH2_PROXY_=oauth2-config
Fix Redirect Configuration
Alright, let us try it out by opening a browser and entering the URL of the
echo "https://$USER_FACING_APP_DOMAIN"
the URL looks someting similar as "https://hello.2b720quhy3zp.eu-de.codeengine.appdomain.cloud".
However, the authentication flow does not work, yet.
The current configuration detects calling users that aren’t authenticated and redirects those users to App ID. However, App ID does reject the request as it requires to properly configure a redirect URL that corresponds to the domain that initiated the login flow. So let us fix this, by configuring the same redirect URL that also had been put into the oauth2-proxy configuration:
curl -s -X PUT "https://$APPID_REGION.appid.cloud.ibm.com/management/v4/${APPID_TENANT_ID}/config/redirect_uris" \
-H "Authorization: $(ibmcloud iam oauth-tokens --output JSON|jq -r '.iam_token')" \
-H "Content-Type: application/json" \
-d "{\"redirectUris\": [\"https://${USER_FACING_APP_DOMAIN}/oauth2/callback\"]}"
Now, let us try it out by calling the same application URL again. Now, the user is redirected to the App ID login page as expected.