⚿
Baleduorg
Authorization & JWT issuance API
Auth flow Parameters OpenAPI spec Try it
OAuth Token service oauth2.1 · v1

Exchange credentials for an access token

Accepts a grant (authorization code, refresh token, or client credentials) and returns a signed JWT access token, scoped to the requesting client, ready to send as a bearer token on subsequent requests.

Authorization code flow

01

Redirect to authorize

App sends the user to /oauth/authorize with client_id, redirect_uri, and requested scope.

02

User grants access

User signs in and approves the requested scopes; the browser is redirected back with a code.

03

Exchange the code

Server calls this endpoint, POST /oauth/token, with the code and client credentials.

04

Receive the JWT

Response includes a signed access token and, optionally, a refresh token for renewal.

Request parameters

Sent as application/x-www-form-urlencoded in the request body.

NameTypeDescription
grant_type
required
string One of authorization_code, refresh_token, or client_credentials.
code
conditional
string The authorization code returned from /oauth/authorize. Required when grant_type is authorization_code.
refresh_token
conditional
string A previously issued refresh token. Required when grant_type is refresh_token.
client_id
required
string Identifier issued when the client application was registered.
client_secret
required
string Confidential secret for the client. Sent only from a trusted backend, never from a browser or mobile app.
redirect_uri
conditional
string Must match the URI used in the original authorize request. Required for the authorization_code grant.
scope
optional
string Space-separated list of scopes to include in the token. Defaults to the scopes already granted.

JWT claims issued

The access_token returned is a JWT signed with RS256. Its payload carries:

ClaimMeaning
issIssuer — the authorization server's URL.
subSubject — the user or client the token represents.
audAudience — the API this token is valid for.
scopeGranted scopes, space-separated.
iat / expIssued-at and expiry, as Unix timestamps.
jtiUnique token identifier, used for revocation lookups.

OpenAPI path definition

This is the exact path object from openapi.yaml — drop it straight into your spec.

openapi.yaml
/oauth/token:
  post:
    summary: Issue an access token
    operationId: issueToken
    tags: [Authorization]
    requestBody:
      required: true
      content:
        application/x-www-form-urlencoded:
          schema:
            type: object
            required: [grant_type, client_id, client_secret]
            properties:
              grant_type:
                type: string
                enum: [authorization_code, refresh_token, client_credentials]
              code:          { type: string }
              refresh_token: { type: string }
              client_id:     { type: string }
              client_secret: { type: string, format: password }
              redirect_uri:   { type: string }
              scope:          { type: string }
    responses:
      '200':
        description: Token issued
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TokenResponse'
      '400':
        description: Invalid grant or malformed request
      '401':
        description: Client authentication failed
curl
JavaScript
Python
request
curl -X POST https://api.baleduorg.com/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d grant_type=authorization_code \
  -d code=AUTH_CODE_FROM_REDIRECT \
  -d redirect_uri=https://app.baleduorg.com/callback \
  -d client_id=YOUR_CLIENT_ID \
  -d client_secret=YOUR_CLIENT_SECRET
const res = await fetch("https://api.baleduorg.com/oauth/token", {
  method: "POST",
  headers: { "Content-Type": "application/x-www-form-urlencoded" },
  body: new URLSearchParams({
    grant_type: "authorization_code",
    code: "AUTH_CODE_FROM_REDIRECT",
    redirect_uri: "https://app.baleduorg.com/callback",
    client_id: "YOUR_CLIENT_ID",
    client_secret: "YOUR_CLIENT_SECRET"
  })
});

const { access_token, expires_in } = await res.json();
import requests

response = requests.post(
    "https://api.baleduorg.com/oauth/token",
    data={
        "grant_type": "authorization_code",
        "code": "AUTH_CODE_FROM_REDIRECT",
        "redirect_uri": "https://app.baleduorg.com/callback",
        "client_id": "YOUR_CLIENT_ID",
        "client_secret": "YOUR_CLIENT_SECRET",
    },
)

token = response.json()["access_token"]
200 success
400 invalid_grant
response
{
  "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "rt_8f2c1a...",
  "scope": "profile orders:read"
}
{
  "error": "invalid_grant",
  "error_description": "The authorization code is expired or was already used."
}

Try it — generate a sample token

Runs entirely in your browser, no network call is made
Generating a 2048-bit RSA keypair in your browser…
Fill in the fields and select generate token.

          

          
Generating…

This demo generates a real 2048-bit RSA keypair with the Web Crypto API, entirely in your browser, and signs each token with genuine RS256 — the signature above is cryptographically valid and will verify against the public key shown, including in third-party tools like jwt.io. What makes this a demo rather than a production issuer is the key's origin and lifetime: it's generated fresh on this page load, its private half never leaves this tab, and it's discarded when you navigate away — so no server, including Baleduorg's, will recognize a token signed by it. A production integration signs with your registered client's key on your backend, where it's provisioned once and kept secret indefinitely, not regenerated per page load.