OpenID Connect · Live on oidc.biatec.io

Identity and a self-custody wallet,
behind one OIDC token.

Biatec OIDC lets your app delegate sign-in to Google or Microsoft and receive a standard OpenID Connect token carrying an Algorand identity — then, with the right scope, use that same token to sign transaction groups against a spending limit the wallet owner controls. Keys stay in the owner's own Google Drive or OneDrive, never on our servers.

RS256
Token signing
5
Scopes, incl. wallet API
2
Identity providers: Google & Microsoft
100%
Self-custody, always
Protocol reference

Standard OIDC, plus a wallet API

Everything below is anchored at https://oidc.biatec.io. Discovery advertises the exact same set.

GET/.well-known/openid-configuration

Discovery document

Standard OIDC discovery metadata — issuer, endpoints, supported scopes/claims, and jwks_uri. Start integration here.

GET/.well-known/jwks.json

JSON Web Key Set

The RS256 public key(s) used to verify tokens issued by this provider. Rotate your cached copy on kid change.

GET/authorize

Authorization endpoint

Standard response_type=code flow with optional PKCE, plus a legacy direct id_token flow. Shows the Google/Microsoft picker unless idp= is set.

POST/token

Token endpoint

grant_type=authorization_code (with PKCE code_verifier) or refresh_token. Confidential clients authenticate with a client secret; public clients rely on PKCE.

GET/userinfo

UserInfo

Claims for the caller's own access token, sent as Authorization: Bearer. Returns primary_seed_address when the user granted storage access.

POST/introspect · /verify

Introspection & verification

RFC 7662-style token introspection. /verify returns the identical shape and also accepts the token via the Authorization header.

GET/connect/endsession

RP-Initiated Logout

Clears the provider session cookie and redirects to an allowlisted post_logout_redirect_uri. Also reachable as /logout.

Authorization model

Scopes, and the claims they grant

Request only what you need. sign and manage-limits are wallet-API scopes — they must be explicitly allowlisted for your client, they are never granted implicitly.

openid

Required for every flow

Establishes the OIDC flow itself. Grants → sub, iss, aud, exp, iat, nonce.

profile

Display identity

Grants → name, preferred_username — a short form derived from the Algorand address when one exists.

email

Verified email

Grants → email, and (when Drive/OneDrive access was granted) primary_seed_address and biatec_idp (which provider backs the wallet).

sign

Sign transactions

Grants → a sign: true claim on the access token. Required to call POST /wallet/sign — see the Wallet API section below.

manage-limits

Manage spending limits

Grants → a manage-limits: true claim on the access token. Required to read or update the wallet owner's own spending limit.

🛡️

Claims are explicit, not inferred. The wallet API never re-parses the space-separated scope claim at request time — each granted wallet scope stamps its own dedicated claim onto the access token when it's issued, and every wallet endpoint checks that exact claim before doing anything.

Self-custody wallet API

Sign transactions, under a limit the owner sets

Every call below requires Authorization: Bearer <access_token> from /token, with the matching scope granted at /authorize.

1Requires the sign scope

The presented access token must carry the sign claim, or the request is rejected with 403 insufficient_scope.

2Build the transaction group

Assemble your Algorand transaction(s) client-side as usual (assign a group id across them if it's more than one), then base64-encode each transaction's msgpack bytes.

3Call the endpoint

curl -X POST https://oidc.biatec.io/wallet/sign \
  -H "Authorization: Bearer <access_token>" \
  -H "Content-Type: application/json" \
  -d '{
    "transactions": ["", ""],
    "accessToken": ""
  }'

accessToken is the wallet owner's current Google/Microsoft access token — it's what lets Biatec OIDC read and decrypt the self-custody account file for this one call. It is never stored.

4Every payment / asset transfer is checked first

Before anything is signed, each pay or axfer transaction in the group is checked against the owner's spending limit. If any one exceeds it, the whole group is rejected with 403 spending_limit_exceeded and nothing is signed — never a partial group.

{
  "signedTransactions": ["", ""]
}

1Requires the manage-limits scope

Reading the limit is gated the same as changing it — a sign-only token cannot call this.

2Call the endpoint

curl https://oidc.biatec.io/wallet/limits \
  -H "Authorization: Bearer <access_token>"
{ "maxAmountPerTransaction": 5000000 }

The limit is in microAlgos for a payment, or base units of the relevant asset for an asset transfer. 0 means unbounded (no limit configured yet).

1Requires the manage-limits scope

Only the wallet owner's own token can change their own limit — there is no way for a client to set a limit on behalf of a different user.

2Call the endpoint

curl -X PUT https://oidc.biatec.io/wallet/limits \
  -H "Authorization: Bearer <access_token>" \
  -H "Content-Type: application/json" \
  -d '{ "maxAmountPerTransaction": 5000000 }'

Applies immediately to every subsequent /wallet/sign call, from any application the owner has authorized — the limit is per wallet owner, not per relying-party app.

Getting started

Register your application

Biatec OIDC is a whitelisted-client provider — every relying party is registered up front with its redirect URIs and allowed scopes.

What you provideNotes
Client typeConfidential (server-side, with a client secret) or public (mobile/desktop/SPA, PKCE required)
Redirect URIsExact or *-wildcard-subdomain allowlist for the authorization code flow
Post-logout redirect URIsWhere RP-Initiated Logout sends the browser back to; falls back to your redirect URIs if omitted
Allowed scopesopenid profile email by default — request sign and/or manage-limits explicitly if your integration needs the wallet API
✉️

Contact Biatec to register a new client and get a client_id/client_secret issued.