Skip to content

Commit 1e78ce2

Browse files
add oauth2 example
Signed-off-by: F-Node-Karlsruhe <christian.fries@eecc.de>
1 parent e92d257 commit 1e78ce2

9 files changed

Lines changed: 64 additions & 9 deletions

File tree

.cursor/notes/index.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ oid4vp/
1818
│ ├── oid4vp-core/ # Framework-neutral library (artifact: oid4vp)
1919
│ ├── oid4vp-spring/ # Spring Boot auto-configuration
2020
│ └── oid4vp-spring-boot-starter/ # Starter dependency aggregator
21-
├── docs/API_INTEGRATION_ROADMAP.md # Embedding / discovery-service integration plan
2221
├── scripts/release.js
2322
├── CHANGELOG.md
2423
└── README.md
@@ -30,7 +29,7 @@ See [module-layout.md](module-layout.md) for embedding patterns, pluggable depen
3029

3130
- **Presentation request generation** via `Oid4Vp.generatePresentationRequest()`
3231
- **Wallet URL building** with inline or `request_uri` transport
33-
- **Direct post handling** with optional `response_code` (`DirectPostResult`)
32+
- **Direct post handling** with optional `response_code` (`DirectPostResult`) — OAuth2 login completion documented in `README.md`
3433
- **Pluggable** repository and verifier; `Oid4Vp.builder()` for tests and host wiring
3534
- **DCQL query models**, GS1 template, `PresentationParser`, `PresentationClaims` extraction via `PresentationRequestDefinition`, sealed `Oid4VpError`
3635

@@ -47,5 +46,4 @@ Release: `npm run release minor` (from repo root). Version lives in parent `oid4
4746
## Important Files
4847

4948
- `oid4vp-java/oid4vp-core/src/main/java/de/eecc/oid4vc/oid4vp/api/Oid4Vp.java` — main entry point
50-
- `docs/API_INTEGRATION_ROADMAP.md` — full refactor rationale and discovery-service notes
5149
- `CHANGELOG.md` — version history

.cursor/notes/module-layout.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
- `DirectPostHandler``DirectPostResult` — post-verification outcome (`ISSUE_RESPONSE_CODE`, `COMPLETE`, `CUSTOM`)
1818
- `GenerateRequestOptions.builderSupplier` + `beforeSave` — set app fields before `save()`
1919
- `PollStatusResolver` — override poll UX; default handles `response_code`, `completed`, verification errors
20+
- OAuth2 login: `issueResponseCode` → poll or redirect → redeem `state`+`response_code` at token endpoint → `invalidateResponseCode`
2021
- `Oid4VpError` sealed hierarchy — map errors without parsing HTTP status from messages
2122
- `PresentationRequestDefinition.extractPresentationClaims` + `Oid4Vp.extractPresentationClaims` — template-driven claim extraction from stored `vp_token`
2223

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Changed
11+
12+
- Documented OAuth 2.0 login completion via `response_code` in `README.md`
13+
1014
## [0.5.0] - 2026-06-15
1115

1216
### Added

README.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,58 @@ PresentationClaims claims = oid4Vp.extractPresentationClaims(Gs1LicenseRequest.I
9898
List<String> gcps = claims.values();
9999
```
100100

