All Products
Search
Document Center

Identity as a Service:Integrate SSO by OIDC

Last Updated:Mar 31, 2026

IDaaS uses the OpenID Connect (OIDC) authorization code flow to implement single sign-on (SSO) for your custom applications. Your application interacts with two endpoints — the authorization endpoint and the token endpoint — to complete the full SSO flow. IDaaS hosts the entire authentication process; your application only needs to handle the result.

How it works

The following steps summarize the OIDC authorization code flow between your application, the user's browser, and IDaaS:

  1. Your application redirects the browser to the IDaaS authorization endpoint.

  2. IDaaS presents the sign-in page. The user authenticates.

  3. IDaaS redirects the browser back to your redirect_uri with an authorization code.

  4. Your application exchanges the code for tokens by calling the IDaaS token endpoint.

  5. Your application verifies the ID Token and establishes the user's session.

Note

OIDC 1.0 adds a user identity layer on top of OAuth 2.0 and is backward-compatible with the OAuth 2.0 authorization code flow. The key difference is that the token endpoint also returns an ID Token containing user identity claims.

Prerequisites

Before you begin, ensure that you have:

  • An IDaaS instance

  • A custom application or OIDC-based application created in IDaaS (see Custom applications)

  • The client_id and client_secret for your application (available on the General tab of the Applications page)

Integrate SSO with OIDC

Step 1: Get your application credentials

On the Applications page, click your application and open the General tab. Note the client_id and client_secret — these are required for all subsequent API requests.

To rotate or manage credentials, see General configurations.

Step 2: Send a request to the authorization endpoint

When a user accesses your application without an active session, redirect the browser to the IDaaS authorization endpoint with the following parameters.

Find the authorization endpoint URL on the Applications page: click your application, open the Sign-In tab, and look in the Application Settings section.

Construct the redirect URL as follows:

{{Authorization Endpoint}}?
  client_id=app_***&
  redirect_uri=http%3A%2F%2Flocalhost%3A3000%2F***&
  response_type=code&
  scope=openid&
  state=525f49cc-***
ParameterRequiredExampleDescription
client_idYesapp_michs7r****6pyeThe client ID from the General tab.
scopeYesopenid email profileControls which user attributes are returned. Default for custom applications: openid email profile. OIDC-based applications can also request phone. See Scope and field mapping.
response_typeYescodeMust be code to use the authorization code flow.
redirect_uriYeshttp://localhost:3000/user/oauth2/aliyunidaas/callbackThe URL where IDaaS sends the authorization code after the user signs in.
stateNo (recommended)525f49cc-87c4-4655-b79c-4c4f971b1ad1A random string you generate. IDaaS returns this value unchanged. Use it to verify the response comes from the same session and prevent Cross-Site Request Forgery (CSRF) attacks. Use at least 32 characters.
Important

Always validate the state value when IDaaS redirects back to your application. Reject any response where the returned state does not match the value you sent.

Step 3: Handle the sign-in callback

After the user authenticates, IDaaS performs a 302 redirect to your redirect_uri:

{{redirect_uri}}?
  code=CO***&
  state=525f49cc-***
ParameterExampleDescription
codeCOE59pkCTm4A9nmowJUsfsfarGEaiShj3TuDc7NCzLCYu9The authorization code. Use it in the next step to request tokens.
state525f49cc-87c4-4655-b79c-4c4f971b1ad1Verify this value matches the one you sent in Step 2 before proceeding.

IDaaS supports multiple authentication methods, including DingTalk QR code and SMS. See General configuration for the full list.

Step 4: Exchange the authorization code for tokens

After validating the state value, exchange the authorization code for tokens by sending a POST request to the token endpoint. Find the token endpoint URL in the same Application Settings section as the authorization endpoint.

POST /v2/<instance_id>/<app_id>/oauth2/token HTTP/1.0
Host: eiam-api-cn-hangzhou.aliyuncs.com
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code
  &code=n0esc3N*****5acc3f0ogp4
  &client_id=s6BhdR*****kqt3
  &client_secret=7Fjfp0ZBr1*****KtDRbnfVdmIw
  &redirect_uri=http%3A%2F%2Fwww.example.com%2Fsso%2Fcallback

A successful response contains both an access token and an ID Token:

