Skip to content

Fix user token API endpoints #27040

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions docs/content/development/api-usage.en-us.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,13 @@ Gitea parses queries and headers to find the token in
## Generating and listing API tokens

A new token can be generated with a `POST` request to
`/users/:name/tokens`.
`/user/tokens`.

Note that `/users/:name/tokens` is a special endpoint and requires you
Note that `/user/tokens` is a special endpoint and requires you
to authenticate using `BasicAuth` and a password, as follows:

```sh
$ curl -H "Content-Type: application/json" -d '{"name":"test"}' -u username:password https://gitea.your.host/api/v1/users/<username>/tokens
$ curl -H "Content-Type: application/json" -d '{"name":"test"}' -u username:password https://gitea.your.host/api/v1/user/tokens
{"id":1,"name":"test","sha1":"9fcb1158165773dd010fca5f0cf7174316c3e37d","token_last_eight":"16c3e37d"}
```

Expand All @@ -56,7 +56,7 @@ plain-text. It will not be displayed when listing tokens with a `GET`
request; e.g.

```sh
$ curl --url https://yourusername:[email protected]/api/v1/users/<username>/tokens
$ curl --url https://yourusername:[email protected]/api/v1/user/tokens
[{"name":"test","sha1":"","token_last_eight:"........":},{"name":"dev","sha1":"","token_last_eight":"........"}]
```

Expand All @@ -68,7 +68,7 @@ is where you'd place the code from your authenticator.
Here is how the request would look like in curl:

```sh
$ curl -H "X-Gitea-OTP: 123456" --url https://yourusername:[email protected]/api/v1/users/yourusername/tokens
$ curl -H "X-Gitea-OTP: 123456" --url https://yourusername:[email protected]/api/v1/user/tokens
```