101+
### OAuth 2.0 login completion (`response_code`)
102+
103+
After the wallet delivers a verified presentation via `direct_post`, a one-time `response_code` bridges the
104+
OpenID4VP step to your OAuth 2.0 token endpoint.
105+
106+
**Flow**
107+
108+
1. The wallet POSTs `vp_token` and `state` to your `response_uri`.
109+
2. You call `oid4Vp.processDirectPost(vpToken, state, handler)`; the library verifies presentations and invokes your handler.
110+
3. For login flows, return `DirectPostResult.issueResponseCode()` from the handler. The library stores the verified session and issues a single-use `response_code`.
111+
4. The frontend obtains that code in one of two ways:
112+
- **Wallet redirect** (`redirect(true)`): the wallet redirects the user agent to `redirect_uri#response_code=…`.
113+
- **QR / poll** (`redirect(false)`): the frontend polls `GET …/response/{state}` until it receives `{ "response_code": "…" }` (204 while pending).
114+
5. The frontend exchanges `state` + `response_code` at your OAuth 2.0 token endpoint (for example `POST …/token`).
115+
6. You resolve the stored presentation by `response_code`, validate it matches `state`, extract claims, issue access/refresh tokens, and call `oid4Vp.invalidateResponseCode(request)` so the code cannot be reused.
116+
117+
Non-login flows (for example “add credential without signing in”) can return `DirectPostResult.complete()` instead; polling then returns `{ "completed": true }` with no `response_code`.
118+
119+
**Server-side example** (adapt paths and token issuance to your application):
120+
121+
```java
122+
import com.fasterxml.jackson.databind.JsonNode;
123+
import de.eecc.oid4vc.oid4vp.PresentationClaims;
124+
import de.eecc.oid4vc.oid4vp.VpTokenResponse;
125+
import de.eecc.oid4vc.oid4vp.api.DirectPostResult;
126+
127+
import java.util.Optional;
128+
129+
// Wallet direct_post → POST /api/auth/oid4vp/response
130+
VpTokenResponse.DirectPostResponse directPostResponse =
131+
oid4Vp.processDirectPost(vpToken, state, (LoginPresentationRequest request, JsonNode vpTokenNode) -> {
132+
PresentationClaims claims = oid4Vp.extractPresentationClaims(myDefinition, vpTokenNode);
133+
// persist claims on request if needed for token redemption
134+
return DirectPostResult.issueResponseCode();
135+
});
136+
137+
// QR poll → GET /api/auth/oid4vp/response/{state} (204 until ready)
138+
Optional<VpTokenResponse.PollResponse> poll = oid4Vp.pollPresentationStatus(state);
139+
140+
// Token endpoint → POST /api/auth/oid4vp/token (state + response_code)
141+
LoginPresentationRequest stored = oid4Vp
142+
.findPresentationRequestByResponseCode(responseCode, LoginPresentationRequest.class)
143+
.orElseThrow(() -> new BadRequestException("Unknown or expired response_code"));
144+
if (!stored.getState().equals(state)) {
145+
throw new BadRequestException("response_code does not match state");
146+
}
147+
PresentationClaims claims = oid4Vp.extractPresentationClaims(myDefinition, stored);
148+
TokenResult tokens = issueSessionTokens(claims); // your JWT / OAuth2 issuance
149+
oid4Vp.invalidateResponseCode(stored);
150+
```
151+
152+
101153
Lower-level access: `definition.extractPresentationClaims(vpTokenNode)` or `PresentationParser` for format-specific parsing.
102154

103155
#### Built-in template: GS1 License Presentation

oid4vp-java/oid4vp-core/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<parent>
88
<groupId>de.eecc.oid4vc</groupId>
99
<artifactId>oid4vp-parent</artifactId>
10-
<version>0.5.1-SNAPSHOT</version>
10+
<version>0.5.0</version>
1111
</parent>
1212

1313
<artifactId>oid4vp</artifactId>

oid4vp-java/oid4vp-core/src/main/java/de/eecc/oid4vc/oid4vp/api/GenerateRequestOptions.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@
1616
*
1717
* <pre>{@code
1818
* oid4Vp.generatePresentationRequest(
19-
* GenerateRequestOptions.<DiscoveryPresentationRequest>builder(Gs1LicenseRequest.INSTANCE)
19+
* GenerateRequestOptions.<ExtendedPresentationRequest>builder(Gs1LicenseRequest.INSTANCE)
2020
* .redirect(false)
21-
* .builderSupplier(() -> DiscoveryPresentationRequest.builder()
21+
* .builderSupplier(() -> ExtendedPresentationRequest.builder()
2222
* .purpose(Oid4VpPurpose.ADD_ORG_GCPS)
2323
* .organizationId(orgId))
2424
* .build());

oid4vp-java/oid4vp-spring-boot-starter/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<parent>
88
<groupId>de.eecc.oid4vc</groupId>
99
<artifactId>oid4vp-parent</artifactId>
10-
<version>0.5.1-SNAPSHOT</version>
10+
<version>0.5.0</version>
1111
</parent>
1212

1313
<artifactId>oid4vp-spring-boot-starter</artifactId>

oid4vp-java/oid4vp-spring/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<parent>
88
<groupId>de.eecc.oid4vc</groupId>
99
<artifactId>oid4vp-parent</artifactId>
10-
<version>0.5.1-SNAPSHOT</version>
10+
<version>0.5.0</version>
1111
</parent>
1212

1313
<artifactId>oid4vp-spring</artifactId>

oid4vp-java/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>de.eecc.oid4vc</groupId>
88
<artifactId>oid4vp-parent</artifactId>
9-
<version>0.5.1-SNAPSHOT</version>
9+
<version>0.5.0</version>
1010
<packaging>pom</packaging>
1111

1212
<name>oid4vp-parent</name>

0 commit comments

Comments
 (0)