| 1 | --- |
| 2 | title: Accounts and authentication |
| 3 | description: Accounts, invites, email addresses, confirming them, two-factor authentication and recovery codes, fine-grained and classic personal access tokens, scopes and permissions, a workspace's rules for tokens, OAuth, signing in from a tool, password reset and your security log. |
| 4 | --- |
| 5 | |
| 6 | ## Creating an account |
| 7 | |
| 8 | g1t is invite-only for now: to make an account you need an |
| 9 | [invite](#invites). Open the link in your invite, or enter its code at |
| 10 | [g1t.sh/register](https://g1t.sh/register). Without one, ask for access |
| 11 | on the same page. Usernames are lowercase letters, digits and single |
| 12 | hyphens, up to 39 characters. |
| 13 | |
| 14 | Before you can do anything else, you [confirm your email |
| 15 | address](#confirming-your-email-address) with the code g1t emails you. |
| 16 | |
| 17 | Accounts can only be created in a browser. There is no API for it, by |
| 18 | design: it keeps passwords out of scripts and agents, and lets g1t protect |
| 19 | the one place accounts are made. |
| 20 | |
| 21 | ## Your settings |
| 22 | |
| 23 | Your own settings are at [g1t.sh/settings](https://g1t.sh/settings), one |
| 24 | page each. Open them from your account menu at the bottom of the sidebar, |
| 25 | under **Your settings**; the sidebar then lists every page. |
| 26 | |
| 27 | | Page | Address | What is on it | |
| 28 | | --- | --- | --- | |
| 29 | | Profile | [`/settings/profile`](https://g1t.sh/settings/profile) | Your picture, and your [public profile](/guides/workspaces/#profiles): name, pronouns, bio, location and website. | |
| 30 | | Emails | [`/settings/emails`](https://g1t.sh/settings/emails) | Your [email addresses](#email-addresses), the backup address, and [keeping your address private](#keeping-your-address-private). | |
| 31 | | Invites | [`/settings/invites`](https://g1t.sh/settings/invites) | [Making, copying and revoking invites](#invites). | |
| 32 | | SSH keys | [`/settings/keys`](https://g1t.sh/settings/keys) | Public keys for [git over SSH](/guides/git/#ssh), each with when it was added and last used. | |
| 33 | | Access tokens | [`/settings/tokens`](https://g1t.sh/settings/tokens) | Your [personal access tokens](#access-tokens): fine-grained and classic. | |
| 34 | | GitHub | [`/settings/github`](https://g1t.sh/settings/github) | [Linking and unlinking GitHub](/guides/github/#link-and-unlink-github). | |
| 35 | | Connected applications | [`/settings/applications`](https://g1t.sh/settings/applications) | Tools you [signed in to with OAuth](#signing-in-with-oauth), such as an agent using the MCP server. | |
| 36 | | Two-factor authentication | [`/settings/two-factor`](https://g1t.sh/settings/two-factor) | [An authenticator app and recovery codes](#two-factor-authentication). | |
| 37 | | Security log | [`/settings/security-log`](https://g1t.sh/settings/security-log) | [What happened to your account](#security-log). | |
| 38 | |
| 39 | `g1t.sh/settings` opens Profile. |
| 40 | |
| 41 | ## Signing in with GitHub |
| 42 | |
| 43 | **Continue with GitHub** on the sign-in and sign-up pages signs you in with |
| 44 | your GitHub account, and makes a g1t account the first time. Link or |
| 45 | unlink GitHub in [Settings → GitHub](https://g1t.sh/settings/github). See |
| 46 | [GitHub](/guides/github/#sign-in-with-github). |
| 47 | |
| 48 | Making an account with GitHub needs an invite too: start from your invite |
| 49 | link, or enter the code when g1t asks for it after GitHub. |
| 50 | |
| 51 | With [two-factor authentication](#two-factor-authentication) on, signing in |
| 52 | with GitHub asks for a code from your app as well. |
| 53 | |
| 54 | ## Two-factor authentication |
| 55 | |
| 56 | Two-factor authentication asks for a code from an authenticator app on |
| 57 | your phone each time you sign in with your password or with GitHub, so a |
| 58 | stolen password is not enough. Any app that reads a time-based one-time |
| 59 | password (TOTP) QR code works, such as 1Password, Google Authenticator or |
| 60 | Authy. |
| 61 | |
| 62 | ### Turn it on |
| 63 | |
| 64 | 1. Open [Settings → Two-factor authentication](https://g1t.sh/settings/two-factor) |
| 65 | and choose **Set up**. g1t asks for your password if you have not |
| 66 | signed in in the last 10 minutes. |
| 67 | 2. Scan the QR code with your app, or type the key shown under it. |
| 68 | 3. Enter the six-digit code the app shows, and choose **Turn on**. |
| 69 | 4. Save the ten recovery codes g1t shows. They are shown only then. |
| 70 | |
| 71 | ### Signing in with it on |
| 72 | |
| 73 | After your password (or GitHub), g1t asks for the code from your app. A |
| 74 | code works for 30 seconds, and the one before and after it are accepted |
| 75 | too, for a phone clock a little off. Each code works once. After five wrong |
| 76 | codes, or ten minutes, start the sign-in again. |
| 77 | |
| 78 | Lost your phone? Enter a recovery code instead of the app's code. Each |
| 79 | works once, and your security log records its use. |
| 80 | |
| 81 | Git over HTTPS never takes your password while two-factor authentication |
| 82 | is on: use a [personal access token](#access-tokens) as the password, or |
| 83 | [SSH](/guides/git/). Access tokens, SSH keys and OAuth applications are |
| 84 | not affected. |
| 85 | |
| 86 | ### Recovery codes, and turning it off |
| 87 | |
| 88 | On the same page: |
| 89 | |
| 90 | - **Make new recovery codes** replaces all ten; the old ones stop working. |
| 91 | - **Turn off** needs a code from your app or a recovery code, and your |
| 92 | password if you have not signed in in the last 10 minutes. |
| 93 | |
| 94 | You cannot turn it off while you own a workspace that |
| 95 | [requires it](/guides/workspaces/#require-two-factor-authentication): stop |
| 96 | requiring it there first, or hand the workspace to another owner. In a |
| 97 | workspace that requires it, turning it off holds you out of that workspace |
| 98 | until you turn it on again. |
| 99 | |
| 100 | Turning it on or off, and making new recovery codes, are emailed to your |
| 101 | primary and backup addresses, written to your [security log](#security-log), |
| 102 | and recorded in the [audit log](/guides/audit-log/) of each of your |
| 103 | workspaces as `two_factor.enabled` and `two_factor.disabled`. |
| 104 | |
| 105 | ### Require two-factor authentication |
| 106 | |
| 107 | An owner can require it of everyone with access to a workspace. See |
| 108 | [Workspaces](/guides/workspaces/#require-two-factor-authentication). |
| 109 | |
| 110 | Passkeys are not supported yet; they are next. |
| 111 | |
| 112 | ## Invites |
| 113 | |
| 114 | While g1t is invite-only, every new account needs an invite code, such as |
| 115 | `g1t-k7m2-q9xd-…`. People already on g1t make them, and g1t sends them to |
| 116 | people who [asked for access](#asking-for-access). An invite: |
| 117 | |
| 118 | - works once, for one new account; |
| 119 | - works for 30 days; |
| 120 | - when it was made for an email address, works only with that address; |
| 121 | - can be revoked by whoever made it until it is used, and after that until |
| 122 | the new account [confirms its email address](#confirming-your-email-address). |
| 123 | |
| 124 | ### Using an invite |
| 125 | |
| 126 | Every invite email links to `g1t.sh/invite/<code>`. That one page shows |
| 127 | who sent it and what it is for (joining a workspace, collaborating on a |
| 128 | repository, or just making an account), and finishes the job there: |
| 129 | |
| 130 | 1. **No account yet**: sign up on the page. When the invite was sent to |
| 131 | your address, the email field is filled in and locked. Choose a |
| 132 | username (one is suggested from your address) and a password, then |
| 133 | [confirm the address](#confirming-your-email-address) with the code g1t |
| 134 | emails it, even though the invite came there: an invite link can be |
| 135 | forwarded, so it does not prove the inbox is yours. Or select |
| 136 | **Continue with GitHub**: the invite rides along, and the account uses |
| 137 | the invited address when GitHub has verified it too, in which case no |
| 138 | confirmation is needed. |
| 139 | 2. **The address already has an account**: select **Sign in to accept**. |
| 140 | After you sign in, the invite is accepted for you. |
| 141 | 3. **Signed in as someone else**: an invite sent to one address works only |
| 142 | for an account that has confirmed that address. The page says so and |
| 143 | offers **Sign out and continue**. |
| 144 | |
| 145 | Once you have signed in, or your new account has confirmed its address, |
| 146 | you land in the workspace (or the repository) the invite was for, already |
| 147 | a member, with a one-time "You're in" banner, and it becomes the workspace |
| 148 | your sidebar shows. |
| 149 | |
| 150 | Signing up spends the invite at once, so nobody else can use it while you |
| 151 | confirm your address, but you join its workspace only when you confirm, in |
| 152 | the same step. Until then the invite shows as **confirming their email** to |
| 153 | whoever made it, and they can still revoke it. If the invite is revoked or |
| 154 | expires, or its workspace is deleted, before you confirm, your address is |
| 155 | confirmed all the same and g1t tells you the invite no longer applies: ask |
| 156 | whoever invited you to add you again. A |
| 157 | code typed at [g1t.sh/register](https://g1t.sh/register) goes to the |
| 158 | same page. |
| 159 | |
| 160 | An expired, revoked or used invite says which, and who sent it, so you |
| 161 | can ask them for a new one; or ask for access from the same page. |
| 162 | |
| 163 | ### Making invites |
| 164 | |
| 165 | 1. Open [Settings → Invites](https://g1t.sh/settings/invites). |
| 166 | 2. Optionally enter the email address of the person you are inviting. |
| 167 | With one, g1t emails them the invite, and only that address can use it. |
| 168 | Without one, anyone with the link can, once. |
| 169 | 3. Select **Create invite**, then copy the link. |
| 170 | |
| 171 | Each person can have **5** invites out at a time. Pending and used invites |
| 172 | count; an invite you revoke, or one that expires before anyone uses it, |
| 173 | comes back to you. The list under the form shows each invite's state: |
| 174 | pending, confirming their email (used to sign up by someone who has not |
| 175 | confirmed their address yet), joined (with the username of who joined), |
| 176 | expired or revoked. You |
| 177 | must confirm your email before you can make invites. An agent's token and |
| 178 | a workspace's token cannot make them. |
| 179 | |
| 180 | ### Inviting someone into a workspace |
| 181 | |
| 182 | An owner can invite an email address straight into a workspace from its |
| 183 | People page; see [members and roles](/guides/workspaces/#members-and-roles). |
| 184 | When the address has no g1t account, the invite makes the account, which |
| 185 | joins the workspace once it confirms its email address, and it uses one |
| 186 | invite. Inviting someone who is |
| 187 | already on g1t costs nothing. |
| 188 | |
| 189 | ### Need more invites? |
| 190 | |
| 191 | Write to [hey@flagon.io](mailto:hey@flagon.io?subject=%5Bg1t%20Invites%5D%20) |
| 192 | with the subject `[g1t Invites]` and say who you would like to bring. g1t |
| 193 | can give more invites to you, or to a workspace, whose owners then share |
| 194 | them. Invites given to a workspace appear under |
| 195 | [Settings → Invites](https://g1t.sh/settings/invites) for |
| 196 | each of its owners, as a choice of whose invites to use. |
| 197 | |
| 198 | ### Asking for access |
| 199 | |
| 200 | Without an invite, [g1t.sh/register](https://g1t.sh/register) asks for your |
| 201 | email address and, if you like, what you will build. g1t emails that |
| 202 | address once to confirm you are on the list, and staff see the request |
| 203 | straight away. When they approve it, the invite comes to the same address, |
| 204 | sometimes with a note, and its link opens sign-up with the address filled |
| 205 | in. There is no fixed date: g1t opens up a few people at a time. Asking |
| 206 | again with the same address updates your request without another email; it |
| 207 | does not move you down the list. |
| 208 | |
| 209 | ### Invites through the API |
| 210 | |
| 211 | | Route | MCP tool and action | What it does | |
| 212 | | --- | --- | --- | |
| 213 | | [`GET /user/invites`](/reference/api/invites/list-invites/) | `account` `list_invites` | Your invites and how many you have left | |
| 214 | | [`POST /user/invites`](/reference/api/invites/create-invite/) | `account` `create_invite` | Make an invite, optionally for one `email` | |
| 215 | | [`DELETE /user/invites/{id}`](/reference/api/invites/revoke-invite/) | `account` `revoke_invite` | Revoke a pending invite, or one whose new account has not confirmed its address | |
| 216 | | [`POST /workspaces/{workspace}/invitations`](/reference/api/invites/invite-member/) | `workspace` `invite_member` | Invite an address into a workspace. Owners only. | |
| 217 | |
| 218 | ## Confirming your email address |
| 219 | |
| 220 | A new account confirms its email address before it can do anything else on |
| 221 | g1t. Right after you sign up, g1t emails the address from `noreply@g1t.sh` |
| 222 | with two ways to confirm it, either one enough: |
| 223 | |
| 224 | - a **six-digit code**, shown large in the email (and in its subject, so a |
| 225 | phone's notification shows it). Type it on the **Confirm your email** |
| 226 | page g1t takes you to. On a phone, the keyboard offers it from the |
| 227 | message. |
| 228 | - a **link**, for when you would rather click than type. It works whether |
| 229 | or not you are signed in, in any browser. |
| 230 | |
| 231 | The code and the link work for **60 minutes**, once. Using either ends the |
| 232 | other. **Send a new code** on the confirmation page sends a fresh code and |
| 233 | link, at most once a minute and 10 times an hour, and the ones before stop |
| 234 | working. |
| 235 | |
| 236 | | On the confirmation page | What it does | |
| 237 | | --- | --- | |
| 238 | | **Confirm email** | Checks the code. A wrong, used or expired code gets the same answer. After 10 wrong codes in an hour, codes for the account are not checked for a while (a minute, then longer); the link in the email still works. Wrong codes from one network are limited the same way. | |
| 239 | | **Send a new code** | A new code and link; the ones before stop working. | |
| 240 | | **Wrong address? Change it** | Replaces the address you signed up with and sends the new one a code. Only while the account has no confirmed address. | |
| 241 | | **Sign out** | Signs out. Sign in again to come back to the page. | |
| 242 | |
| 243 | ### Until you confirm |
| 244 | |
| 245 | An account that has not confirmed its address can only confirm it: |
| 246 | |
| 247 | - **The site** sends every page to the confirmation page, and back to where |
| 248 | you were going once you confirm. Signing in and out, password resets, |
| 249 | the confirmation link, and g1t's [policies](https://g1t.sh/policies), |
| 250 | security, support, status and pricing pages stay open. |
| 251 | - **The API** answers `403` with a message saying to confirm your address, |
| 252 | except for [`GET /user`](/reference/api/accounts/whoami/), |
| 253 | [`GET /user/emails`](/reference/api/accounts/list-emails/) and |
| 254 | [`POST /user/emails/confirm`](/reference/api/accounts/confirm-email/). |
| 255 | - **The MCP server** answers `403` with the same message. |
| 256 | - **Git** over HTTPS refuses pushes and fetches with your credentials, with |
| 257 | the same message. Package registries treat them as wrong credentials. |
| 258 | - You cannot create a workspace, join the one your invite named, make |
| 259 | invites or tokens, or approve a tool's sign-in. |
| 260 | |
| 261 | You cannot make a token before you confirm, so the API and MCP refusals |
| 262 | matter only for an account that made one before this rule existed. |
| 263 | |
| 264 | ### Addresses GitHub has confirmed |
| 265 | |
| 266 | An account made with **Continue with GitHub** starts confirmed: its address |
| 267 | is one GitHub has verified, so GitHub has already proved the inbox is |
| 268 | yours, and no code is sent. |
| 269 | |
| 270 | ### Accounts that never confirmed |
| 271 | |
| 272 | Accounts are confirmed once and stay confirmed. An account made before this |
| 273 | rule that never confirmed its address, or whose address another account |
| 274 | confirmed first, is held at the confirmation page the same way the next |
| 275 | time it signs in; **Send a new code** gets it a code, and **Change it** |
| 276 | gives it a new address. |
| 277 | |
| 278 | ### Confirming through the API |
| 279 | |
| 280 | | Route | MCP tool and action | What it does | |
| 281 | | --- | --- | --- | |
| 282 | | [`POST /user/emails/confirm`](/reference/api/accounts/confirm-email/) | `account` `confirm_email` | Confirm an address with the `code` from its email | |
| 283 | |
| 284 | The answer says whether the account is now confirmed (`verified`), the |
| 285 | workspace confirming joined it to (`joined`), or why its invite no longer |
| 286 | applies (`invite_lapsed`). |
| 287 | |
| 288 | ## Email addresses |
| 289 | |
| 290 | An account can have up to 10 email addresses. Manage them in |
| 291 | [Settings → Emails](https://g1t.sh/settings/emails). |
| 292 | |
| 293 | | An address that is | Can | |
| 294 | | --- | --- | |
| 295 | | Primary | Get account mail and password reset links. Exactly one, always confirmed once any address is. | |
| 296 | | Confirmed | Sign you in (type it instead of your username), ask for a password reset, and mark commits that carry it as yours. | |
| 297 | | Backup | Get security notices as well as the primary. Optional, and a confirmed address other than the primary. | |
| 298 | | Unconfirmed | Nothing yet. It is not yours until you enter the code or follow the link g1t sent it. | |
| 299 | |
| 300 | A confirmed address belongs to one account. Anyone can add an address they |
| 301 | have not confirmed; the first account to confirm it keeps it, and the |
| 302 | address leaves every other account that added it. An address another |
| 303 | account has confirmed cannot be added. |
| 304 | |
| 305 | ### Add an address |
| 306 | |
| 307 | 1. Open [Settings → Emails](https://g1t.sh/settings/emails). |
| 308 | 2. Enter the address under **Add an email address** and select **Add**. |
| 309 | 3. Enter the code g1t emails it, or follow the link in the same email. |
| 310 | Both work for 60 minutes; **Resend link** sends a new code and link, at |
| 311 | most once a minute and 10 times an hour, and ends the ones before. |
| 312 | |
| 313 | If your account had no confirmed address yet, the first one you confirm |
| 314 | becomes your primary. |
| 315 | |
| 316 | ### Choose your primary and backup |
| 317 | |
| 318 | Select **Make primary** beside a confirmed address. Under **Backup |
| 319 | address**, choose a confirmed address to get security notices too, or |
| 320 | **Primary address only**. |
| 321 | |
| 322 | ### Remove an address |
| 323 | |
| 324 | Select **Remove** beside it. You cannot remove your primary address (make |
| 325 | another one primary first) or your last confirmed address. |
| 326 | |
| 327 | ### Confirming it is you |
| 328 | |
| 329 | Adding or removing an address, changing your primary or backup, and |
| 330 | turning two-factor authentication on or off, need proof that it is you: a |
| 331 | sign-in in the last 10 minutes, or your password, |
| 332 | which g1t asks for on the page. After you enter it, g1t does not ask again |
| 333 | for 10 minutes. An account that signs in only with GitHub signs out and in |
| 334 | with GitHub again, or sets a password with |
| 335 | [Forgot your password](https://g1t.sh/forgot). |
| 336 | |
| 337 | Each of these changes is emailed to every confirmed address on the account, |
| 338 | including an address that was just removed, and written to your |
| 339 | [security log](#security-log). |
| 340 | |
| 341 | ### Keeping your address private |
| 342 | |
| 343 | **Keep my email address private** is on for every account unless you turn |
| 344 | it off. While it is on, commits g1t makes for you (merging a pull request |
| 345 | on the web, catching a branch up, and commits an agent makes for you) carry |
| 346 | your noreply address instead of your primary: |
| 347 | |
| 348 | ``` |
| 349 | <8 characters of your account id>+<username>@users.noreply.g1t.sh |
| 350 | ``` |
| 351 | |
| 352 | The page shows yours. It never receives mail. Turn the setting off to put |
| 353 | your primary address on those commits instead. |
| 354 | |
| 355 | **Block pushes that expose my email** refuses a push that would publish one |
| 356 | of your addresses while you keep it private. When both settings are on, |
| 357 | g1t reads the new commits in each push you make, and declines the push if |
| 358 | any of them has one of your confirmed addresses as its author or committer |
| 359 | address. git shows why, with the address masked: |
| 360 | |
| 361 | ``` |
| 362 | remote: push declined: commit 3f9a1c2 would publish s***@gmail.com while your email is private. |
| 363 | remote: Commit with 6c1d0efg+sam@users.noreply.g1t.sh (git config user.email 6c1d0efg+sam@users.noreply.g1t.sh) and amend, |
| 364 | remote: or change this in g1t.sh/settings/emails. |
| 365 | ``` |
| 366 | |
| 367 | To push those commits: |
| 368 | |
| 369 | 1. Set your noreply address for the repository: |
| 370 | `git config user.email <your noreply address>`. |
| 371 | 2. Rewrite the commits with it. For the last commit, |
| 372 | `git commit --amend --reset-author --no-edit`; for several, |
| 373 | `git rebase <base> --exec "git commit --amend --reset-author --no-edit"`. |
| 374 | 3. Push again. |
| 375 | |
| 376 | Only your own addresses are checked: commits by other people in the same |
| 377 | push go through, and so does your noreply address. A push an agent makes |
| 378 | for you follows your settings. |
| 379 | |
| 380 | ### How commits are attributed |
| 381 | |
| 382 | g1t shows a commit as yours, with your picture and a link to your profile, |
| 383 | when its author address is one of your confirmed addresses or your noreply |
| 384 | address. Commits that g1t made for you before noreply addresses existed |
| 385 | (`<username>@users.g1t.sh`) count as yours too. An unconfirmed address |
| 386 | never attributes a commit, so nobody can claim your commits by adding your |
| 387 | address. Commits whose address matches no account show the name in the |
| 388 | commit. |
| 389 | |
| 390 | ### Email addresses through the API |
| 391 | |
| 392 | | Route | MCP tool and action | What it does | |
| 393 | | --- | --- | --- | |
| 394 | | [`GET /user/emails`](/reference/api/accounts/list-emails/) | `account` `list_emails` | Your addresses and email settings | |
| 395 | | [`POST /user/emails`](/reference/api/accounts/add-email/) | `account` `add_email` | Add an address; takes `email` and `password` | |
| 396 | | [`POST /user/emails/confirm`](/reference/api/accounts/confirm-email/) | `account` `confirm_email` | Confirm an address with the `code` from its email | |
| 397 | | [`DELETE /user/emails/{email}`](/reference/api/accounts/remove-email/) | `account` `remove_email` | Remove an address; takes `password` | |
| 398 | | [`PATCH /user/email-settings`](/reference/api/accounts/update-email-settings/) | `account` `update_email_settings` | Change `primary`, `backup`, `private_email` or `block_private_pushes` | |
| 399 | |
| 400 | Through the API, `password` is the proof a sensitive change needs. Without |
| 401 | it, or with the wrong one, the answer is `403` with the code |
| 402 | `reauth_required`. Only a person's own token can use these: an agent's |
| 403 | token and a workspace's token are refused. |
| 404 | |
| 405 | ## Workspaces |
| 406 | |
| 407 | Your account does not own repositories itself: a workspace does. After |
| 408 | confirming your email, the first thing you do is create one. Workspaces, |
| 409 | their members and roles, and the access tokens that belong to a workspace |
| 410 | are covered in [workspaces](/guides/workspaces/). |
| 411 | |
| 412 | ## Access tokens |
| 413 | |
| 414 | A token stands in for your password everywhere outside the website: |
| 415 | |
| 416 | | Where | How to send it | |
| 417 | | --- | --- | |
| 418 | | git | As the password, with your username. | |
| 419 | | API | `Authorization: Bearer g1t_…` | |
| 420 | | MCP | The same header, set when you add the server. | |
| 421 | |
| 422 | A token is shown once, when it is created; g1t stores only a hash of it. |
| 423 | If you lose one, delete it and create another. Delete a token the moment |
| 424 | you think someone else has seen it. |
| 425 | |
| 426 | There are two kinds of personal access token, on two tabs of |
| 427 | [Settings → Access tokens](https://g1t.sh/settings/tokens): |
| 428 | |
| 429 | | | Fine-grained token | Classic token | |
| 430 | | --- | --- | --- | |
| 431 | | Reaches | One resource owner: one workspace you belong to, or your own account | Every workspace and repository you can reach, including ones you join later | |
| 432 | | Repositories | All of the workspace's, the ones you choose (up to 50), or public ones only | All you can reach | |
| 433 | | What it may do | A level for each [permission](#permissions) | Its [scopes](#scopes) | |
| 434 | | Expires | Always, within 366 days | 7 days to 1 year, or never | |
| 435 | | A workspace can | Require an owner's approval first, or keep them out | Keep them out | |
| 436 | |
| 437 | Both never do more than you could on the website, and both are sent the |
| 438 | same way. Prefer a fine-grained token: it reaches only what it needs. |
| 439 | |
| 440 | For CI and integrations that work for a team, a workspace can have tokens |
| 441 | of its own that act as the workspace and keep working when their creator |
| 442 | leaves. See [workspace tokens](#workspace-tokens). |
| 443 | |
| 444 | ### Create a fine-grained token |
| 445 | |
| 446 | 1. Open [Settings → Access tokens](https://g1t.sh/settings/tokens). The |
| 447 | **Fine-grained tokens** tab is first. |
| 448 | 2. Under **New fine-grained token**, give it a **Token name** after what |
| 449 | will use it, and optionally a **Description**, which a workspace's |
| 450 | owners see if they review it. |
| 451 | 3. Choose the **Resource owner**: a workspace you belong to, or **Your |
| 452 | account**. A workspace that does not allow fine-grained tokens cannot be |
| 453 | chosen. |
| 454 | 4. Choose its **Expiration**: 7, 30, 60, 90 or 180 days, or 1 year, or |
| 455 | less when the workspace sets a shorter limit. |
| 456 | 5. Under **Repository access**, choose **Public repositories** (read-only), |
| 457 | **All repositories** of the workspace (including ones made later), or |
| 458 | **Only select repositories**, and tick up to 50. |
| 459 | 6. Under **Permissions**, set each one the token needs to **Read-only** or |
| 460 | **Read and write** (and **Admin** for packages). **Metadata** is always |
| 461 | read-only. Each row shows the g1t scopes its level gives. |
| 462 | 7. Select **Generate token**, and copy it. It is not shown again. |
| 463 | |
| 464 | When the workspace [requires approval](#a-workspaces-rules-for-tokens) and |
| 465 | you are not one of its owners, the token is made **Pending approval**: it |
| 466 | works at once, but reads public repositories only until an owner approves |
| 467 | it. The owners hear of it in their [inbox](/guides/inbox/), and you hear of |
| 468 | their answer in yours. An owner's own token never waits. |
| 469 | |
| 470 | Select **Edit** on a token to change its name, description, repositories |
| 471 | or permissions. The token stays the same. Widening it in a workspace that |
| 472 | requires approval asks again. Its resource owner and expiry cannot change; |
| 473 | make a new token instead. |
| 474 | |
| 475 | The list shows each token's status (pending, denied or revoked, with the |
| 476 | owner's note), what it reaches, its permissions, and when it was made, last |
| 477 | used and expires. |
| 478 | |
| 479 | ### Permissions |
| 480 | |
| 481 | Each level of a fine-grained token's permissions gives g1t |
| 482 | [scopes](#scopes), and the token is checked by those scopes |
| 483 | exactly as a classic token is. Where two permissions give the same scopes |
| 484 | (Checks and Commit statuses; Secrets and Variables; Deployments and Pages), |
| 485 | giving either gives both. |
| 486 | |
| 487 | Repository permissions, for a workspace as the resource owner: |
| 488 | |
| 489 | | Permission | Levels | What it covers | g1t scopes it gives | |
| 490 | | --- | --- | --- | --- | |
| 491 | | `actions` (Actions) | read, write | Workflow runs, jobs, logs and artifacts: reading them, and running, cancelling and rerunning workflows | read: `workflows:read`; write: `workflows:write` | |
| 492 | | `administration` (Administration) | read, write | Repository settings, rulesets, who has access and deploy keys; renaming, archiving, transferring and deleting | read: `repo:read`, `access:read`; write: `repo:admin`, `access:admin` | |
| 493 | | `agents` (g1t agents) | write | Putting g1t's agents to work and messaging them, which uses the workspace's money | write: `agents:run` | |
| 494 | | `checks` (Checks) | read, write | Check runs and check suites on commits. Shares its scopes with Commit statuses | read: `checks:read`; write: `checks:write` | |
| 495 | | `contents` (Contents) | read, write | Code, branches, commits and releases: cloning and fetching, pushing, and publishing releases | read: `code:read`; write: `code:write`, `repo:write` | |
| 496 | | `deployments` (Deployments) | read, write | Deployments and their statuses | read: `deployments:read`; write: `deployments:write` | |
| 497 | | `environments` (Environments) | read, write | Environments, and their secrets and variables | read: `deployments:read`, `secrets:read`; write: `secrets:admin` | |
| 498 | | `issues` (Issues) | read, write | Issues, their comments, labels and milestones, and plans | read: `issues:read`; write: `issues:write` | |
| 499 | | `memory` (Memory and context) | read, write | Recalling memory and searching the workspace's context, and saving memory for the next agent | read: `memory:read`; write: `memory:write` | |
| 500 | | `metadata` (Metadata) | read | Seeing repositories and searching them. Always read | read: `repo:read` | |
| 501 | | `packages` (Packages) | read, write, admin | Pulling private packages, publishing them, and (admin) deleting packages and versions | read: `packages:read`; write: `packages:write`; admin: `packages:delete` | |
| 502 | | `pages` (Pages) | read, write | Deployments on g1t.page. Shares its scopes with Deployments | read: `deployments:read`; write: `deployments:write` | |
| 503 | | `pull_requests` (Pull requests) | read, write | Pull requests, their reviews, changes, sessions and merge queues | read: `pull_requests:read`; write: `pull_requests:write` | |
| 504 | | `secrets` (Secrets) | read, write | Actions secrets: listing them (never their values), setting and deleting them. Shares its scopes with Variables | read: `secrets:read`; write: `secrets:admin` | |
| 505 | | `security_events` (Security events and alerts) | read, write | Code scanning, secret scanning and vulnerability alerts, SARIF uploads and security settings | read: `security:read`; write: `security:write` | |
| 506 | | `statuses` (Commit statuses) | read, write | Statuses on commits. Shares its scopes with Checks | read: `checks:read`; write: `checks:write` | |
| 507 | | `variables` (Variables) | read, write | Actions variables: reading, setting and deleting them. Shares its scopes with Secrets | read: `secrets:read`; write: `secrets:admin` | |
| 508 | | `webhooks` (Webhooks) | read, write | Webhooks and their deliveries | read: `webhooks:read`; write: `webhooks:admin` | |
| 509 | | `workflows` (Workflows) | write | Adding, changing and deleting workflow files under .g1t/workflows and .github/workflows. Write only | write: `workflow_files:write` | |
| 510 | |
| 511 | Workspace permissions, for a workspace as the resource owner: |
| 512 | |
| 513 | | Permission | Levels | What it covers | g1t scopes it gives | |
| 514 | | --- | --- | --- | --- | |
| 515 | | `members` (Members) | read, write | The workspace's people, invitations and teams | read: `workspace:read`; write: `workspace:admin` | |
| 516 | | `workspace_administration` (Administration) | read, write | The workspace's settings, integrations, rulesets and base permission | read: `workspace:read`, `access:read`; write: `workspace:admin`, `access:admin` | |
| 517 | | `workspace_billing` (Billing) | read, write | Usage, budget, AI credit and invoices, and (write) changing the budget and buying credit | read: `billing:read`; write: `billing:write` | |
| 518 | | `models` (AI Gateway) | read, write | AI Gateway requests: seeing them, and sending requests, which uses the workspace's AI credit | read: `models:read`; write: `models:write` | |
| 519 | | `self_hosted_runners` (Self-hosted runners) | read, write | Runners, their groups and settings | read: `runners:read`; write: `runners:admin` | |
| 520 | | `workspace_secrets` (Secrets) | read, write | The workspace's Actions secrets. Shares its scopes with the repository Secrets permission | read: `secrets:read`; write: `secrets:admin` | |
| 521 | | `workspace_webhooks` (Webhooks) | read, write | The workspace's webhooks. Shares its scopes with the repository Webhooks permission | read: `webhooks:read`; write: `webhooks:admin` | |
| 522 | |
| 523 | Account permissions, for your own account as the resource owner: |
| 524 | |
| 525 | | Permission | Levels | What it covers | g1t scopes it gives | |
| 526 | | --- | --- | --- | --- | |
| 527 | | `email_addresses` (Email addresses) | read, write | Your email addresses and email settings, invites and invitations | read: `account:read`; write: `account:write` | |
| 528 | | `starring` (Starring) | read, write | Stars and pinned projects. Shares its scopes with Email addresses | read: `account:read`; write: `account:write` | |
| 529 | | `notifications` (Notifications) | read, write | Your inbox, subscriptions and watched repositories | read: `notifications:read`; write: `notifications:write` | |
| 530 | |
| 531 | ### What a fine-grained token reaches |
| 532 | |
| 533 | - **In its workspace**, what your role allows, in the repositories it |
| 534 | reaches, and only what its permissions give. |
| 535 | - **Elsewhere**, public repositories, read-only, as anyone can. It cannot |
| 536 | comment, open issues or push there. |
| 537 | - **With your account as its resource owner**, public repositories, |
| 538 | read-only, and what its account permissions give. |
| 539 | - **While pending, denied or revoked**, public repositories, read-only. |
| 540 | |
| 541 | A request it cannot make answers `403` naming why: the scope it lacks, or |
| 542 | `This fine-grained token's resource owner is the workspace acme: it can only |
| 543 | read public repositories elsewhere, …`. A repository outside its selection |
| 544 | answers as if it did not exist. |
| 545 | |
| 546 | ### Create a classic token |
| 547 | |
| 548 | 1. Open [Settings → Access tokens](https://g1t.sh/settings/tokens), and |
| 549 | select the **Tokens (classic)** tab. |
| 550 | 2. Under **New classic token**, give it a **Name** after what will use it. |
| 551 | 3. Choose when it **Expires**: 7 days, 30 days, 90 days (the default), |
| 552 | 1 year, or No expiry. An expired token stops working; make a new one. |
| 553 | No expiry shows a warning: the token works until someone deletes it. |
| 554 | 4. Under **Scopes**, tick the boxes for what it may do. They are grouped |
| 555 | by area. The form starts on the **Agent** [preset](#presets); select |
| 556 | another preset to tick its boxes instead. |
| 557 | 5. Select **Create token**, and copy the token. It is not shown again. |
| 558 | |
| 559 | The list shows each token's name, when it was made and last used, when it |
| 560 | expires, and its access: a preset's name, its scopes, or Full access. To |
| 561 | change what a token may do, select **Edit access**, tick or untick boxes, |
| 562 | and select **Save access**. The token stays the same; the change applies |
| 563 | from its next request. |
| 564 | |
| 565 | A classic token reaches every workspace you belong to unless the |
| 566 | workspace's [rules](#a-workspaces-rules-for-tokens) keep it out: one that |
| 567 | does not allow classic tokens, one whose longest lifetime this token |
| 568 | exceeds, or one whose owner revoked it there. It keeps working everywhere |
| 569 | else. |
| 570 | |
| 571 | ## Scopes |
| 572 | |
| 573 | A scope is a resource and a level, written `resource:level`, such as |
| 574 | `issues:write`. A higher level includes the lower ones of the same |
| 575 | resource: `repo:admin` includes `repo:write`, which includes `repo:read`. |
| 576 | It never includes another resource: `repo:admin` does not let a token push, |
| 577 | which is `code:write`. |
| 578 | |
| 579 | On the form, scopes are a checklist grouped by area: |
| 580 | |
| 581 | | Group | Scopes | |
| 582 | | --- | --- | |
| 583 | | Repositories & code | `repo:read`, `repo:write`, `code:read`, `code:write` | |
| 584 | | Packages | `packages:read`, `packages:write` | |
| 585 | | Issues & pull requests | `issues:read`, `issues:write`, `pull_requests:read`, `pull_requests:write` | |
| 586 | | Agents | `agents:run` | |
| 587 | | Workflows | `workflows:read`, `workflows:write`, `workflow_files:write` | |
| 588 | | Checks | `checks:read`, `checks:write` | |
| 589 | | Deployments | `deployments:read`, `deployments:write` | |
| 590 | | Memory & search | `memory:read`, `memory:write` | |
| 591 | | Account | `account:read`, `account:write` | |
| 592 | | Notifications | `notifications:read`, `notifications:write` | |
| 593 | | Security | `security:read`, `security:write` | |
| 594 | | Workspace | `workspace:read`, `access:read`, `webhooks:read`, `secrets:read` | |
| 595 | | Billing | `billing:read`, `billing:write` | |
| 596 | | Runners | `runners:read` | |
| 597 | | AI Gateway | `models:read`, `models:write` | |
| 598 | | Dangerous | `repo:admin`, `packages:delete`, `workspace:admin`, `access:admin`, `webhooks:admin`, `secrets:admin`, `runners:admin` | |
| 599 | |
| 600 | Ticking a higher level ticks the lower ones of its resource and greys |
| 601 | them out: tick `issues:write` and `issues:read` is ticked too. Untick |
| 602 | `issues:write` and `issues:read` stays ticked. |
| 603 | |
| 604 | | Scope | What it lets a token do | |
| 605 | | --- | --- | |
| 606 | | `repo:read` | See repositories, their settings, labels, timelines, releases, languages, contributors and security alerts, and search | |
| 607 | | `repo:write` | Create repositories, rename branches, change how pull requests merge and publish releases | |
| 608 | | `repo:admin` | Rename, archive, transfer, delete or change who can see a repository, and dismiss security alerts | |
| 609 | | `code:read` | Clone and fetch private repositories with git | |
| 610 | | `code:write` | Push commits with git | |
| 611 | | `security:read` | See [secret scanning](/guides/security/secret-protection/), [code scanning](/guides/security/code-scanning/) and vulnerability alerts, custom patterns, the dependency graph and SBOM, and security settings | |
| 612 | | `security:write` | Dismiss and reopen alerts, bypass push protection, review bypass requests, manage custom patterns, upload SARIF and change security settings | |
| 613 | | `packages:read` | Pull container images and install private [packages](/guides/packages/). Public ones need no scope. | |
| 614 | | `packages:write` | Push container images and publish packages; with the Admin role on a package, change its settings | |
| 615 | | `packages:delete` | Delete and restore packages and their versions | |
| 616 | | `issues:read` | Read issues, comments and plans | |
| 617 | | `issues:write` | Open, edit, close and comment on issues | |
| 618 | | `pull_requests:read` | Read pull requests, their changes, sessions and merge queues | |
| 619 | | `pull_requests:write` | Open, review, close and merge pull requests | |
| 620 | | `agents:run` | Put g1t to work and message it, which uses the workspace's money | |
| 621 | | `workflows:read` | Read workflows, runs and logs | |
| 622 | | `workflows:write` | Run, cancel, rerun and turn workflows on or off | |
| 623 | | `workflow_files:write` | Add, change and delete [workflow files](#workflow-files) under `.g1t/workflows` and `.github/workflows`, with git or the API. Not in any preset but full access. | |
| 624 | | `checks:read` | Read commits' statuses, check runs, check suites and annotations | |
| 625 | | `checks:write` | Report [statuses and check runs](/guides/checks/) on commits, and ask for checks to run again | |
| 626 | | `deployments:read` | See [deployments](/guides/deployments-api/), their statuses and environments | |
| 627 | | `deployments:write` | Report deployments and their statuses, from any CI | |
| 628 | | `memory:read` | Recall memory and search the workspace's context | |
| 629 | | `memory:write` | Save memory for the next agent | |
| 630 | | `account:read` | Read your email addresses, invites, invitations, pinned projects and stars | |
| 631 | | `account:write` | Change your email addresses, make invites, answer invitations, pin projects and star repositories | |
| 632 | | `notifications:read` | See your [inbox](/guides/inbox/), its threads, and what you subscribe to and watch | |
| 633 | | `notifications:write` | Mark notifications read, done, saved or snoozed, subscribe to threads and watch repositories | |
| 634 | | `workspace:read` | Read workspace settings, invites, integrations, model routes and [teams](/guides/teams/) | |
| 635 | | `workspace:admin` | Create and delete workspaces, invite members, manage teams, connect integrations | |
| 636 | | `billing:read` | See a workspace's [usage, budget, AI credit and invoices](/guides/usage-and-billing/) | |
| 637 | | `billing:write` | Change a workspace's budget and buy AI credit. Only owners, as people: a workspace's own token and g1t's agents never change billing, whatever their scopes. Not in any preset but full access. | |
| 638 | | `access:read` | See who has access to repositories | |
| 639 | | `access:admin` | Give people and teams access to repositories, and take it away | |
| 640 | | `webhooks:read` | See webhooks and their deliveries | |
| 641 | | `webhooks:admin` | Create, change and delete webhooks | |
| 642 | | `secrets:read` | List secrets (never their values) and read variables | |
| 643 | | `secrets:admin` | Set and delete secrets and variables | |
| 644 | | `runners:read` | See [self-hosted runners](/guides/self-hosted-runners/), their groups and where agents run. Not in the Agent preset. | |
| 645 | | `runners:admin` | Register and remove self-hosted runners, change their groups and settings | |
| 646 | | `models:read` | See the workspace's [AI Gateway](/guides/ai-gateway/) requests: their models, tokens, cost and status | |
| 647 | | `models:write` | Send model requests through the [AI Gateway](/guides/ai-gateway/), which uses the workspace's AI credit. Only a workspace's own token can send them. Not in any preset but full access. | |
| 648 | |
| 649 | Every operation of the API and the MCP server needs exactly one of these, |
| 650 | except `whoami` (`GET /user`), which any token may use. Each endpoint's page |
| 651 | in the [API reference](/reference/api/) names its scope, and so does each |
| 652 | action in [MCP tools](/reference/mcp/). A few calls need a second scope for |
| 653 | what they ask: |
| 654 | |
| 655 | | Call | Also needs | |
| 656 | | --- | --- | |
| 657 | | `delegate` (`POST /repos/{owner}/{name}/issues/delegate`, the `agent` tool's `delegate`), which opens an issue | `issues:write`, beside `agents:run` | |
| 658 | | `apply_plan` or `import_issue` (the `plan` tool's `apply`, the `issue` tool's `import`) with `assign: true` | `agents:run` | |
| 659 | | `update_repo` with `private` or `default_branch` | `repo:admin` | |
| 660 | |
| 661 | ### What a token can do |
| 662 | |
| 663 | What a request may do is where these overlap: |
| 664 | |
| 665 | 1. **Your role.** A token never does more than you could on the website. A |
| 666 | token with `repo:admin` still cannot delete a repository unless you are |
| 667 | an owner of its workspace. See [access and roles](/guides/access-and-roles/). |
| 668 | 2. **What it reaches.** A classic token, every workspace and repository you |
| 669 | can reach, including ones you join later, unless a workspace's |
| 670 | [rules](#a-workspaces-rules-for-tokens) keep it out. A fine-grained |
| 671 | token, its [resource owner](#what-a-fine-grained-token-reaches) only. |
| 672 | 3. **Its scopes.** What kinds of thing it may do: chosen directly on a |
| 673 | classic token, given by its permissions on a fine-grained one. |
| 674 | |
| 675 | To keep a token away from other workspaces, make a fine-grained one, or use |
| 676 | a [workspace token](#workspace-tokens): it reaches only its own workspace. |
| 677 | |
| 678 | ### Presets |
| 679 | |
| 680 | A preset ticks a starting set of boxes. Select one, then tick or untick |
| 681 | any box. |
| 682 | |
| 683 | | Preset | Scopes | |
| 684 | | --- | --- | |
| 685 | | Read only | Every `read` scope. Changes nothing. | |
| 686 | | Agent | Every `read` scope except `runners:read`, and `code:write`, `issues:write`, `pull_requests:write`, `agents:run`, `memory:write` and `notifications:write`. Reads everything, works on issues and pull requests, pushes code, puts g1t to work, and answers your inbox. No admin scope. | |
| 687 | | CI | `repo:read`, `code:read`, `code:write`, `packages:read`, `packages:write`, `workflows:read`, `workflows:write`, `checks:read`, `checks:write`, `deployments:read` and `deployments:write`. Clones and pushes code, pushes and pulls packages, runs workflows, and reports [checks](/guides/checks/) and deployments. | |
| 688 | | Full access | Everything you can do, including deleting repositories and changing who has access. Marked **Dangerous**. | |
| 689 | |
| 690 | Admin scopes change things that are hard to undo, or decide who can reach |
| 691 | what. They are under **Dangerous**, with a warning. Give them only to |
| 692 | something you trust as much as yourself. |
| 693 | |
| 694 | ### Git and scopes |
| 695 | |
| 696 | Over HTTPS, git checks the same token: |
| 697 | |
| 698 | | To | Needs | |
| 699 | | --- | --- | |
| 700 | | Clone or fetch a public repository | No scope | |
| 701 | | Clone or fetch a private repository | `code:read` | |
| 702 | | Push | `code:write` | |
| 703 | | Push commits that add, change or delete [workflow files](#workflow-files) | `code:write` and `workflow_files:write` | |
| 704 | |
| 705 | Your role on the repository applies too, as on the website. A refused push |
| 706 | or clone says which scope is missing. |
| 707 | |
| 708 | ### Workflow files |
| 709 | |
| 710 | A workflow runs with its repository's secrets and a token of its own, so |
| 711 | changing one is as powerful as holding those. A token therefore needs |
| 712 | `workflow_files:write` (a fine-grained token's **Workflows** permission) to |
| 713 | add, change or delete any file under `.g1t/workflows/` or |
| 714 | `.github/workflows/`, besides `code:write`: |
| 715 | |
| 716 | - **With git**, every commit a push adds is compared with its parent, and a |
| 717 | push that changes a workflow file is declined, naming it: |
| 718 | |
| 719 | ```text |
| 720 | remote: This access token cannot change the workflow file .github/workflows/ci.yml: it needs the workflow_files:write scope. |
| 721 | remote: Push with a token that has the workflow_files:write scope, or make the change signed in on g1t.sh. |
| 722 | ``` |
| 723 | |
| 724 | A push too large for g1t to read whole is declined for such a token too, |
| 725 | since it cannot be checked; push it in smaller parts. |
| 726 | - **Through g1t**, a file written for a token (such as a starter workflow) |
| 727 | is refused the same way. |
| 728 | - **A workflow job's token** never may, whatever its `permissions:` say. |
| 729 | See [the job's token](/guides/actions/#the-jobs-token). |
| 730 | - **Signed in on g1t.sh**, your role decides, as for any file. |
| 731 | |
| 732 | Full-access tokens, and tokens made before scopes, include it. A |
| 733 | [deploy key](/guides/git/#deploy-keys) with write access may change |
| 734 | workflow files. |
| 735 | |
| 736 | ### When a token lacks a scope |
| 737 | |
| 738 | The API answers `403` with the scope that was missing in `needed_scope`: |
| 739 | |
| 740 | ```json |
| 741 | { |
| 742 | "error": { |
| 743 | "code": "forbidden", |
| 744 | "message": "This access token needs the issues:write scope to use create_issue.", |
| 745 | "needed_scope": "issues:write" |
| 746 | } |
| 747 | } |
| 748 | ``` |
| 749 | |
| 750 | Through MCP the same message comes back as a tool result with `isError` |
| 751 | set. Give the token that scope with **Edit access**, or make a new token. |
| 752 | |
| 753 | ### Tokens made before scopes |
| 754 | |
| 755 | Tokens and OAuth sign-ins made before tokens had scopes keep full access, |
| 756 | so nothing that uses them stops working. Settings marks each one |
| 757 | **Legacy · full access**, and says to narrow it to what it needs. For a |
| 758 | token, select **Narrow this token**; for an application, **Change access** |
| 759 | in [Connected applications](https://g1t.sh/settings/applications). Then |
| 760 | tick its scopes. A token you make with Full access on purpose is not marked |
| 761 | legacy. |
| 762 | |
| 763 | A token from [signing in from a tool](#signing-in-from-a-tool), such as the |
| 764 | g1t CLI, has full access. |
| 765 | |
| 766 | ### Workspace tokens |
| 767 | |
| 768 | A workspace's own tokens act as the workspace rather than a person. An |
| 769 | owner makes them in the workspace's **Settings → Access tokens**, with the |
| 770 | same checklist and expiry choices; the form starts on the CI preset. A |
| 771 | workspace token reaches all of that workspace's repositories, never |
| 772 | another workspace, and cannot manage people, tokens or workspaces. |
| 773 | |
| 774 | It has the Write role on the workspace's repositories, as a member does: |
| 775 | it pushes, merges and works on issues and pull requests, within its scopes. |
| 776 | Tick **Admin on the workspace's repositories** when making it to give it |
| 777 | Admin instead, so it can also manage webhooks, secrets, deploy keys and who |
| 778 | has access, and manage teams as an owner would. Only an owner can, and only |
| 779 | when making it. See |
| 780 | [workspace access tokens](/guides/workspaces/#workspace-access-tokens). |
| 781 | |
| 782 | ## A workspace's rules for tokens |
| 783 | |
| 784 | An owner decides which of the members' own personal tokens reach the |
| 785 | workspace, under its **Settings → Personal access tokens** |
| 786 | (`g1t.sh/<workspace>/-/personal-access-tokens`). The rules apply from each |
| 787 | token's next request, to tokens made before them too. A token they keep out |
| 788 | keeps working everywhere else, and reads the workspace's public |
| 789 | repositories as anyone can. |
| 790 | |
| 791 | | Rule | Default | What it does | |
| 792 | | --- | --- | --- | |
| 793 | | Allow fine-grained personal access tokens | On | Off: no fine-grained token can name the workspace as its resource owner, and existing ones stop reaching it. | |
| 794 | | Require approval of fine-grained tokens | On | A member's fine-grained token naming the workspace waits for an owner's approval, and again when it is widened. Owners' own tokens never wait. | |
| 795 | | Allow classic personal access tokens | On | Off: classic tokens no longer reach the workspace. | |
| 796 | | Tokens must expire | Off | On: a token that never expires does not reach the workspace. | |
| 797 | | Longest lifetime | No limit | A token that lasts longer (from when it was made to when it expires), or never expires, does not reach the workspace. Fine-grained tokens for it cannot be made longer. | |
| 798 | |
| 799 | The same page lists: |
| 800 | |
| 801 | - **Waiting for approval.** Each pending fine-grained token with its owner, |
| 802 | permissions, repositories and expiry. Add an optional note, then select |
| 803 | **Approve** or **Deny**. Its owner hears of it in their inbox, with the |
| 804 | note. |
| 805 | - **Tokens that can reach the workspace.** Every fine-grained token naming |
| 806 | it, and every classic token of its members and outside collaborators that |
| 807 | has not expired, with its owner, permissions or scopes, last use and |
| 808 | expiry, and whether it reaches the workspace now (and if not, why). Never |
| 809 | the token itself. Select **Revoke** to take one out: a fine-grained token |
| 810 | stops reaching the workspace for good; a classic token keeps working |
| 811 | everywhere else, but never reaches this workspace again. |
| 812 | |
| 813 | Approvals, denials, revocations and rule changes are |
| 814 | [audit log](/guides/audit-log/) entries: `token.approval_requested`, |
| 815 | `token.approved`, `token.denied`, `token.revoked` and |
| 816 | `token.policy_changed`. |
| 817 | |
| 818 | ### A workspace's rules through the API |
| 819 | |
| 820 | Owners, as people (a personal token with the scope works; a workspace's own |
| 821 | token does not): |
| 822 | |
| 823 | | Route | MCP tool and action | What it does | Scope | |
| 824 | | --- | --- | --- | --- | |
| 825 | | [`GET /workspaces/{workspace}/personal-access-token-policy`](/reference/api/personal-access-tokens/get-token-policy/) | `workspace` `get_token_policy` | The rules. Members may read them. | `workspace:read` | |
| 826 | | [`PATCH /workspaces/{workspace}/personal-access-token-policy`](/reference/api/personal-access-tokens/set-token-policy/) | `workspace` `set_token_policy` | Change `allow_classic`, `allow_fine_grained`, `require_approval`, `max_lifetime_days` (0 for no limit) or `forbid_no_expiry` | `workspace:admin` | |
| 827 | | [`GET /workspaces/{workspace}/personal-access-tokens`](/reference/api/personal-access-tokens/list-member-tokens/) | `workspace` `list_member_tokens` | The tokens that can reach it; `kind` is `classic` or `fine_grained` | `access:read` | |
| 828 | | [`GET /workspaces/{workspace}/personal-access-token-requests`](/reference/api/personal-access-tokens/list-token-requests/) | `workspace` `list_token_requests` | The fine-grained tokens waiting for approval | `access:read` | |
| 829 | | [`POST /workspaces/{workspace}/personal-access-token-requests/{id}`](/reference/api/personal-access-tokens/review-token-request/) | `workspace` `review_token_request` | `decision` is `approve` or `deny`, with an optional `reason` | `access:admin` | |
| 830 | | [`POST /workspaces/{workspace}/personal-access-tokens/{id}`](/reference/api/personal-access-tokens/revoke-member-token/) | `workspace` `revoke_member_token` | Revoke a token in the workspace, with an optional `reason` | `access:admin` | |
| 831 | |
| 832 | ## Signing in with OAuth |
| 833 | |
| 834 | Applications that can open your browser, such as an agent connecting to the |
| 835 | [MCP server](/guides/bring-your-own-agent/), sign you in with OAuth 2.1. |
| 836 | You see a page on g1t naming the application and where it will send you |
| 837 | back, and you approve or deny. The application never sees your password and |
| 838 | there is no token to copy. |
| 839 | |
| 840 | The page lists what the application will be able to do, as the same |
| 841 | checklist a token has, with only the scopes it asked for, all ticked. |
| 842 | Untick anything you would rather it could not do, leaving at least one; |
| 843 | you cannot give it more than it asked for. Like a token, it reaches |
| 844 | everything you can. |
| 845 | |
| 846 | An application that asks for no scopes in particular gets the |
| 847 | [Agent preset](#presets): every `read` scope except `runners:read`, and `code:write`, |
| 848 | `issues:write`, `pull_requests:write`, `agents:run`, `memory:write` and |
| 849 | `notifications:write`. |
| 850 | It never gets an admin scope unless it asks for one and you leave it |
| 851 | ticked. |
| 852 | |
| 853 | Applications you have approved are listed in |
| 854 | [Settings → Connected applications](https://g1t.sh/settings/applications), |
| 855 | each with its access. Select **Change access** to tick or untick its |
| 856 | scopes, then **Save access**: it stays signed in, the change applies at |
| 857 | once, and its next refresh keeps it. Select **Sign out** to end its access |
| 858 | at once. |
| 859 | |
| 860 | For people building a client: |
| 861 | |
| 862 | | | | |
| 863 | | --- | --- | |
| 864 | | Metadata | `https://api.g1t.sh/.well-known/oauth-authorization-server` | |
| 865 | | Authorization | `https://g1t.sh/oauth/authorize` | |
| 866 | | Token | `https://api.g1t.sh/oauth/token` | |
| 867 | | Registration | `https://api.g1t.sh/oauth/register` | |
| 868 | |
| 869 | - The flow is authorization code with PKCE. `S256` is required. |
| 870 | - Clients are public: there are no client secrets. |
| 871 | - Register with `client_name` and `redirect_uris`. A redirect address is an |
| 872 | `https` URL, `http` on `localhost`, or the application's own scheme. A |
| 873 | client on `localhost` may use any port. |
| 874 | - Registration stores nothing. The client id it returns encodes what was |
| 875 | registered, so it cannot be used to fill g1t with junk. |
| 876 | - Ask for scopes with `scope` on the authorization request, separated by |
| 877 | spaces, such as `scope=repo:read issues:write pull_requests:write`. |
| 878 | Names g1t does not know are left out. Leave `scope` out for the Agent |
| 879 | preset. The authorization server's metadata and |
| 880 | `https://mcp.g1t.sh/.well-known/oauth-protected-resource` list every |
| 881 | scope in `scopes_supported`. |
| 882 | - The token response's `scope` holds the scopes the person granted, |
| 883 | separated by spaces, or `*` for a sign-in with full access. Refreshing |
| 884 | keeps them. |
| 885 | - An access token lasts 30 days. The refresh token returned with it works |
| 886 | once and returns the next pair; the previous access token stops working. |
| 887 | - An authorization code lasts five minutes and works once. |
| 888 | |
| 889 | ## Signing in from a tool |
| 890 | |
| 891 | A tool that cannot receive a redirect, such as a script on a remote machine, |
| 892 | gets a token without ever handling your password: |
| 893 | |
| 894 | 1. The tool asks g1t for a code and shows you a link and a short code such |
| 895 | as `WDJB-MJHT`. |
| 896 | 2. You open the link, sign in (or create an account), check that the code |
| 897 | matches, and approve. |
| 898 | 3. The tool collects its token. |
| 899 | |
| 900 | ```sh |
| 901 | # 1. The tool starts a sign-in. |
| 902 | curl -X POST https://api.g1t.sh/device/code -H "Content-Type: application/json" -d '{"client_name": "my-tool"}' |
| 903 | |
| 904 | # 2. You open verification_uri_complete from the response and approve. |
| 905 | |
| 906 | # 3. The tool polls, no faster than "interval" seconds, until it is approved. |
| 907 | curl -X POST https://api.g1t.sh/device/token -H "Content-Type: application/json" -d '{"device_code": "…"}' |
| 908 | ``` |
| 909 | |
| 910 | The poll answers with a `status` of `pending`, `approved`, `denied` or |
| 911 | `expired`. An approved answer carries the token, once. Codes expire after 15 |
| 912 | minutes. The token appears in |
| 913 | [Settings → Access tokens](https://g1t.sh/settings/tokens) under the tool's name, where you |
| 914 | can delete it. |
| 915 | |
| 916 | Only approve a code you asked for. The token has full access: it can do |
| 917 | everything you can. To give a tool less, make an |
| 918 | [access token](#create-a-fine-grained-token) with only the scopes it needs instead. |
| 919 | |
| 920 | ## Resetting your password |
| 921 | |
| 922 | Use [g1t.sh/forgot](https://g1t.sh/forgot) and enter any confirmed |
| 923 | address of your account. The link goes to that address and works for one |
| 924 | hour; your primary and backup addresses are told a reset was asked for |
| 925 | when it went elsewhere. A new account that has not confirmed its address |
| 926 | yet can use that address, and following the link confirms it. |
| 927 | |
| 928 | The page answers the same way whether or not the address has an account. |
| 929 | g1t sends at most 5 reset links an hour to one address. If g1t cannot |
| 930 | take the request at all, the page says so and keeps what you typed, so you |
| 931 | can try again. |
| 932 | |
| 933 | Setting a new password signs you out everywhere and emails your primary |
| 934 | and backup addresses. |
| 935 | |
| 936 | ## Too many attempts |
| 937 | |
| 938 | g1t counts wrong passwords, on the sign-in page, for git over HTTPS and |
| 939 | when confirming it is you, against the account and against where they come |
| 940 | from. After 10 wrong passwords for one account in an hour, or 30 from one |
| 941 | place, g1t stops checking passwords for it for a minute, then twice as long |
| 942 | after each further wrong password, up to an hour. While it waits, every |
| 943 | attempt gets the same answer: "Too many attempts". The account's primary |
| 944 | and backup addresses are told the first time. Signing in with the right |
| 945 | password, or resetting it, clears the count. Access tokens, SSH keys and |
| 946 | GitHub sign-in are not affected. |
| 947 | |
| 948 | ## Security log |
| 949 | |
| 950 | [Settings → Security log](https://g1t.sh/settings/security-log) lists what |
| 951 | happened to your account: addresses added, confirmed, removed or made |
| 952 | primary, your backup and privacy settings, password changes, pauses after |
| 953 | too many wrong passwords, two-factor authentication turned on or off and |
| 954 | recovery codes made or used, personal access tokens created, deleted or |
| 955 | given new scopes, SSH keys added or removed, and applications authorized, |
| 956 | changed or revoked. Changes g1t staff made, such as removing an address |
| 957 | someone else needed, say so and why. |
| 958 | |
| 959 | Token, SSH key, application and two-factor changes are also recorded in the |
| 960 | [audit log](/guides/audit-log/) of each workspace you belong to, where its |
| 961 | owners see them. |
| 962 | |
| 963 | ## What g1t stores |
| 964 | |
| 965 | Passwords are stored as salted PBKDF2-SHA256 hashes. Sessions and tokens are |
| 966 | stored as SHA-256 hashes. Neither can be read back. A two-factor secret is |
| 967 | encrypted (AES-256-GCM) and bound to your account, and recovery codes are |
| 968 | kept as SHA-256 hashes. |