{
  "token_type": "Bearer",
  "access_token": "ATM4SoVDqWgUq***********wk3ZS5mtn6fcSp8NH8",
  "expires_in": 1200,
  "expires_at": 1644843164,
  "id_token": "eyJraWQiOiJLRVkyV************gRIadj-frOIRFChA"
}
Important

The user attributes available in the tokens are determined by the scope values you requested in Step 2.

To establish the user's session, use one of the following approaches:

Step 5: Parse and verify the ID Token

The ID Token is a JSON Web Token (JWT) signed with RS256. It contains user identity claims in plaintext, plus a Signature that you must verify before trusting the contents.

Important

Signature verification is mandatory. Do not use the claims in an ID Token without first verifying its signature.

To inspect the raw token structure, paste the id_token value into jwt.io. A decoded token looks like this:

{
  "kid": "KEY2Ty1qL6u21NGKmccv3jwfd2ndmgtQPnag",
  "alg": "RS256"
}.{
  "sub": "user_uyvefotjn7kpbejfmxoos3rtmm",
  "jti": "jwt_aaaac7xyhclac6aqkgtjaxsthw5yotn5d77pmki",
  "iss": "https://pre-eiam-api-cn-hangzhou.aliyun-inc.com/v2/********/oidc",
  "iat": 1644841965,
  "nbf": 1644841965,
  "exp": 1644842265,
  "aud": "app_mhylgo3iairjqjdx5eop6uaf34",
  "at_hash": "XHEaGpMooM9zvQXaMzCNEA",
  "name": "testuser",
  "preferred_username": "testuser"
}.[Signature]

Get the public key for signature verification

Before verifying the signature, retrieve the JSON Web Key (JWK) public key from IDaaS. Find the public key endpoint URL in Application Settings (same location as the other endpoints).

Calling the endpoint returns a key set:

{
  "keys": [
    {
      "kty": "RSA",
      "e": "AQAB",
      "use": "sig",
      "kid": "KEYkYnc55G********CTvT7So44RGDYdbfs",
      "n": "pXmYkIpy1vaNjTMclU86BQjfmDhjlqMAX8ySVvh9gO-nae4ayvG_*********-v4gP27T7u6bUy0GXTlh3eKE0v1LYB81nfqjF2uazlPwPR5yYOhhWcK-gMNByLfE3CnkDc1YGwA3dZmIz-ZjOCKy8xLaBuqjrvwn5tpMpAoYEEaH4jIm7unTdhbKEKspNR-UXKD8q9RppMh5Tn2sB6oPHlQANudJDgqSwEOevIrdmHU0Zqxrb9cscGH9hH0QjmYEu72yI8BVeliPo3jK6JIoqCIcj5K_t8BJlFQ9QLJ8_o9tmd3BFv5_LVsh4BKGw"
    }
  ]
}

Verify the signature

Use a JWT library from the jwt.io library list to parse and verify the ID Token. The following example uses the Java library org.bitbucket.b_c:jose4j.

Add the Maven dependency:

<dependency>
  <groupId>org.bitbucket.b_c</groupId>
  <artifactId>jose4j</artifactId>
  <version>0.7.12</version>
</dependency>

Replace issuer, appId, jwkJson, and jwt with the actual values from your IDaaS application before running:

import org.jose4j.jwk.JsonWebKey;
import org.jose4j.jwk.JsonWebKeySet;
import org.jose4j.jwt.JwtClaims;
import org.jose4j.jwt.consumer.JwtConsumer;
import org.jose4j.jwt.consumer.JwtConsumerBuilder;

public class IdTokenTest {

