upID documentation
Sign in with upID in your application: start an OIDC request, obtain a verified identity and establish your own session.
Based on the current implementation as of 9 November 2026.
Integration availability
A local pilot with upHome is currently implemented. Arbitrary third-party clients are not yet accepted. This guide describes the current profile and how to prepare an integration; it does not mean your application can already connect to a public service.
id.upturnlab.com is the selected address for the public website. Publishing the website and documentation does not itself enable an OIDC server on that domain. The upID operator must separately confirm the environment, issuer and client approval.
How sign-in works
upID verifies a user's identity through OpenID Connect. Your system remains responsible for its own users, sessions, roles and application permissions. A verified upID sign-in does not automatically assign a role or grant access to your organisation's data.
- Your server creates a one-time sign-in attempt and redirects the browser to upID.
- upID displays a QR code or offers sign-in by phone number. The user approves the request in the upID app on a linked device.
- The browser returns to your callback with a one-time code and state. The client secret and verifier are never sent through the browser.
- Your server exchanges the code for tokens, verifies the ID Token and applies the agreed access policy. It then links the identity to a local user and establishes an application session.
You implement sign-in initiation, the callback and your own session. upID handles QR codes, device approval, phone numbers and account recovery. You do not need to copy its internal mobile APIs into your project.
Before you connect
The current profile is intended for a server-side web application that can keep client_secret out of the browser. Use an OIDC library for your platform; decoding a JWT manually is not a substitute for identity verification.
A new application requires a separate server-side approval step to agree the client, callback and session policy. Client self-registration is not available yet. Creating an arbitrary client_id record does not by itself remove the current pilot's restrictions.
Obtain the following from the upID operator
- The exact HTTPS issuer for the agreed environment. Store it in server-side configuration; do not select it from callback data or the Host header.
- Separate client_id and client_secret values for the application and environment. Keep the secret in a server-side secret store, never in HTML, a frontend bundle, a mobile app or Git.
- A registered HTTPS callback without wildcards or arbitrary return addresses. Use the exact same redirect_uri string in the sign-in request and the code exchange.
- Confirmation of the available scopes, client authentication method, signing algorithm, access-status checks and logout requirements.
Server-side client profile
issuer = OPERATOR_CONFIRMED_HTTPS_ISSUER
client_id = REGISTERED_CLIENT_ID
client_secret = SERVER_SECRET_STORE
redirect_uri = https://app.example.com/auth/upid/callback
response_type = code
scope = openid profile
code_challenge_method = S256
token_endpoint_auth_method = client_secret_basic
id_token_signed_response_alg = RS256
These examples use placeholders, not usable credentials or requests to a production environment. Your OIDC library must construct the actual URLs and parameters. HTTP examples contain line breaks for readability.
Environment and endpoints
Load /.well-known/openid-configuration relative to the agreed issuer. Verify that its issuer field exactly matches your configuration. Read authorization_endpoint, token_endpoint and jwks_uri from verified metadata and check them against the agreed environment; never substitute URLs from user input.
Make server-side requests over HTTPS with certificate and hostname verification enabled. Configure trust for a local environment's certificate separately; do not disable TLS verification to make the connection work.
OpenID Connect Discovery 1.0: provider configuration verification
| Method | Path relative to issuer | Purpose |
|---|---|---|
GET |
/.well-known/openid-configuration |
Provider metadata; connected in the local pilot. |
GET |
/module.php/oidc/authorization |
Browser redirect for sign-in; connected in the local pilot. |
POST |
/module.php/oidc/token |
Server-side code exchange; requires HTTPS, client_secret_basic and an application/x-www-form-urlencoded body. |
GET |
/module.php/oidc/jwks |
Public keys for ID Token signature verification; no client secrets are published here. |
A current implementation detail matters here: the OIDC module generates Discovery and may advertise more capabilities than the server routes expose. A UserInfo, logout or other metadata field does not mean that upID has enabled that capability.
Start sign-in
Generate independent, cryptographically random state, nonce and code_verifier values for each attempt. Bind the attempt to the browser, issuer, client, callback, language and a limited lifetime. Store the original values on the server, then redirect the browser to authorization_endpoint.
PKCE is mandatory even for a confidential client. Compute code_challenge as BASE64URL(SHA256(code_verifier)) without padding. For example, generate a verifier by base64url-encoding 32 random bytes; never use a constant value or reuse an attempt.
RFC 7636: PKCE and the S256 transformation
GET AUTHORIZATION_ENDPOINT_FROM_DISCOVERY?
response_type=code&
client_id=YOUR_CLIENT_ID&
redirect_uri=URL_ENCODED_REGISTERED_CALLBACK&
scope=openid%20profile&
state=ONE_TIME_RANDOM_STATE&
nonce=ONE_TIME_RANDOM_NONCE&
code_challenge=BASE64URL_SHA256_VERIFIER&
code_challenge_method=S256&
ui_locales=az
These examples use placeholders, not usable credentials or requests to a production environment. Your OIDC library must construct the actual URLs and parameters. HTTP examples contain line breaks for readability.
| Parameter | Value or rule |
|---|---|
response_type | Only code: this profile uses Authorization Code Flow. |
client_id | The identifier of a separately approved client. The working profile is currently limited to local upHome. |
redirect_uri | An exact match to the registered HTTPS callback. |
scope | The current request accepts exactly the string openid profile, in that order. The profile scope does not promise a name, email address or phone number in the token. |
state / nonce | Both are required, each at most 128 bytes long; use random base64url strings. state binds the response to the attempt and browser; nonce binds the ID Token to the same sign-in. |
code_challenge / code_challenge_method | A 43-character base64url SHA-256 challenge, with S256 as the only method. plain and requests without PKCE are rejected. |
ui_locales | One of az, ru or en. If omitted or set to another value, the upID interface uses az. |
The current authorization request accepts only the listed parameters, without duplicates or arrays; the query is limited to 4096 bytes. prompt, max_age, claims and request objects are outside this profile. Configure your OIDC library not to add response_mode, prompt or any other undocumented parameters automatically. Open upID through a normal browser redirect; iframe embedding and frontend code exchange are outside this profile.
Handle the callback
Before contacting the token endpoint, match state to an unexpired attempt belonging to this browser. Consume the attempt atomically and only once. An unknown, missing or repeated state must not trigger a code exchange or session creation.
Handle an error response only within a matched attempt. A denial or cancellation does not establish a sign-in. Do not accept access_token, id_token, refresh_token or code_verifier from the callback query; this profile expects code and state or a provider error.
Exchange the code with a server-side POST to token_endpoint. Send the original code_verifier and the same redirect_uri. Use your library's client_secret_basic authentication; the current profile rejects client_secret in the request body and client_assertion.
POST TOKEN_ENDPOINT_FROM_DISCOVERY
Authorization: Basic ENCODED_CLIENT_CREDENTIALS
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&
code=CODE_FROM_CALLBACK&
redirect_uri=URL_ENCODED_REGISTERED_CALLBACK&
code_verifier=ORIGINAL_VERIFIER
These examples use placeholders, not usable credentials or requests to a production environment. Your OIDC library must construct the actual URLs and parameters. HTTP examples contain line breaks for readability.
Do not establish a local sign-in merely because the HTTP response succeeded or contains an access_token: verify the ID Token first. After processing, remove code and state from the visible address by redirecting to a clean internal URL. Select that URL from a server-side allowlist, not from an arbitrary return_to value.
Verify the ID Token
Use your OIDC library's full verifier. The current client profile expects RS256 and signature verification using keys from the verified jwks_uri. Reading the JWT payload or finding a sub claim does not verify an identity.
- Verify the signature and the allowed algorithm. Do not trust an alg value or key URL taken from an unverified token.
- iss must exactly match the configured issuer; aud must include your client_id. Multiple aud values require azp to identify your client; any azp value present must also be checked.
- Check exp and iat according to your library's policy and the agreed clock tolerance. A missing, expired or invalid required claim means the token must be rejected.
- nonce must be present and match the original server-side attempt; sub must be a non-empty string. Use the issuer + sub pair to link the identity to a local user.
OpenID Connect Core 1.0: Authorization Code and ID Token verification
Do not link accounts automatically by phone number, email address or display name. Do not promise profile data solely on the basis of the profile scope. An ID Token is not a general-purpose access token for your product's APIs.
The current pilot also uses the signed upid_correlation claim. This is a private upID extension linking sign-in to access approval, not a standard OIDC claim or a standalone bearer credential. You must not ignore it when reproducing upHome's policy or treat it as an established contract for every external client.
Sessions, access status and logout
After fully verifying the identity and the agreed access conditions, create your own server-side session with a new identifier. Cookies, CSRF protection, lifetimes, roles and access to your resources remain the application's responsibility. Do not store unnecessary tokens in the browser or localStorage.
Local upHome checks access status through a separate server-side upID API, covering the account, device and specific sign-in context. This is not standard OAuth introspection and is not yet available to arbitrary clients. A JWT's remaining lifetime alone does not prove that access is still authorised.
The /api/v1/rp-sessions/status and /close paths check and close an access context; /confirm and /end report a product session. These private APIs require a separately approved client. A confirmed signal does not replace access authorisation; unconfirmed does not prove logout. Agree the external client contract before connecting.
Local upHome caches a positive access decision for no more than 30 seconds from the start of the server request. After that, if upID is unavailable, protected actions are blocked while the local session retains its existing lifetime. This is the current product's policy, not a promise to instantly disable every open page.
Logout from your application ends its local session through a protected action, such as a POST with CSRF protection. It does not mean logout from every product, device revocation or termination of the provider session. RP-initiated and back-channel logout are outside the available upID profile.
Errors and retrying sign-in
Do not mark the user as signed in until identity and access approval are confirmed. Show a clear message and offer a new sign-in attempt. Diagnostics need only an error category and your own non-secret request identifier.
| Signal | Application action |
|---|---|
| state is unknown, expired or already used | Do not exchange the code. Offer a new, explicit sign-in attempt; preserve any existing independent session. |
| User denial / provider error | End only the matched attempt. Do not present a denial as a successful sign-in. |
| invalid_client / invalid_request / invalid_grant | Check client approval, HTTPS, Basic, the exact callback, PKCE and one-time code use. An error is not a reason to weaken validation. |
| ID Token or JWKS verification failed | Do not create a session. Check the environment and configuration; do not fall back to an unsigned or unverified token. |
| 429 / Retry-After | Wait for the specified delay. Do not create an automatic sign-in retry loop. |
| Network failure or an unknown code-exchange result | Do not blindly retry the code: the server may already have consumed it. Start a new sign-in once connectivity is restored; do not destroy an existing independent session. |
Do not write client_secret, code, verifier, tokens, Cookie or the full callback URL to access logs, analytics, error reports or Git. Do not expose raw provider responses or technical exceptions to the user.
What is not available yet
- Self-service onboarding for external clients, Dynamic Client Registration, a general SDK or an established profile for SPAs or native public clients.
- Refresh grant, offline_access, implicit, password and client_credentials are not enabled. The current profile uses only Authorization Code and does not provide a token refresh flow.
- UserInfo and end-session: the module may advertise them in Discovery, but current upID routes do not expose them. Do not rely on them as required steps for sign-in or logout.
- Silent SSO, prompt=none, max_age, request objects and arbitrary claims. The current sign-in requires fresh, explicit approval on a linked device.
- Global logout and general OAuth introspection/revocation APIs are outside the published profile. Production availability, operating requirements and support must be agreed separately.
Before putting an integration into use
- The operator has confirmed your environment, client approval, callback and session policy. Replace the examples with real configuration and keep secrets on the server.
- Manually complete device-approved sign-in, application session creation, local logout and another sign-in.
- User denial, invalid or repeated state, repeated code, an incorrect verifier or callback, and an invalid signature must be rejected without granting new access. Perform these checks in your agreed environment; they are not claimed to have passed here.
- If Discovery, JWKS or the token endpoint is unavailable, or lifetimes expire, the application must not accept an unverified identity; a late callback after logout must not restore the old sign-in.
- Check messages, preservation of the existing session, a clean address after the callback, absence of secrets in logs and sign-in accessibility in the required languages.
Standards
Use an OIDC library to implement the protocol. The primary specifications define the normative exchange and verification rules; this upID implementation is limited to the profile above.
- OpenID Connect Core 1.0: Authorization Code and ID Token verification
- OpenID Connect Discovery 1.0: provider configuration verification
- RFC 7636: PKCE and the S256 transformation
- RFC 9700: current OAuth 2.0 security recommendations