# Registrant Auth - OIDC

<figure><img src="/files/31d8KYW3V3CizzQznPRo" alt=""><figcaption></figcaption></figure>

**Step-1 - Widget calls Registry API — /registrant-authentication/start-authentication-transaction**

The Widget is not the component that is the true owner of the authentication-transaction. The true ownership, instead lies with the Registry Server side.

**Step-2 - Start Auth\_Transaction API**

The API receives this call and starts the Authentication Transaction. It creates an Auth-Transaction object.

To create this Auth-Transaction object, the server side relies on some configurations (configuration tables) with values that can be tweaked to suit the implementation specifics.

1. response\_type = code (tells that the exchange is based on an Authorization Code and not tokens) - This can be hardcoded in the Widget
2. client\_id = FARMER\_REGISTRY\_DOA\_SOME\_PROVINCE
3. redirect\_uri = <https://farmer\\_registry.doasp.org/oidc/callback>
4. scope = openid profile

   1. openid (mandatory, confirms OpenID protocol)
   2. profile (requests for basic ID profile)

   The registry ideally should not request for any more claims
5. state = generated random value
   1. the API generates a random value and stores it in memory
   2. the IdP gets this state value in the request
   3. the IdP does not change this value and returns this unchanged value back in the registry callback
   4. <mark style="color:blue;">the registry will validate this value on receiving the callback from IdP, during</mark> <mark style="color:blue;">**Step-8**</mark>
   5. this mechanism is to mitigate CSRF attacks
