---
title: "Exchange a code or refresh token for an access token (alias)."
method: POST
path: "/oauth/access_token"
tags: ["OAuth"]
---

# Exchange a code or refresh token for an access token (alias).

`POST /oauth/access_token`

## Request

- Base URL: `https://api.ownerrez.com`
- URL: `https://api.ownerrez.com/oauth/access_token`
- Auth: HTTP basic

Identical to `POST /oauth/token`; both routes run the same handler. New integrations should use `/oauth/token`.

Authenticates the OAuth app itself, not a user: HTTP Basic with your client id as the username and client secret as the password. An account email and Personal Access Token do not work here.

## Request body `application/x-www-form-urlencoded`

- object
  - `grant_type` string: One of authorization_code, refresh_token, token_upgrade, or urn:ietf:params:oauth:grant-type:device_code.
  - `code` string: The authorization code, for grant_type=authorization_code.
  - `redirect_uri` string: The same redirect_uri used to obtain the code.
  - `code_verifier` string: The PKCE verifier, when the authorize request sent a code_challenge.
  - `refresh_token` string: The refresh token (rt_…), for grant_type=refresh_token.
  - `access_token` string: The existing token to convert, for grant_type=token_upgrade.
  - `device_code` string: The device code, for the device-code grant.

## Response `200`

The issued token.

- object
  - `access_token` string: The access token (at_…). Send it as `Authorization: Bearer {token}`.
  - `token_type` string: Always `bearer`.
  - `scope` string: The granted scope: `read` or `full`.
  - `user_id` integer: The OwnerRez account this token acts on.
  - `user_display_name` string: Display name of that account.
  - `refresh_token_supported` boolean: Whether this app's policy issues refresh tokens.
  - `refresh_token` string: The refresh token (rt_…); present when the app's policy supports refresh.
  - `expires_in` integer: Seconds until the access token expires; absent when the token does not expire.
  - `expires_at` string: Expiry timestamp; absent when the token does not expire.

## Other responses

- `400`: The request was rejected. Note the OAuth 2.0 error shape, which differs from the rest of the API.
- `401`: App authentication failed. Body is `{Message}` (ASP.NET HttpError), not the OAuth `{error, error_description}` shape. Missing Basic also sends `WWW-Authenticate: Basic realm=ownerrez_oauthapp`.

## Changes

- **2026-10-01** `838877899156`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/ownerrez/apis/ownerrez-api/changes/oauth/access_token/post.md)

---

[API](https://skmtc.dev/ownerrez/apis/ownerrez-api.md) - [All operations](https://skmtc.dev/ownerrez/apis/ownerrez-api/llms.txt) - [OpenAPI document](https://skmtc.dev/ownerrez/apis/ownerrez-api/revisions/c400448b7a2a?raw)
