# X API: give your app Read and write, then get new tokens

How to fix a 403 oauth1-permissions error from the X API, step by step in the current Developer Console - set the app to Read and write, then regenerate the OAuth 1.0a access token and secret so they carry the new permission.

You call an X API endpoint that writes, such as posting, and get back `403 Forbidden` with the problem type `oauth1-permissions`. A 403 from X means your credentials are valid but don't have permission for that action [1]. With OAuth 1.0a, the permission lives in two places: the app's setting, and the access token you made under that setting.

**The short version**

1. **The app needs Read and write.** Read only can't post, like or follow [2].
2. **Old tokens keep the old permission.** X says changing permissions "requires users to re-authorize your app to get new tokens with the updated scope" [2]. For your own account, that means pressing Regenerate on the access token after the change.
3. **Regenerating kills the old token.** Copy the new pair at once; X shows it only once [3] [4].
4. **The API key and secret don't change.** Only the access token and secret need regenerating.

> **Not found:** X's docs name the Developer Console, the Apps list, the Keys and tokens tab and the Regenerate button [4] [5], but they don't document every label on the page where you set permissions. The labels in step 2 ("User authentication settings", "Set up" or "Edit", "App permissions") come from the older portal and from community guides [7]. If a label differs, look for the app's settings or authentication section; the three permission levels themselves are documented [2].

*Figure: Four steps: a post returns 403 oauth1-permissions, set the app to Read and write, regenerate the access token and secret, the new pair carries the new permission. The first is red.* A 403 oauth1-permissions error is fixed by setting Read and write, then regenerating the access token.

## Open your app in the Developer Console

**Goal:** Have the right app open in the console, signed in as the account that will post.

- Go to console.x.com and sign in with your X account [3].
- Open **Apps** in the side menu and click the app whose keys you use [4].
- Check who you're signed in as. The access token on the Keys and tokens tab makes requests "on behalf of your own account" [2], the account that owns the app. If that isn't the account you want to post as, the posts will go out from the wrong account.

**Good enough when**

- [ ] The app's name on the page matches the app your program uses.
- [ ] The account in the corner is the one that should post.

## Set the app permission to Read and write

**Goal:** The app's OAuth 1.0a permission reads Read and write.

- On the app's page, find **User authentication settings** and click **Set up** (or **Edit** if it's already set up) [7].
- Under **App permissions**, pick **Read and write**. Pick **Read and write and Direct message** only if your program also sends DMs [2].
- If the form asks for the type of app, pick the one that matches yours; a script that posts for you is an automated app or bot [2].
- If it asks for a **Callback URI** and **Website URL**, they must be filled in to save. For a script that only uses the console's tokens, `http://127.0.0.1` is accepted as a local callback [2], and the website can be your own site [7].
- Click **Save**.

**Good enough when**

- [ ] The app's settings now show Read and write.

## Regenerate the access token and secret

**Goal:** A new access token and secret, made after the permission change.

- Open the **Keys and tokens** tab of the same app [4].
- Find **Access Token and Secret** and click **Regenerate** [5]. Confirm.
- Copy both values straight away. They're shown once, and the old pair stops working now [3].
- Don't regenerate the **API Key and Secret** (the consumer keys). They didn't cause the 403, and regenerating them breaks everything else that uses them [3].
- If the console shows which permission the new token has, it should say Read and write. If it still says Read, the save in step 2 didn't take; go back and save again, then regenerate again.

**Good enough when**

- [ ] You have two new strings: the access token (it starts with your account's number and a dash [6]) and the access token secret.
- [ ] The page says the token was created after you saved Read and write.

## Put the new pair in the env file

**Goal:** Your program reads the new token and secret.

- Open `~/.config/x-api/env`. Replace the values of `X_ACCESS_TOKEN` and `X_ACCESS_TOKEN_SECRET` with the new pair. Leave `X_API_KEY`, `X_API_KEY_SECRET` and `X_BEARER_TOKEN` as they are.
- Keep the file out of git [5].

**Good enough when**

- [ ] Only the two access lines changed.
- [ ] No old token is left anywhere else, such as another env file or a shell profile.

## Check that writing works

**Goal:** The call that returned 403 now succeeds.

- Rerun the exact command that failed. With our tools that's the queued post, for example `x-pull queue-tick <queue.json> --send`, or a dry run first without `--send`.
- A post is public. If you only want to prove the token works, post to a test account, or delete the test post afterwards.

**Good enough when**

- [ ] The response is 201 Created with a post id, not 403.
- [ ] The post shows on the right account.
- [ ] If you still get 403 oauth1-permissions, the token is older than the permission change: do step 3 again.

## Sources

1. X docs, Response codes and errors: 403 means valid auth but no permission for the resource or action. <https://docs.x.com/x-api/fundamentals/response-codes-and-errors>
2. X docs, Apps: the three OAuth 1.0a permission levels, the note that changing permissions needs re-authorization for new tokens, OAuth 2.0 app types and callback URL rules (127.0.0.1 for local). <https://docs.x.com/fundamentals/developer-apps>
3. X docs, Developer Console: console.x.com; keys and tokens are shown once, and regenerating invalidates the old ones. <https://docs.x.com/fundamentals/developer-portal>
4. X docs, API Key and Secret: find or regenerate credentials under Apps, then the app's Keys and tokens tab. <https://docs.x.com/fundamentals/authentication/oauth-1-0a/api-key-and-secret>
5. X docs, Authentication best practices: the Regenerate button beside each set of keys and tokens; keep secrets out of version control. <https://docs.x.com/fundamentals/authentication/guides/authentication-best-practices>
6. X docs, Obtaining access tokens using 3-legged OAuth: access tokens don't expire, and the example token begins with the user's numeric id. <https://docs.x.com/fundamentals/authentication/oauth-1-0a/obtaining-user-access-tokens>
7. X Developer Community thread on User authentication settings (2022, older portal): where App permissions, callback and website URL are set; the website URL is informational. <https://devcommunity.x.com/t/user-authentication-settings/173310>

---

Published 2026-10-18. Web page: https://www.mackenziebowes.com/lessons/x-api-read-and-write-tokens