6. code\_challenge
   1. the API generates a random value (called code\_verifier) and stores it in memory
   2. code\_challenge = BASE64(SHA256(code\_verifier)
   3. <mark style="color:blue;">the IdP will use this code\_challenge in</mark> <mark style="color:blue;">**Step-9**</mark> <mark style="color:blue;">to validate whether the requester is the original owner of the transaction</mark>
   4. This mechanism, called PKCE (Proof Key for Code Exchange), ensures that an authorization code can be redeemed only by the component that initiated the authorization transaction. Even if an authorization code is intercepted, it is unusable without the corresponding proof key (`code_verifier`). PKCE provides a dynamic, per-transaction proof of possession of the authorisation transaction.
7. code\_challenge\_method
   1. S256 - This says the code\_challenge has been created using the SHA-256 algorithm
   2. <mark style="color:blue;">The IDP will use this algorithm to compute the Hash Value of the Code Verifier in</mark> <mark style="color:blue;">**Step-9**</mark>
8. nonce
   1. This is a random String (high entropy, high randomness) generated by this API
   2. The API will store this NONCE
   3. In Step-8, when the Registry receives the token (registry exchanges the authorization\_code for tokens), the registry will unpack the NONCE and validate this NONCE value
   4. This NONCE validation, ensures that a TOKEN is bound to the original STATE (mentioned in Point 5)
9. To support this functionality, the API - **start\_authentication\_transaction** will store the following **Auth\_Transaction** object in REDIS. This object will be addressed (retrievable) by using the **STATE** value as Ke&#x79;**.**

<pre data-full-width="true"><code><strong>AuthTransaction {
</strong>state: "af0ifjsldkj", ## key value for retrieving the object
codeVerifier: "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk", ## IdP uses, to validate ownership of Authorization Code
nonce: "random-opaque-value", ## Registry uses to prevent replay of Tokens
clientId: "FARMER_REGISTRY_DOA_SOME_PROVINCE",
redirectUri: "https://farmer_registry.doasp.org/registrant_authentication/callback",
createdAt: "2026-03-03T06:20:00Z",
expiresAt: "2026-03-03T06:25:00Z",
registrantId: "124a-2utz-1ute-1jdt"
}
</code></pre>

**Step-3 (302 Redirect from OIDC Widget to IdP Authorization Endpoint)**

<pre><code>GET https://idp.example.org/authorize
<strong>?response_type=code
</strong>&#x26;client_id=FARMER_REGISTRY_DOA_SOME_PROVINCE
&#x26;redirect_uri=https://farmer_registry.doasp.org/registrant_authentication/callback
&#x26;scope=openid profile
&#x26;state=af0ifjsldkj
&#x26;code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
&#x26;code_challenge_method=S256
&#x26;nonce=n-0S6_WzA2Mj
</code></pre>

**Step - 4 (Navigate to IdP Authorization endpoint)**

This is handled by the Browser Engine

**Step - 5 (Authenticate Registrant)**

This is handled by the IdP depending on how the ID Authentication mechanism has been configured.

**Step - 6 (Redirect to redirect\_uri)**

This is handled by the IdP, once it establishes the result of Authentication

**Step - 7 (Handle the redirect into redirect\_uri)**

This is handled by the Browser Engine

**Step - 8 (Exchange the Authorization\_Code for Tokens)**

This API is implemented by the Registry. This is the API that is specified in the original request as "redirect\_uri" — <https://farmer\\_registry.doasp.org/registrant\\_authentication/callback>

In this API, the Registry will receive the "Authorization\_Code" and the "State" as URL parameters

```
https://registry.example.org/oidc/callback
?code=SplxlOBeZQQYbYS6WxSbIA
&state=af0ifjsldkj
```

1. Retrieve the Auth\_Transaction using the state
2. Validate existence of State
3. Validate expiry time of the Transaction
4. Use Code\_Verifier and call the IdP to exchange the Authorization\_Code for Token
5. This is a POST request (Server to Server)

**Endpoint**

```
https://idp.example.org/oauth2/token
```

**HTTP Request**

```
POST /oauth2/token HTTP/1.1
Host: idp.example.org
Content-Type: application/x-www-form-urlencoded
Authorization: Basic cmVnaXN0cnktY2xpZW50OnMzY3IzdA==
```

**HTTP Request Body**

```
grant_type=authorization_code
&code=SplxlOBeZQQYbYS6WxSbIA
&redirect_uri=https://farmer_registry.doasp.org/registrant_authentication/callback
&client_id=FARMER_REGISTRY_DOA_SOME_PROVINCE
&code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
```

**Step - 9 (Return the Tokens)**

The IdP validates the code\_verifier (using SHA-256) and returns the Tokens.

**Step - 10 (Validate ID Token and create "Identity-Verification" Context)**

1. Validate the Signature of the Token
2. The Public Keys of the IdP are available at

   ```
   https://idp.example.org/.well-known/jwks.json
   ```

   * Read `kid` from ID token header
   * Select matching key from JWKS
   * Verify the signature using the declared algorithm (`alg`)
3. Validate the following claims

   | Claim   | Validation                                                                      |
   | ------- | ------------------------------------------------------------------------------- |
   | `iss`   | Must match IdP issuer                                                           |
   | `aud`   | Must contain registry client\_id - FARMER\_REGISTRY\_DOA\_SOME\_PROVINCE        |
   | `exp`   | Must be in the future                                                           |
   | `iat`   | Must be reasonable                                                              |
   | `nbf`   | (If present) must be ≤ now                                                      |
   | `nonce` | Must match stored nonce (auth\_transaction.nonce)                               |
   | `sub`   | Must be present and the value should match the auth\_transaction.registrant\_id |
4. Create an "Identity-Verification" context

```
{"identity-verificationId": "VER-2026-00123",
"registrantId": "REG-12345",
"idp": "idp.example.org",
"subject": "00u123abcXYZ",
"verifiedAt": "2026-03-03T08:10:00Z",
"validUntil": "2027-03-03T08:10:00Z",
"assuranceLevel": "strong",
"verificationMethod": "oidc",
"claimsVerified": { "name": true, "date_of_birth": true, "phone": true }
}
```

5. The Register-Record should have a status = "Identity-verified" - BOOLEAN - that should be marked TRUE along with the latest "identity-verificationId"
6. The Identity-Verification Context should be persisted in another table - which has Identity-VerificationId as the Primary Key

**Step - 11 (Return Success Response to Browser)**


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.openg2p.org/products/registry/registry/design/registrant-authentication-oidc-widget.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
