Skip to content

feat: add POST /api/v1/datastore/preauth_offer endpoint#493

Open
leifj wants to merge 6 commits into
SUNET:mainfrom
sirosfoundation:feat/datastore-preauth-offer
Open

feat: add POST /api/v1/datastore/preauth_offer endpoint#493
leifj wants to merge 6 commits into
SUNET:mainfrom
sirosfoundation:feat/datastore-preauth-offer

Conversation

@leifj

@leifj leifj commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Summary

Add a new endpoint POST /api/v1/datastore/preauth_offer that generates a pre-authorized credential offer for a specific document in the datastore.

This restores the capability that was lost when PR #375 removed the old /api/v1/notification endpoint and the QR field from the CompleteDocument model.

Closes #492

What it does

The endpoint accepts {authentic_source, scope, document_id} and:

  1. Looks up the document from the datastore
  2. Generates a credential offer with a pre-authorized code (via openid4vci.NewCredentialOffer)
  3. Creates and persists an authorization context in the cache (5-minute expiry)
  4. Caches the document data for the credential endpoint (keyed by pre-auth code)
  5. Returns the credential offer, a credential_offer_url, and a QR code

Design

This follows the same pre-authorized code flow pattern used by the OIDC (handlers_oidcrp.go) and SAML (endpoints_saml.go) standalone authentication flows, but sources the document data from the datastore instead of from authentication claims.

The wallet can redeem the offer via the standard token + credential endpoints, just as it would for an OIDC/SAML-initiated offer.

Files changed

  • internal/apigw/apiv1/handlers_datastore.go — new handler + request/reply types
  • internal/apigw/httpserver/endpoints_datastore.go — HTTP endpoint wrapper
  • internal/apigw/httpserver/service.go — route registration
  • internal/apigw/httpserver/api.go — interface method
  • internal/apigw/apiv1/handlers_datastore_test.go — unit tests (4 test cases)

Add a new endpoint that generates a pre-authorized credential offer for a
specific document in the datastore. This restores the capability that was
lost when PR SUNET#375 removed the old /api/v1/notification endpoint and the QR
field from the CompleteDocument model.

The endpoint:
1. Looks up the document by (authentic_source, scope, document_id)
2. Generates a credential offer with a pre-authorized code
3. Creates and persists an authorization context in the cache
4. Caches the document data for the credential endpoint
5. Returns the credential offer, credential_offer_url, and a QR code

This follows the same pre-authorized code flow pattern used by the OIDC
and SAML standalone authentication flows, but sources the document data
from the datastore instead of from authentication claims.

Closes SUNET#492
@s-jairl

s-jairl commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Could you make swagger to get the API docs updated as well?

@s-jairl

s-jairl commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

There also seems to be some build errors with the tests:

Error: internal/apigw/httpserver/endpoints_admin_test.go:141:66: cannot use mock (variable of type *adminStatusMock) as Apiv1 value in argument to testSetupAdminStatus: *adminStatusMock does not implement Apiv1 (missing method DatastorePreAuthOffer)

Leif Johansson added 5 commits June 17, 2026 11:09
…ate swagger docs

- Add missing DatastorePreAuthOffer stub to unimplementedApiv1 struct to
  fix build error in admin status tests
- Add pkg/openid4vp to swagger-apigw parse directories so
  openid4vp.QRReply type is resolved
- Regenerate apigw swagger docs
Per reviewer feedback (issue SUNET#492 comment), QR code generation is
unnecessary server-side complexity that clients can handle more flexibly
(custom size, branding, etc).

The endpoint now returns only the credential_offer and credential_offer_url.
Clients can generate QR codes from the URL as needed.
When AuthorizationDetails is set on the AuthorizationContext, the token
endpoint returns authorization_details with credential_identifiers in
the token response. Per OID4VCI spec, this forces the wallet to use
credential_identifier (not credential_configuration_id) in the
credential request. Most wallets use credential_configuration_id for
pre-auth flows, causing a 400 error.

Remove AuthorizationDetails from the pre-auth context. The scope is
already conveyed via the Scopes field, and the credential offer itself
contains the credential_configuration_id.
The credential endpoint dispatches on AuthProvider to retrieve cached
documents. The datastore pre-auth handler was not setting AuthProvider,
causing 'unsupported or missing auth provider' errors when the wallet
redeemed the offer.

Add AuthProviderDatastore constant and set it on the authorization
context. The credential handler now recognizes it alongside the
existing OIDC/SAML/OpenID4VP providers.
The credential endpoint's requireIdentifier check rejected datastore
pre-auth sessions because they don't have an authenticated identifier.
Like assertion-based issuance, datastore issuance sources its data from
pre-uploaded documents, not identity-mapped lookups, so an empty
identifier is valid. Downstream code already guards identifier usage
with != "" checks.
@sonarqubecloud

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Pre-authorized credential offer endpoint missing since API refactoring

2 participants