# API Specs

## OAuth2

## Start OAuth-style authorization flow

> Initiates the authorization flow. Verifies \`client\_id\`, \`redirect\_uri\`, and optional \`state\`.\
> If valid, redirects to the consent/verification page with a auth\_request\_id for further processing.\
> Partner can then exchange the authorization code for an access token.<br>

```json
{"openapi":"3.0.0","info":{"title":"Very Connect API","version":"1.0.0"},"servers":[{"url":"https://api.very.org/oauth2"},{"url":"http://localhost:3000/oauth2"}],"paths":{"/authorize":{"get":{"tags":["oauth"],"summary":"Start OAuth-style authorization flow","description":"Initiates the authorization flow. Verifies `client_id`, `redirect_uri`, and optional `state`.\nIf valid, redirects to the consent/verification page with a auth_request_id for further processing.\nPartner can then exchange the authorization code for an access token.\n","parameters":[{"name":"response_type","in":"query","required":true,"schema":{"type":"string","enum":["code"]}},{"name":"client_id","in":"query","required":true,"schema":{"type":"string"}},{"name":"redirect_uri","in":"query","required":true,"schema":{"type":"string","format":"uri"}},{"name":"state","in":"query","required":false,"schema":{"type":"string"}},{"name":"nonce","in":"query","required":false,"schema":{"type":"string"}},{"name":"scope","in":"query","required":true,"schema":{"type":"string","pattern":"^openid( offline_access)?$"},"description":"Space-separated list of scopes. Must include \"openid\" for OpenID Connect authentication.\nUse \"offline_access\" to request refresh tokens.\n"}],"responses":{"302":{"description":"Redirects to consent or palm verification UI"},"400":{"$ref":"#/components/responses/Error"},"500":{"$ref":"#/components/responses/Error"}}}}},"components":{"responses":{"Error":{"description":"API Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"string"},"error_description":{"type":"string"}},"required":["error"]}}}}
```

## Exchange authorization code for external user ID

> After successful palm verification, exchanges an authorization \`code\` for the corresponding \`external\_user\_id\`.<br>

```json
{"openapi":"3.0.0","info":{"title":"Very Connect API","version":"1.0.0"},"servers":[{"url":"https://api.very.org/oauth2"},{"url":"http://localhost:3000/oauth2"}],"paths":{"/token":{"post":{"tags":["oauth"],"summary":"Exchange authorization code for external user ID","description":"After successful palm verification, exchanges an authorization `code` for the corresponding `external_user_id`.\n","requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/PostTokenRequest"}}}},"responses":{"200":{"description":"Token response with external user ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PostTokenResponse"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Error"},"500":{"$ref":"#/components/responses/Error"}}}}},"components":{"schemas":{"PostTokenRequest":{"type":"object","properties":{"grant_type":{"type":"string","enum":["authorization_code","refresh_token"],"description":"OAuth 2.0 / OIDC grant type"},"client_id":{"type":"string"},"client_secret":{"type":"string"},"code":{"type":"string","description":"Authorization code (required for authorization_code grant)"},"refresh_token":{"type":"string","description":"Refresh token (required for refresh_token grant)"},"redirect_uri":{"type":"string","format":"uri","description":"Redirect URI (required for authorization_code grant)"}},"required":["grant_type","client_id","client_secret"]},"PostTokenResponse":{"type":"object","properties":{"access_token":{"type":"string","format":"jwt","description":"JWT access token for accessing protected resources. \nThis token should be included in the Authorization header as \"Bearer {access_token}\".\nContains user identity and granted scopes.\n"},"token_type":{"type":"string","enum":["Bearer"],"description":"Token type for OAuth 2.0/OIDC (always \"Bearer\")"},"expires_in":{"type":"integer","description":"Lifetime in seconds of the access token"},"scope":{"type":"string","description":"Space-separated list of granted scopes"},"id_token":{"type":"string","format":"jwt","description":"OIDC ID Token (JWT) **authoritative** user identity.\n• `sub` claim === `external_user_id`  \n• `acr`, `auth_time`, and custom Very claims available for risk checks.\n"},"refresh_token":{"type":"string","format":"jwt","description":"Refresh token for obtaining new access tokens without re-authentication.\nOnly provided when \"offline_access\" scope is granted.\nUse this token with the \"refresh_token\" grant type to get new access tokens.\n"},"refresh_token_expires_in":{"type":"integer","description":"Lifetime in seconds of the refresh token (optional)"}},"required":["access_token","token_type","expires_in","scope","id_token"]},"Error":{"type":"object","properties":{"error":{"type":"string"},"error_description":{"type":"string"}},"required":["error"]}},"responses":{"Error":{"description":"API Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}
```

## Retrieve user profile from Access Token

> Standard OIDC \*\*UserInfo\*\* endpoint.  \
> Returns claims about the subject (\`sub\`) represented by the\
> Bearer Access Token presented in the \`Authorization\` header.\
> \
> • Requires \`scope=openid\`.  \
> • Only returns claims the user originally consented to\
> &#x20; (e.g., \`email\`, \`picture\`)—never private biometric templates.<br>

```json
{"openapi":"3.0.0","info":{"title":"Very Connect API","version":"1.0.0"},"servers":[{"url":"https://api.very.org/oauth2"},{"url":"http://localhost:3000/oauth2"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT"}},"schemas":{"UserInfoResponse":{"type":"object","description":"Returns claims about the subject (`sub`) represented by the access token acquired from the /oauth/token endpoint.","properties":{"sub":{"type":"string","description":"Stable, pairwise identifier for the end user\n(same value as the `sub` claim in the ID Token).\n"}},"required":["sub"]},"Error":{"type":"object","properties":{"error":{"type":"string"},"error_description":{"type":"string"}},"required":["error"]}},"responses":{"Error":{"description":"API Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/userinfo":{"get":{"tags":["oauth"],"summary":"Retrieve user profile from Access Token","description":"Standard OIDC **UserInfo** endpoint.  \nReturns claims about the subject (`sub`) represented by the\nBearer Access Token presented in the `Authorization` header.\n\n• Requires `scope=openid`.  \n• Only returns claims the user originally consented to\n  (e.g., `email`, `picture`)—never private biometric templates.\n","responses":{"200":{"description":"User claims","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserInfoResponse"}}}},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"500":{"$ref":"#/components/responses/Error"}}}}}}
```
