From 79ce24bc6fb5079b226f64fe2a7558062be0e1f5 Mon Sep 17 00:00:00 2001 From: Jonas Franz Date: Sun, 14 Apr 2019 10:42:11 +0200 Subject: [PATCH] Add oauth2 documentation (#6604) * Add oauth2 documentation Signed-off-by: Jonas Franz * Apply suggestions from code review Co-Authored-By: jonasfranz * Update docs/content/doc/advanced/oauth2-provider.md Co-Authored-By: jonasfranz * Update oauth2-provider.md --- docs/content/doc/advanced/api-usage.en-us.md | 8 ++ docs/content/doc/advanced/oauth2-provider.md | 92 +++++++++++++++++++ docs/static/authorize.png | Bin 0 -> 18951 bytes 3 files changed, 100 insertions(+) create mode 100644 docs/content/doc/advanced/oauth2-provider.md create mode 100644 docs/static/authorize.png diff --git a/docs/content/doc/advanced/api-usage.en-us.md b/docs/content/doc/advanced/api-usage.en-us.md index d5a7b3a6ef..c5db817fdb 100644 --- a/docs/content/doc/advanced/api-usage.en-us.md +++ b/docs/content/doc/advanced/api-usage.en-us.md @@ -39,6 +39,14 @@ Gitea parses queries and headers to find the token in You can create an API key token via your Gitea installation's web interface: `Settings | Applications | Generate New Token`. +### OAuth2 + +Access tokens obtained from Gitea's [OAuth2 provider](https://docs.gitea.io/en-us/oauth2-provider) are accepted by these methods: + +- `Authorization bearer ...` header in HTTP headers +- `token=...` parameter in URL query string +- `access_token=...` parameter in URL query string + ### More on the `Authorization:` header For historical reasons, Gitea needs the word `token` included before diff --git a/docs/content/doc/advanced/oauth2-provider.md b/docs/content/doc/advanced/oauth2-provider.md new file mode 100644 index 0000000000..c924d1ce07 --- /dev/null +++ b/docs/content/doc/advanced/oauth2-provider.md @@ -0,0 +1,92 @@ +--- +date: "2019-04-19:44:00+01:00" +title: "OAuth2 provider" +slug: "oauth2-provider" +weight: 41 +toc: true +draft: false +menu: + sidebar: + parent: "advanced" + name: "OAuth2 Provider" + weight: 41 + identifier: "oauth2-provider" +--- + + +# OAuth2 provider + +Gitea supports acting as an OAuth2 provider to allow third party applications to access its resources with the user's consent. This feature is available since release 1.8.0. + +## Endpoints + + +Endpoint | URL +-----------------------|---------------------------- +Authorization Endpoint | `/login/oauth/authorize` +Access Token Endpoint | `/login/oauth/access_token` + + +## Supported OAuth2 Grants + +At the moment Gitea only supports the [**Authorization Code Grant**](https://tools.ietf.org/html/rfc6749#section-1.3.1) standard with additional support of the [Proof Key for Code Exchange (PKCE)](https://tools.ietf.org/html/rfc7636) extension. + + +To use the Authorization Code Grant as a third party application it is required to register a new application via the "Settings" (`/user/settings/applications`) section of the settings. + +## Scopes + +Currently Gitea does not support scopes (see [#4300](https://github.com/go-gitea/gitea/issues/4300)) and all third party applications will be granted access to all resources of the user and his/her organizations. + +## Example + +**Note:** This example does not use PKCE. + +1. Redirect to user to the authorization endpoint in order to get his/her consent for accessing the resources: + +```curl +https://[YOUR-GITEA-URL]/login/oauth/authorize?client_id=CLIENT_ID&redirect_uri=REDIRECT_URI& response_type=code&state=STATE +``` + +The `CLIENT_ID` can be obtained by registering an application in the settings. The `STATE` is a random string that will be send back to your application after the user authorizes. The `state` parameter is optional but should be used to prevent CSRF attacks. + + +![Authorization Page](/authorize.png) + +The user will now be asked to authorize your application. If they authorize it, the user will be redirected to the `REDIRECT_URL`, for example: + +```curl +https://[REDIRECT_URI]?code=RETURNED_CODE&state=STATE +``` + +2. Using the provided `code` from the redirect, you can request a new application and refresh token. The access token endpoints accepts POST requests with `application/json` and `application/x-www-form-urlencoded` body, for example: + +```curl +POST https://[YOUR-GITEA-URL]/login/oauth/access_token +``` + +```json +{ + "client_id": "YOUR_CLIENT_ID", + "client_secret": "YOUR_CLIENT_SECRET", + "code": "RETURNED_CODE", + "grant_type": "authorization_code", + "redirect_uri": "REDIRECT_URI" +} +``` + +Response: +```json +{ +"access_token":"eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJnbnQiOjIsInR0IjowLCJleHAiOjE1NTUxNzk5MTIsImlhdCI6MTU1NTE3NjMxMn0.0-iFsAwBtxuckA0sNZ6QpBQmywVPz129u75vOM7wPJecw5wqGyBkmstfJHAjEOqrAf_V5Z-1QYeCh_Cz4RiKug", +"token_type":"bearer", +"expires_in":3600, +"refresh_token":"eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJnbnQiOjIsInR0IjoxLCJjbnQiOjEsImV4cCI6MTU1NzgwNDMxMiwiaWF0IjoxNTU1MTc2MzEyfQ.S_HZQBy4q9r5SEzNGNIoFClT43HPNDbUdHH-GYNYYdkRfft6XptJBkUQscZsGxOW975Yk6RbgtGvq1nkEcklOw" +} +``` + +The `CLIENT_SECRET` is the unique secret code generated for this application. Please note that the secret will only be visible after you created/registered the application with Gitea and cannot be recovered. If you lose the secret you must regenerate the secret via the application's settings. + +The `REDIRECT_URI` in the `access_token` request must match the `REDIRECT_URI` in the `authorize` request. + +3. Use the `access_token` to make [API requests](https://docs.gitea.io/en-us/api-usage#oauth2) to access the user's resources. diff --git a/docs/static/authorize.png b/docs/static/authorize.png new file mode 100644 index 0000000000000000000000000000000000000000..7556b1220cd21c0c7b08cbb2ff99b7af91043397 GIT binary patch literal 18951 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