    public static void main(String[] args) throws Exception {
        // EIAM's Issuer identifier (OIDC issuer URL)
        String issuer = "https://eiam-api-cn-hangzhou.aliyuncs.com/v2/idaas_padyrlux3mphrlsex4uonyqhxu/**********/oidc";
        // The unique identifier of the current application (obtained from EIAM)
        String appId = "app_mkif4*****pxpzbasqmu";
        // Application public key in JSON format, used to verify the JWT signature
        String jwkJson = "{\n" + "  \"keys\": [\n" + "    {\n" + "      \"kty\": \"RSA\",\n" + "      \"e\": \"AQAB\",\n" + "      \"use\": \"sig\",\n" + "      \"kid\": \"KEY2H82C2at57itnW4onT3p1ySjwH4nirjCk\",\n" + "      \"n\": \"w7Jl3fAUJp_9GuxV*****QsOA4lnXR5OD4kF4QbIeBiDiH8_MThrFi9k2MB6YMkSzf5JfIkpAS3JCqZ7k6Wooydp4pzaZNZAk3SGzdsa022RmAT" + "-Iayi4Yj6J9tSdTQCjwh2XkzzsIxA_Hla8rWiQ8Vhw1" +
            "-7QArgObfe67nSR7LxD55MFLxk9FU0*****RlGhrQGE_0LUuGWtCJG1r1e6aKquyswfxxAr3Rvj8QGIeJrG0R1Pv8m8d1_5OdULhB7149VqjM6D98WFjab0U2SNv0UlREZXTcS4p-2QNm_1egYRRpJEY_00FZqNSYsmErMGepYhO_61KoGqd8cphWQ\"\n" + "    }\n" + "  ]\n" + "}";
        String jwt = "eyJraWQiOiJLRVkySDgyQzJhdD*****uaXJqQ2siLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJ1c2Vy*****lmNjRjZjR3amFrbnBieGpjd3V1IiwianRpIjoiand0X2FhYWFkYWllYTc2eWg1cW0zcm11bnoyeGg0eHd5aTJzZHBoNjR6aSIsImlzcyI6Imh0dHBzOi8vZWlhbS1hcGktY24taGFuZ3pob3UuYWxpeXVuY3MuY29tL3YyL2lkYWFzX3BhZHlybHV4M21waHJsc2V4NHVvbnlxaHh1L2FwcF9ta2lmNGR3bHBlaDZkbnM0cHhwemJhc3FtdS9vaWRjIiwiaWF0IjoxNjUzNjMwMDQxLCJuYmYiOjE2NTM2MzAwNDEsImV4cCI6MTY1MzYzMDM0MSwiYXVkIjoiYXBwX21raWY0ZHdscGVoNmRuczRweHB6YmFzcW11IiwibmFtZSI6InRlc3QiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJ0ZXN0IiwidXBkYXRlZF9hdCI6MTY1MzYyODU5MH0.pAsUNB8OkdpIxJMZRfLJ7Pa31tsJyl44a1jVIlvdQxwOtPULAwrFxnB0X3eQx89hUGCdvYWl9FO9o-5kT7L-RER0wJYz9YNKqrVNBnaRwINRZyeYLRVurWMMzODQz-V0ULd9raM1M_i2f_SoWFs1gPFtYh_ijUARHISi7Q3q93ZfAuY8Lq2Nq07QunmDbosvioUd5wJG7WCxW5XXZYDUQe9p5IEYd1MSvnWuTOLbg7rKn0Vm4dNYGWjz1WuoAyCsc_QxOCqpmQ_2czoqPeN-SvPJAQ2CykLk7DSnGpABw1aNrjDidLS9Beqsga9VDCth86sk_0lyTZOaORtUrfVTtQ";
        // Parse JWK public key set
        JsonWebKeySet jsonWebKeySet = new JsonWebKeySet(jwkJson);
        // Create JWT validator
        JwtConsumer jwtConsumer = createJwtConsumer(jsonWebKeySet, issuer, appId);
        // Execute signature verification and parse claims
        JwtClaims jwtClaims = jwtConsumer.processToClaims(jwt);
        // Prints the user information from the ID Token
        System.out.println(jwtClaims);
    }

    public static JwtConsumer createJwtConsumer(JsonWebKeySet jsonWebKeySet, String issuer, String appId) {
        // Configure JWT validator using builder pattern
        final JwtConsumerBuilder jwtConsumerBuilder = new JwtConsumerBuilder();
        jwtConsumerBuilder.setExpectedIssuer(issuer);
        jwtConsumerBuilder.setRequireIssuedAt();
        jwtConsumerBuilder.setRequireExpirationTime();
        jwtConsumerBuilder.setAllowedClockSkewInSeconds(60);
        jwtConsumerBuilder.setExpectedAudience(appId);
        // Set public key resolver (match JWK by kid)
        jwtConsumerBuilder.setVerificationKeyResolver((jws, nestingContext) -> {
            // Get kid from JWT header
            final String signKeyId = jws.getKeyIdHeaderValue();
            // Find the matching key in the JWK set
            for (JsonWebKey jsonWebKey : jsonWebKeySet.getJsonWebKeys()) {
                if (signKeyId.equals(jsonWebKey.getKeyId())) {
                    return jsonWebKey.getKey();
                }
            }
            throw new RuntimeException("Cannot find verification key: " + signKeyId);
        });
        return jwtConsumerBuilder.build();
    }
}

