-
-
Notifications
You must be signed in to change notification settings - Fork 83
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #276 from pilcrowonpaper/next
Release v3.3.0
- Loading branch information
Showing
7 changed files
with
152 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
- Add Gitea provider ([#265](https://github.com/pilcrowonpaper/arctic/pull/265)). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
--- | ||
title: "Gitea" | ||
--- | ||
|
||
# Gitea | ||
|
||
OAuth 2.0 provider for Gitea. | ||
|
||
Also see [OAuth 2.0 with PKCE](/guides/oauth2-pkce). | ||
|
||
## Initialization | ||
|
||
The `baseURL` parameter is the full URL where the Gitea instance is hosted. Use `https://gitea.com` for managed servers. Pass the client secret for confidential clients. | ||
|
||
```ts | ||
import * as arctic from "arctic"; | ||
|
||
const baseURL = "https://gitea.com"; | ||
const baseURL = "https://my-app.com/gitea"; | ||
const gitea = new arctic.gitea(baseURL, clientId, clientSecret, redirectURI); | ||
const gitea = new arctic.gitea(baseURL, clientId, null, redirectURI); | ||
``` | ||
|
||
## Create authorization URL | ||
|
||
```ts | ||
import * as arctic from "arctic"; | ||
|
||
const state = arctic.generateState(); | ||
const codeVerifier = arctic.generateCodeVerifier(); | ||
const scopes = ["read:user", "write:notification"]; | ||
const url = gitea.createAuthorizationURL(state, codeVerifier, scopes); | ||
``` | ||
|
||
## Validate authorization code | ||
|
||
`validateAuthorizationCode()` will either return an [`OAuth2Tokens`](/reference/main/OAuth2Tokens), or throw one of [`OAuth2RequestError`](/reference/main/OAuth2RequestError), [`ArcticFetchError`](/reference/main/ArcticFetchError), [`UnexpectedResponseError`](/reference/main/UnexpectedResponseError), or [`UnexpectedErrorResponseBodyError`](/reference/main/UnexpectedErrorResponseBodyError). Gitea returns an access token, the access token expiration, and a refresh token. | ||
|
||
```ts | ||
import * as arctic from "arctic"; | ||
|
||
try { | ||
const tokens = await gitea.validateAuthorizationCode(code, codeVerifier); | ||
const accessToken = tokens.accessToken(); | ||
const accessTokenExpiresAt = tokens.accessTokenExpiresAt(); | ||
const refreshToken = tokens.refreshToken(); | ||
} catch (e) { | ||
if (e instanceof arctic.OAuth2RequestError) { | ||
// Invalid authorization code, credentials, or redirect URI | ||
const code = e.code; | ||
// ... | ||
} | ||
if (e instanceof arctic.ArcticFetchError) { | ||
// Failed to call `fetch()` | ||
const cause = e.cause; | ||
// ... | ||
} | ||
// Parse error | ||
} | ||
``` | ||
|
||
## Refresh access tokens | ||
|
||
Use `refreshAccessToken()` to get a new access token using a refresh token. This method's behavior is identical to `validateAuthorizationCode()`. | ||
|
||
```ts | ||
import * as arctic from "arctic"; | ||
|
||
try { | ||
const tokens = await gitea.refreshAccessToken(refreshToken); | ||
const accessToken = tokens.accessToken(); | ||
const accessTokenExpiresAt = tokens.accessTokenExpiresAt(); | ||
const refreshToken = tokens.refreshToken(); | ||
} catch (e) { | ||
if (e instanceof arctic.OAuth2RequestError) { | ||
// Invalid authorization code, credentials, or redirect URI | ||
} | ||
if (e instanceof arctic.ArcticFetchError) { | ||
// Failed to call `fetch()` | ||
} | ||
// Parse error | ||
} | ||
``` | ||
|
||
## Get user profile | ||
|
||
Add the `read:user` scope and use the [`/user` endpoint](https://gitea.com/api/swagger#/user). | ||
|
||
```ts | ||
const scopes = ["read:user"]; | ||
const url = gitea.createAuthorizationURL(state, codeVerifier, scopes); | ||
``` | ||
|
||
```ts | ||
const response = await fetch("https://gitea.com/user", { | ||
headers: { | ||
Authorization: `Bearer ${accessToken}` | ||
} | ||
}); | ||
const user = await response.json(); | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import { CodeChallengeMethod, OAuth2Client } from "../client.js"; | ||
import { joinURIAndPath } from "../request.js"; | ||
|
||
import type { OAuth2Tokens } from "../oauth2.js"; | ||
|
||
export class Gitea { | ||
private authorizationEndpoint: string; | ||
private tokenEndpoint: string; | ||
|
||
private client: OAuth2Client; | ||
|
||
constructor(baseURL: string, clientId: string, clientSecret: string | null, redirectURI: string) { | ||
this.authorizationEndpoint = joinURIAndPath(baseURL, "/login/oauth/authorize"); | ||
this.tokenEndpoint = joinURIAndPath(baseURL, "/login/oauth/access_token"); | ||
this.client = new OAuth2Client(clientId, clientSecret, redirectURI); | ||
} | ||
|
||
public createAuthorizationURL(state: string, codeVerifier: string, scopes: string[]): URL { | ||
const url = this.client.createAuthorizationURLWithPKCE( | ||
this.authorizationEndpoint, | ||
state, | ||
CodeChallengeMethod.S256, | ||
codeVerifier, | ||
scopes | ||
); | ||
return url; | ||
} | ||
|
||
public async validateAuthorizationCode( | ||
code: string, | ||
codeVerifier: string | ||
): Promise<OAuth2Tokens> { | ||
const tokens = await this.client.validateAuthorizationCode( | ||
this.tokenEndpoint, | ||
code, | ||
codeVerifier | ||
); | ||
return tokens; | ||
} | ||
|
||
public async refreshAccessToken(refreshToken: string): Promise<OAuth2Tokens> { | ||
const tokens = await this.client.refreshAccessToken(this.tokenEndpoint, refreshToken, []); | ||
return tokens; | ||
} | ||
} |