Skip to content

Commit 4b74a3d

Browse files
authored
Add Bitbucket Cloud API token authentication support (#604)
1 parent 9015afb commit 4b74a3d

File tree

12 files changed

+418
-53
lines changed

12 files changed

+418
-53
lines changed

.github/workflows/go-build-test.yml

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ jobs:
1111
os: [macos-latest, ubuntu-latest]
1212
steps:
1313
- name: Set up Go 1.24.6
14-
uses: actions/setup-go@v1
14+
uses: actions/setup-go@v6
1515
with:
1616
go-version: 1.24.6
1717
id: go
@@ -28,6 +28,10 @@ jobs:
2828
- name: Run Bitbucket Cloud Integration Tests
2929
run: scripts/bitbucket_cloud_integration_tests.sh
3030
env:
31+
# New API Token authentication (recommended)
32+
BITBUCKET_API_TOKEN: ${{ secrets.GHORG_BITBUCKET_API_TOKEN }}
33+
BITBUCKET_API_EMAIL: ${{ secrets.GHORG_BITBUCKET_API_EMAIL }}
34+
# Legacy App Password authentication (for backward compatibility testing)
3135
BITBUCKET_TOKEN: ${{ secrets.GHORG_BITBUCKET_APP_PASSWORD }}
3236
BITBUCKET_USERNAME: ${{ secrets.GHORG_BITBUCKET_USERNAME }}
3337
- name: Run GitLab Cloud Integration Tests
@@ -46,7 +50,7 @@ jobs:
4650
runs-on: windows-latest
4751
steps:
4852
- name: Set up Go 1.24.6
49-
uses: actions/setup-go@v1
53+
uses: actions/setup-go@v6
5054
with:
5155
go-version: 1.24.6
5256
id: go
@@ -67,6 +71,10 @@ jobs:
6771
- name: Run Bitbucket Integration Tests
6872
run: scripts/bitbucket_cloud_integration_tests.sh
6973
env:
74+
# New API Token authentication (recommended)
75+
BITBUCKET_API_TOKEN: ${{ secrets.GHORG_BITBUCKET_API_TOKEN }}
76+
BITBUCKET_API_EMAIL: ${{ secrets.GHORG_BITBUCKET_API_EMAIL }}
77+
# Legacy App Password authentication (for backward compatibility testing)
7078
BITBUCKET_TOKEN: ${{ secrets.GHORG_BITBUCKET_APP_PASSWORD }}
7179
BITBUCKET_USERNAME: ${{ secrets.GHORG_BITBUCKET_USERNAME }}
7280
- name: Run GitLab Cloud Integration Tests Linux

README.md

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -154,12 +154,23 @@ Note: ghorg will respect the `XDG_CONFIG_HOME` [environment variable](https://wi
154154

155155
> Note: ghorg supports both Bitbucket Cloud and Bitbucket Server (self-hosted instances)
156156
157-
#### App Passwords
157+
#### API Tokens (Recommended for Bitbucket Cloud)
158158

159-
1. To configure with bitbucket you will need to create a new [app password](https://confluence.atlassian.com/bitbucket/app-passwords-828781300.html) and update your `$HOME/.config/ghorg/conf.yaml` or use the (--token, -t) and (--bitbucket-username) flags.
160-
1. Update [SCM type](https://github.com/gabrie30/ghorg/blob/master/sample-conf.yaml#L54-L57) to `bitbucket` in your `ghorg/conf.yaml` or via cli flags
159+
Bitbucket has deprecated App Passwords in favor of API Tokens. This is the recommended authentication method for Bitbucket Cloud.
160+
161+
1. Create an [API token](https://support.atlassian.com/bitbucket-cloud/docs/create-an-api-token/) from your Atlassian account settings
162+
1. **Important**: When creating the token, grant **all read scopes** (Account: Read, Workspace membership: Read, Projects: Read, Repositories: Read, etc.) to ensure ghorg can list and clone repositories
163+
1. Set `GHORG_BITBUCKET_API_TOKEN` in your `$HOME/.config/ghorg/conf.yaml` or use the `--token` flag
164+
1. Set `GHORG_BITBUCKET_API_EMAIL` to your Atlassian account email (or use `--bitbucket-api-email`)
165+
1. Update SCM type to `bitbucket` in your `ghorg/conf.yaml` or via cli flags
161166
1. See [examples/bitbucket.md](https://github.com/gabrie30/ghorg/blob/master/examples/bitbucket.md) on how to run
162167

168+
> Note: When using API tokens, ghorg automatically uses `x-bitbucket-api-token-auth` as the Git username for clone operations, as required by Bitbucket's API token authentication.
169+
170+
#### App Passwords (Legacy)
171+
172+
> Note: Bitbucket has deprecated App Passwords. Consider using API Tokens instead.
173+
163174
#### PAT/OAuth token
164175

165176
1. Create a [PAT](https://confluence.atlassian.com/bitbucketserver/personal-access-tokens-939515499.html)

cmd/clone.go

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,10 @@ func cloneFunc(cmd *cobra.Command, argz []string) {
118118
os.Setenv("GHORG_BITBUCKET_USERNAME", cmd.Flag("bitbucket-username").Value.String())
119119
}
120120

121+
if cmd.Flags().Changed("bitbucket-api-email") {
122+
os.Setenv("GHORG_BITBUCKET_API_EMAIL", cmd.Flag("bitbucket-api-email").Value.String())
123+
}
124+
121125
if cmd.Flags().Changed("clone-type") {
122126
cloneType := strings.ToLower(cmd.Flag("clone-type").Value.String())
123127
os.Setenv("GHORG_CLONE_TYPE", cloneType)
@@ -331,10 +335,23 @@ func cloneFunc(cmd *cobra.Command, argz []string) {
331335
} else if os.Getenv("GHORG_SCM_TYPE") == "gitlab" {
332336
os.Setenv("GHORG_GITLAB_TOKEN", token)
333337
} else if os.Getenv("GHORG_SCM_TYPE") == "bitbucket" {
334-
if cmd.Flags().Changed("bitbucket-username") {
338+
// Auto-detect token type based on configuration:
339+
// 1. If GHORG_BITBUCKET_API_EMAIL is set, treat as API token
340+
// 2. If --bitbucket-username is provided, treat as app password (legacy)
341+
// 3. If GHORG_BITBUCKET_USERNAME is set but no API email, treat as app password (legacy)
342+
// 4. Otherwise, treat as API token (new default for Bitbucket Cloud)
343+
if os.Getenv("GHORG_BITBUCKET_API_EMAIL") != "" {
344+
// API email explicitly set - use API token auth
345+
os.Setenv("GHORG_BITBUCKET_API_TOKEN", cmd.Flag("token").Value.String())
346+
} else if cmd.Flags().Changed("bitbucket-username") {
347+
// Username provided via flag - use app password (legacy)
348+
os.Setenv("GHORG_BITBUCKET_APP_PASSWORD", cmd.Flag("token").Value.String())
349+
} else if os.Getenv("GHORG_BITBUCKET_USERNAME") != "" && os.Getenv("GHORG_BITBUCKET_API_TOKEN") == "" {
350+
// Username set in config but no API token - assume app password for backward compat
335351
os.Setenv("GHORG_BITBUCKET_APP_PASSWORD", cmd.Flag("token").Value.String())
336352
} else {
337-
os.Setenv("GHORG_BITBUCKET_OAUTH_TOKEN", cmd.Flag("token").Value.String())
353+
// Default to API token for new Bitbucket Cloud authentication
354+
os.Setenv("GHORG_BITBUCKET_API_TOKEN", cmd.Flag("token").Value.String())
338355
}
339356
} else if os.Getenv("GHORG_SCM_TYPE") == "gitea" {
340357
os.Setenv("GHORG_GITEA_TOKEN", token)

cmd/examples-copy/bitbucket.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,45 @@ To view all additional flags see the [sample-conf.yaml](https://github.com/gabri
88

99
## Bitbucket Cloud
1010

11+
### API Token Authentication (Recommended)
12+
13+
Bitbucket has deprecated App Passwords in favor of API Tokens. This is the recommended authentication method.
14+
15+
**Creating the API Token:**
16+
1. Go to your [Atlassian account settings](https://id.atlassian.com/manage/api-tokens)
17+
2. Create a new API token
18+
3. **Important**: Grant **all read scopes** (Account: Read, Workspace membership: Read, Projects: Read, Repositories: Read) to ensure ghorg can list and clone repositories
19+
20+
**Using the API Token:**
21+
22+
1. Clone the microsoft workspace using an API token
23+
24+
```
25+
ghorg clone microsoft --scm=bitbucket --bitbucket-api-email=<your-atlassian-email> --token=<api-token>
26+
```
27+
28+
1. Using environment variables (recommended for scripts)
29+
30+
```
31+
export GHORG_BITBUCKET_API_TOKEN=<api-token>
32+
export GHORG_BITBUCKET_API_EMAIL=<your-atlassian-email>
33+
ghorg clone microsoft --scm=bitbucket
34+
```
35+
36+
> Note: When using API tokens, ghorg automatically uses `x-bitbucket-api-token-auth` as the Git username for clone operations. The email is only used for API calls to list repositories.
37+
38+
### App Password Authentication (Legacy)
39+
40+
> Note: Bitbucket has deprecated App Passwords. Consider using API Tokens instead.
41+
1142
1. Clone the microsoft workspace using an app-password
1243
1344
```
1445
ghorg clone microsoft --scm=bitbucket --bitbucket-username=<your-username> --token=<app-password>
1546
```
1647
48+
### OAuth Token Authentication
49+
1750
1. Clone the microsoft workspace using oauth token
1851
1952
```

cmd/root.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ var (
2424
cloneType string
2525
scmType string
2626
bitbucketUsername string
27+
bitbucketAPIEmail string
2728
color string
2829
baseURL string
2930
concurrency string
@@ -332,6 +333,8 @@ func InitConfig() {
332333
getOrSetDefaults("GHORG_BITBUCKET_USERNAME")
333334
getOrSetDefaults("GHORG_BITBUCKET_APP_PASSWORD")
334335
getOrSetDefaults("GHORG_BITBUCKET_OAUTH_TOKEN")
336+
getOrSetDefaults("GHORG_BITBUCKET_API_TOKEN")
337+
getOrSetDefaults("GHORG_BITBUCKET_API_EMAIL")
335338
getOrSetDefaults("GHORG_SCM_BASE_URL")
336339
getOrSetDefaults("GHORG_PRESERVE_DIRECTORY_STRUCTURE")
337340
getOrSetDefaults("GHORG_OUTPUT_DIR")
@@ -374,8 +377,9 @@ func init() {
374377
cloneCmd.Flags().StringVar(&protocol, "protocol", "", "GHORG_CLONE_PROTOCOL - Protocol to clone with, ssh or https, (default https)")
375378
cloneCmd.Flags().StringVarP(&path, "path", "p", "", "GHORG_ABSOLUTE_PATH_TO_CLONE_TO - Absolute path to the home for ghorg clones. Must start with / (default $HOME/ghorg)")
376379
cloneCmd.Flags().StringVarP(&branch, "branch", "b", "", "GHORG_BRANCH - Branch left checked out for each repo cloned (default master)")
377-
cloneCmd.Flags().StringVarP(&token, "token", "t", "", "GHORG_GITHUB_TOKEN/GHORG_GITLAB_TOKEN/GHORG_GITEA_TOKEN/GHORG_BITBUCKET_APP_PASSWORD/GHORG_BITBUCKET_OAUTH_TOKEN/GHORG_SOURCEHUT_TOKEN - scm token to clone with")
378-
cloneCmd.Flags().StringVarP(&bitbucketUsername, "bitbucket-username", "", "", "GHORG_BITBUCKET_USERNAME - Bitbucket only: username associated with the app password")
380+
cloneCmd.Flags().StringVarP(&token, "token", "t", "", "GHORG_GITHUB_TOKEN/GHORG_GITLAB_TOKEN/GHORG_GITEA_TOKEN/GHORG_BITBUCKET_APP_PASSWORD/GHORG_BITBUCKET_API_TOKEN/GHORG_BITBUCKET_OAUTH_TOKEN/GHORG_SOURCEHUT_TOKEN - scm token to clone with")
381+
cloneCmd.Flags().StringVarP(&bitbucketUsername, "bitbucket-username", "", "", "GHORG_BITBUCKET_USERNAME - Bitbucket only: username associated with the app password (legacy auth)")
382+
cloneCmd.Flags().StringVarP(&bitbucketAPIEmail, "bitbucket-api-email", "", "", "GHORG_BITBUCKET_API_EMAIL - Bitbucket only: Atlassian account email for API token authentication")
379383
cloneCmd.Flags().StringVarP(&scmType, "scm", "s", "", "GHORG_SCM_TYPE - Type of scm used, github, gitlab, gitea, bitbucket or sourcehut (default github)")
380384
cloneCmd.Flags().StringVarP(&cloneType, "clone-type", "c", "", "GHORG_CLONE_TYPE - Clone target type, user or org (default org)")
381385
cloneCmd.Flags().BoolVar(&skipArchived, "skip-archived", false, "GHORG_SKIP_ARCHIVED - Skips archived repos, github/gitlab/gitea only")

configs/configs.go

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,12 @@ var (
3838
// ErrNoBitbucketAppPassword error message when no app password found
3939
ErrNoBitbucketAppPassword = errors.New("Could not find a valid bitbucket app password. GHORG_BITBUCKET_APP_PASSWORD or (--token, -t) must be set to clone repos from bitbucket, see 'BitBucket Setup' in README.md")
4040

41+
// ErrNoBitbucketAPIToken error message when no API token found
42+
ErrNoBitbucketAPIToken = errors.New("Could not find a valid bitbucket API token. GHORG_BITBUCKET_API_TOKEN or (--token, -t) must be set to clone repos from bitbucket, see 'BitBucket Setup' in README.md")
43+
44+
// ErrNoBitbucketAPIEmail error message when no email found for API token auth
45+
ErrNoBitbucketAPIEmail = errors.New("When using GHORG_BITBUCKET_API_TOKEN, you must also set GHORG_BITBUCKET_API_EMAIL or GHORG_BITBUCKET_USERNAME (your Atlassian account email), see 'BitBucket Setup' in README.md")
46+
4147
// ErrIncorrectScmType indicates an unsupported scm type being used
4248
ErrIncorrectScmType = errors.New("GHORG_SCM_TYPE or --scm must be one of " + strings.Join(scm.SupportedClients(), ", "))
4349

@@ -282,8 +288,20 @@ func getOrSetGitLabToken() {
282288
}
283289

284290
func getOrSetBitBucketToken() {
291+
// Check if API token is set from file path
292+
apiToken := os.Getenv("GHORG_BITBUCKET_API_TOKEN")
293+
if apiToken != "" && IsFilePath(apiToken) {
294+
os.Setenv("GHORG_BITBUCKET_API_TOKEN", GetTokenFromFile(apiToken))
295+
}
296+
297+
// Check if app password is set from file path
298+
appPassword := os.Getenv("GHORG_BITBUCKET_APP_PASSWORD")
299+
if appPassword != "" && IsFilePath(appPassword) {
300+
os.Setenv("GHORG_BITBUCKET_APP_PASSWORD", GetTokenFromFile(appPassword))
301+
}
302+
285303
var token string
286-
if isZero(os.Getenv("GHORG_BITBUCKET_APP_PASSWORD")) && isZero(os.Getenv("GHORG_BITBUCKET_OAUTH_TOKEN")) {
304+
if isZero(os.Getenv("GHORG_BITBUCKET_APP_PASSWORD")) && isZero(os.Getenv("GHORG_BITBUCKET_OAUTH_TOKEN")) && isZero(os.Getenv("GHORG_BITBUCKET_API_TOKEN")) {
287305
if runtime.GOOS == "windows" {
288306
return
289307
}
@@ -294,6 +312,9 @@ func getOrSetBitBucketToken() {
294312

295313
if !isZero(os.Getenv("GHORG_BITBUCKET_USERNAME")) {
296314
os.Setenv("GHORG_BITBUCKET_APP_PASSWORD", token)
315+
} else if !isZero(os.Getenv("GHORG_BITBUCKET_API_EMAIL")) {
316+
// If API email is set, assume API token auth
317+
os.Setenv("GHORG_BITBUCKET_API_TOKEN", token)
297318
} else {
298319
os.Setenv("GHORG_BITBUCKET_OAUTH_TOKEN", token)
299320
}
@@ -359,15 +380,27 @@ func VerifyTokenSet() error {
359380
}
360381

361382
if scmProvider == "bitbucket" {
362-
if os.Getenv("GHORG_BITBUCKET_OAUTH_TOKEN") == "" {
383+
// Check for OAuth token first (takes precedence)
384+
if os.Getenv("GHORG_BITBUCKET_OAUTH_TOKEN") != "" {
385+
return nil
386+
}
363387

364-
if os.Getenv("GHORG_BITBUCKET_USERNAME") == "" {
365-
return ErrNoBitbucketUsername
388+
// Check for new API token authentication
389+
if os.Getenv("GHORG_BITBUCKET_API_TOKEN") != "" {
390+
// API token requires either API email or username for API calls
391+
if os.Getenv("GHORG_BITBUCKET_API_EMAIL") == "" && os.Getenv("GHORG_BITBUCKET_USERNAME") == "" {
392+
return ErrNoBitbucketAPIEmail
366393
}
394+
return nil
395+
}
367396

368-
if os.Getenv("GHORG_BITBUCKET_APP_PASSWORD") == "" {
369-
return ErrNoBitbucketAppPassword
370-
}
397+
// Fall back to legacy App Password authentication
398+
if os.Getenv("GHORG_BITBUCKET_USERNAME") == "" {
399+
return ErrNoBitbucketUsername
400+
}
401+
402+
if os.Getenv("GHORG_BITBUCKET_APP_PASSWORD") == "" {
403+
return ErrNoBitbucketAppPassword
371404
}
372405
}
373406

configs/configs_test.go

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ func TestVerifyTokenSet(t *testing.T) {
3636
os.Setenv("GHORG_SCM_TYPE", "bitbucket")
3737
os.Setenv("GHORG_BITBUCKET_USERNAME", "")
3838
os.Setenv("GHORG_BITBUCKET_APP_PASSWORD", "12345678912345678901")
39+
os.Setenv("GHORG_BITBUCKET_API_TOKEN", "")
40+
os.Setenv("GHORG_BITBUCKET_API_EMAIL", "")
41+
os.Setenv("GHORG_BITBUCKET_OAUTH_TOKEN", "")
3942
err := configs.VerifyTokenSet()
4043
if err != configs.ErrNoBitbucketUsername {
4144
tt.Errorf("Expected ErrNoBitbucketUsername, got: %v", err)
@@ -47,12 +50,71 @@ func TestVerifyTokenSet(t *testing.T) {
4750
os.Setenv("GHORG_SCM_TYPE", "bitbucket")
4851
os.Setenv("GHORG_BITBUCKET_USERNAME", "bitbucketuser")
4952
os.Setenv("GHORG_BITBUCKET_APP_PASSWORD", "")
53+
os.Setenv("GHORG_BITBUCKET_API_TOKEN", "")
54+
os.Setenv("GHORG_BITBUCKET_API_EMAIL", "")
55+
os.Setenv("GHORG_BITBUCKET_OAUTH_TOKEN", "")
5056
err := configs.VerifyTokenSet()
5157
if err != configs.ErrNoBitbucketAppPassword {
5258
tt.Errorf("Expected ErrNoBitbucketAppPassword, got: %v", err)
5359
}
5460

5561
})
62+
63+
t.Run("When cloning bitbucket with API token but no email or username", func(tt *testing.T) {
64+
os.Setenv("GHORG_SCM_TYPE", "bitbucket")
65+
os.Setenv("GHORG_BITBUCKET_USERNAME", "")
66+
os.Setenv("GHORG_BITBUCKET_APP_PASSWORD", "")
67+
os.Setenv("GHORG_BITBUCKET_API_TOKEN", "test_api_token")
68+
os.Setenv("GHORG_BITBUCKET_API_EMAIL", "")
69+
os.Setenv("GHORG_BITBUCKET_OAUTH_TOKEN", "")
70+
err := configs.VerifyTokenSet()
71+
if err != configs.ErrNoBitbucketAPIEmail {
72+
tt.Errorf("Expected ErrNoBitbucketAPIEmail, got: %v", err)
73+
}
74+
75+
})
76+
77+
t.Run("When cloning bitbucket with API token and email", func(tt *testing.T) {
78+
os.Setenv("GHORG_SCM_TYPE", "bitbucket")
79+
os.Setenv("GHORG_BITBUCKET_USERNAME", "")
80+
os.Setenv("GHORG_BITBUCKET_APP_PASSWORD", "")
81+
os.Setenv("GHORG_BITBUCKET_API_TOKEN", "test_api_token")
82+
os.Setenv("GHORG_BITBUCKET_API_EMAIL", "[email protected]")
83+
os.Setenv("GHORG_BITBUCKET_OAUTH_TOKEN", "")
84+
err := configs.VerifyTokenSet()
85+
if err != nil {
86+
tt.Errorf("Expected no error, got: %v", err)
87+
}
88+
89+
})
90+
91+
t.Run("When cloning bitbucket with API token and username fallback", func(tt *testing.T) {
92+
os.Setenv("GHORG_SCM_TYPE", "bitbucket")
93+
os.Setenv("GHORG_BITBUCKET_USERNAME", "[email protected]")
94+
os.Setenv("GHORG_BITBUCKET_APP_PASSWORD", "")
95+
os.Setenv("GHORG_BITBUCKET_API_TOKEN", "test_api_token")
96+
os.Setenv("GHORG_BITBUCKET_API_EMAIL", "")
97+
os.Setenv("GHORG_BITBUCKET_OAUTH_TOKEN", "")
98+
err := configs.VerifyTokenSet()
99+
if err != nil {
100+
tt.Errorf("Expected no error, got: %v", err)
101+
}
102+
103+
})
104+
105+
t.Run("When cloning bitbucket with OAuth token", func(tt *testing.T) {
106+
os.Setenv("GHORG_SCM_TYPE", "bitbucket")
107+
os.Setenv("GHORG_BITBUCKET_USERNAME", "")
108+
os.Setenv("GHORG_BITBUCKET_APP_PASSWORD", "")
109+
os.Setenv("GHORG_BITBUCKET_API_TOKEN", "")
110+
os.Setenv("GHORG_BITBUCKET_API_EMAIL", "")
111+
os.Setenv("GHORG_BITBUCKET_OAUTH_TOKEN", "oauth_token")
112+
err := configs.VerifyTokenSet()
113+
if err != nil {
114+
tt.Errorf("Expected no error, got: %v", err)
115+
}
116+
117+
})
56118
}
57119

58120
func TestVerifyConfigsSetCorrectly(t *testing.T) {

examples/bitbucket.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,45 @@ To view all additional flags see the [sample-conf.yaml](https://github.com/gabri
88

99
## Bitbucket Cloud
1010

11+
### API Token Authentication (Recommended)
12+
13+
Bitbucket has deprecated App Passwords in favor of API Tokens. This is the recommended authentication method.
14+
15+
**Creating the API Token:**
16+
1. Go to your [Atlassian account settings](https://id.atlassian.com/manage/api-tokens)
17+
2. Create a new API token
18+
3. **Important**: Grant **all read scopes** (Account: Read, Workspace membership: Read, Projects: Read, Repositories: Read) to ensure ghorg can list and clone repositories
19+
20+
**Using the API Token:**
21+
22+
1. Clone the microsoft workspace using an API token
23+
24+
```
25+
ghorg clone microsoft --scm=bitbucket --bitbucket-api-email=<your-atlassian-email> --token=<api-token>
26+
```
27+
28+
1. Using environment variables (recommended for scripts)
29+
30+
```
31+
export GHORG_BITBUCKET_API_TOKEN=<api-token>
32+
export GHORG_BITBUCKET_API_EMAIL=<your-atlassian-email>
33+
ghorg clone microsoft --scm=bitbucket
34+
```
35+
36+
> Note: When using API tokens, ghorg automatically uses `x-bitbucket-api-token-auth` as the Git username for clone operations. The email is only used for API calls to list repositories.
37+
38+
### App Password Authentication (Legacy)
39+
40+
> Note: Bitbucket has deprecated App Passwords. Consider using API Tokens instead.
41+
1142
1. Clone the microsoft workspace using an app-password
1243
1344
```
1445
ghorg clone microsoft --scm=bitbucket --bitbucket-username=<your-username> --token=<app-password>
1546
```
1647
48+
### OAuth Token Authentication
49+
1750
1. Clone the microsoft workspace using oauth token
1851
1952
```

0 commit comments

Comments
 (0)