Integrate SSO by OIDC

Updated at:

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-***

Parameter

Required

Example

Description

client_id

Yes

app_michs7r****6pye

The client ID from the General tab.

scope

Yes

openid email profile

Controls 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_type

Yes

code

Must be code to use the authorization code flow.

redirect_uri

Yes

http://localhost:3000/user/oauth2/aliyunidaas/callback

The URL where IDaaS sends the authorization code after the user signs in.

state

No (recommended)

525f49cc-87c4-4655-b79c-4c4f971b1ad1

A 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-***

Parameter

Example

Description

code

COE59pkCTm4A9nmowJUsfsfarGEaiShj3TuDc7NCzLCYu9

The authorization code. Use it in the next step to request tokens.

state

525f49cc-87c4-4655-b79c-4c4f971b1ad1

Verify 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

Parameter

Description

Example

idaas-api-domain

User portal domain

******.aliyunidaas.com

instance_id

Instance ID

idaas_m********r2ed22e6m

application_id

Application ID

app_m********jy6rbau

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

Endpoint

Description

authorization_endpoint

Authorization endpoint

token_endpoint

Token endpoint

userinfo_endpoint

UserInfo endpoint

revocation_endpoint

Token revocation endpoint

jwks_uri

JWK public key endpoint

device_authorization_endpoint

Device 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.

Field

Scope

Description

sub

openid

User ID

jti

openid

JWT ID (auxiliary)

iss

openid

Token issuer (auxiliary)

iat

openid

Token issue time (auxiliary)

nbf

openid

Token validity start time (auxiliary)

exp

openid

Token expiration time (auxiliary)

aud

openid

Application client ID (auxiliary)

at_hash

openid

Access token hash (auxiliary)

phone_number

phone

Phone number, e.g., +86 130****5678

phone_number_verified

phone

Whether the phone number is verified. Verified by default.

email

email

Email address, e.g., al***@example.com

email_verified

email

Whether the email address is verified. Verified by default.

name

profile

Display name

preferred_username

profile

Username

updated_at

profile

Last 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.

Method

Description

none

For public clients. Cannot be used with the client_credentials grant type.

client_secret_basic

Per RFC 6749.

client_secret_post

Per RFC 6749.

client_secret_jwt

Per 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