A successful run outputs the verified claims:

JWT Claims Set:{sub=user_dt6kj6yf64cf4wjaknpbxjcwuu,
                jti=jwt_aaaadaiea76yh5qm3rmunz2xh4xwyi2sdph64zi,
                iss=https://eiam-api-cn-hangzhou.aliyuncs.com/v2/idaas_padyrlux3mphrlsex4uonyqhxu/app_**********/oidc,
                iat=1653630041,
                nbf=1653630041,
                exp=1653630341,
                aud=app_**********,
                name=test,
                preferred_username=test,
                updated_at=1653628590
               }

Step 6: Get user information from the UserInfo endpoint

As an alternative to parsing the ID Token, use the access token to call the UserInfo endpoint. The endpoint follows RFC6750.

Find the UserInfo endpoint URL in Application Settings.

GET /v2/<instance_id>/<app_id>/oauth2/userinfo HTTP/1.0
Host: eiam-api-cn-hangzhou.aliyuncs.com
Authorization: Bearer <AccessToken>

Sample response:

{
    "sub": "user_dt6kj6yf64cf4wjaknpbxjcwuu",
    "name": "test",
    "preferred_username": "test",
    "updated_at": 1653899948
}
Note

The UserInfo endpoint returns the same fields as the ID Token, including any extended claims configured for the application.

Advanced settings

OIDC discovery endpoint

IDaaS supports the OpenID Connect Discovery 1.0 standard. The Issuer URL for an application uses the following format:

https://<idaas-api-domain>/v2/<instance_id>/<application_id>/oidc
ParameterDescriptionExample
idaas-api-domainUser portal domain******.aliyunidaas.com
instance_idInstance IDidaas_m********r2ed22e6m
application_idApplication IDapp_m********jy6rbau

Append /.well-known/openid-configuration to the Issuer URL to get the discovery endpoint. Calling it returns all available endpoints:

EndpointDescription
authorization_endpointAuthorization endpoint
token_endpointToken endpoint
userinfo_endpointUserInfo endpoint
revocation_endpointToken revocation endpoint
jwks_uriJWK public key endpoint
device_authorization_endpointDevice authorization endpoint (OIDC-based applications only; custom applications do not currently support device code flow login)

All endpoint URLs are also available directly in Application Settings.

Scope and field mapping

The following table shows which ID Token claims are returned for each scope value.

FieldScopeDescription
subopenidUser ID
jtiopenidJWT ID (auxiliary)
issopenidToken issuer (auxiliary)
iatopenidToken issue time (auxiliary)
nbfopenidToken validity start time (auxiliary)
expopenidToken expiration time (auxiliary)
audopenidApplication client ID (auxiliary)
at_hashopenidAccess token hash (auxiliary)
phone_numberphonePhone number, e.g., +86 130****5678
phone_number_verifiedphoneWhether the phone number is verified. Verified by default.
emailemailEmail address, e.g., al***@example.com
email_verifiedemailWhether the email address is verified. Verified by default.
nameprofileDisplay name
preferred_usernameprofileUsername
updated_atprofileLast profile update time

Token endpoint authentication methods

IDaaS supports four authentication methods for the token endpoint, as specified in the token_endpoint_auth_methods_supported field of the discovery endpoint.

MethodDescription
noneFor public clients. Cannot be used with the client_credentials grant type.
client_secret_basicPer RFC 6749.
client_secret_postPer RFC 6749.
client_secret_jwtPer OpenID Connect Core 1.0.

The following example shows a token endpoint request using client_secret_basic:

POST /token HTTP/1.0
Host: api.aliyunidaas.com
Authorization: Basic YXBwX21pY2hzN3I0*******cHllOkNTKioqKioq

grant_type=authorization_code&
code=COE59pkCTm4J*******arGEaiShj7NCzLCYu9

Client secret rotation

See the secret rotation section in General configurations.

What's next

After completing the basic OIDC integration, you may want to:

References