You can also create an API key token via your Gitea installation's web
Expand Down
6 changes: 6 additions & 0 deletions modules/context/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,12 @@ type APIInvalidTopicsError struct {
// swagger:response empty
type APIEmpty struct{}

// APIUnauthorizedError is a unauthorized error response
// swagger:response unauthorized
type APIUnauthorizedError struct {
APIError
}

// APIForbiddenError is a forbidden error response
// swagger:response forbidden
type APIForbiddenError struct {
Expand Down
12 changes: 9 additions & 3 deletions routers/api/v1/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -904,9 +904,9 @@ func Routes() *web.Route {

m.Get("/repos", tokenRequiresScopes(auth_model.AccessTokenScopeCategoryRepository), reqExploreSignIn(), user.ListUserRepos)
m.Group("/tokens", func() {
m.Combo("").Get(user.ListAccessTokens).
Post(bind(api.CreateAccessTokenOption{}), reqToken(), user.CreateAccessToken)
m.Combo("/{id}").Delete(reqToken(), user.DeleteAccessToken)
m.Combo("").Get(user.ListAccessTokensOld).
Post(bind(api.CreateAccessTokenOption{}), reqToken(), user.CreateAccessTokenOld)
m.Combo("/{id}").Delete(reqToken(), user.DeleteAccessTokenOld)
}, reqBasicOrRevProxyAuth())

m.Get("/activities/feeds", user.ListUserActivityFeeds)
Expand Down Expand Up @@ -968,6 +968,12 @@ func Routes() *web.Route {
Delete(user.DeletePublicKey)
})

m.Group("/tokens", func() {
m.Combo("").Get(reqToken(), user.ListAccessTokens).
Post(bind(api.CreateAccessTokenOption{}), reqToken(), user.CreateAccessToken)
m.Combo("/{id}").Delete(reqToken(), user.DeleteAccessToken)
}, reqBasicOrRevProxyAuth())

// (admin:application scope)
m.Group("/applications", func() {
m.Combo("/oauth2").
Expand Down
116 changes: 99 additions & 17 deletions routers/api/v1/user/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,12 @@ import (

// ListAccessTokens list all the access tokens
func ListAccessTokens(ctx *context.APIContext) {
// swagger:operation GET /users/{username}/tokens user userGetTokens
// swagger:operation GET /user/tokens user userGetTokens
// ---
// summary: List the authenticated user's access tokens
// produces:
// - application/json
// parameters:
// - name: username
// in: path
// description: username of user
// type: string
// required: true
// - name: page
// in: query
// description: page number of results to return (1-based)
Expand All @@ -43,6 +38,8 @@ func ListAccessTokens(ctx *context.APIContext) {
// responses:
// "200":
// "$ref": "#/responses/AccessTokenList"
// "401":
// "$ref": "#/responses/unauthorized"

opts := auth_model.ListAccessTokensOptions{UserID: ctx.Doer.ID, ListOptions: utils.GetListOptions(ctx)}

Expand Down Expand Up @@ -71,21 +68,46 @@ func ListAccessTokens(ctx *context.APIContext) {
ctx.JSON(http.StatusOK, &apiTokens)
}

// ListAccessTokensOld is a compatibility layer for ListAccessTokens
func ListAccessTokensOld(ctx *context.APIContext) {
// swagger:operation GET /users/{username}/tokens user userGetTokensOld
// ---
// summary: List the authenticated user's access tokens
// deprecated: true
// produces:
// - application/json
// parameters:
// - name: username
// in: path
// description: username of user
// type: string
// required: true
// - name: page
// in: query
// description: page number of results to return (1-based)
// type: integer
// - name: limit
// in: query
// description: page size of results
// type: integer
// responses:
// "200":
// "$ref": "#/responses/AccessTokenList"
// "401":
// "$ref": "#/responses/unauthorized"
ListAccessTokens(ctx)
}

// CreateAccessToken create access tokens
func CreateAccessToken(ctx *context.APIContext) {
// swagger:operation POST /users/{username}/tokens user userCreateToken
// swagger:operation POST /user/tokens user userCreateToken
// ---
// summary: Create an access token
// consumes:
// - application/json
// produces:
// - application/json
// parameters:
// - name: username
// in: path
// description: username of user
// required: true
// type: string
// - name: body
// in: body
// schema:
Expand All @@ -95,6 +117,8 @@ func CreateAccessToken(ctx *context.APIContext) {
// "$ref": "#/responses/AccessToken"
// "400":
// "$ref": "#/responses/error"
// "401":
// "$ref": "#/responses/unauthorized"

form := web.GetForm(ctx).(*api.CreateAccessTokenOption)

Expand Down Expand Up @@ -132,19 +156,44 @@ func CreateAccessToken(ctx *context.APIContext) {
})
}

// DeleteAccessToken delete access tokens
func DeleteAccessToken(ctx *context.APIContext) {
// swagger:operation DELETE /users/{username}/tokens/{token} user userDeleteAccessToken
// CreateAccessTokenOld is a compatibility layer for CreateAccessToken
func CreateAccessTokenOld(ctx *context.APIContext) {
// swagger:operation POST /users/{username}/tokens user userCreateTokenOld
// ---
// summary: delete an access token
// summary: Create an access token
// deprecated: true
// consumes:
// - application/json
// produces:
// - application/json
// parameters:
// - name: username
// in: path
// description: username of user
// type: string
// required: true
// type: string
// - name: body
// in: body
// schema:
// "$ref": "#/definitions/CreateAccessTokenOption"
// responses:
// "201":
// "$ref": "#/responses/AccessToken"
// "400":
// "$ref": "#/responses/error"
// "401":
// "$ref": "#/responses/unauthorized"
CreateAccessToken(ctx)
}

// DeleteAccessToken delete access tokens
func DeleteAccessToken(ctx *context.APIContext) {
// swagger:operation DELETE /user/tokens/{token} user userDeleteAccessToken
// ---
// summary: delete an access token
// produces:
// - application/json
// parameters:
// - name: token
// in: path
// description: token to be deleted, identified by ID and if not available by name
Expand All @@ -153,6 +202,8 @@ func DeleteAccessToken(ctx *context.APIContext) {
// responses:
// "204":
// "$ref": "#/responses/empty"
// "401":
// "$ref": "#/responses/unauthorized"
// "404":
// "$ref": "#/responses/notFound"
// "422":
Expand Down Expand Up @@ -199,6 +250,37 @@ func DeleteAccessToken(ctx *context.APIContext) {
ctx.Status(http.StatusNoContent)
}

// DeleteAccessTokenOld is a compatibility layer for DeleteAccessToken
func DeleteAccessTokenOld(ctx *context.APIContext) {
// swagger:operation DELETE /users/{username}/tokens/{token} user userDeleteAccessTokenOld
// ---
// summary: delete an access token
// deprecated: true
// produces:
// - application/json
// parameters:
// - name: username
// in: path
// description: username of user
// type: string
// required: true
// - name: token
// in: path
// description: token to be deleted, identified by ID and if not available by name
// type: string
// required: true
// responses:
// "204":
// "$ref": "#/responses/empty"
// "401":
// "$ref": "#/responses/unauthorized"
// "404":
// "$ref": "#/responses/notFound"
// "422":
// "$ref": "#/responses/error"
DeleteAccessToken(ctx)
}

// CreateOauth2Application is the handler to create a new OAuth2 Application for the authenticated user
func CreateOauth2Application(ctx *context.APIContext) {
// swagger:operation POST /user/applications/oauth2 user userCreateOAuth2Application
Expand Down
Loading