-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
87d8d13
commit b2fae42
Showing
15 changed files
with
1,522 additions
and
905 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
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,102 @@ | ||
# `OAuthService` | ||
|
||
The `OAuthService` class is designed to abstract the OAuth authorization process using the PKCE (Proof Key for Code Exchange) flow, simplifying the integration with various OAuth providers such as Asana, GitHub, and others. | ||
|
||
## Initialization | ||
|
||
Construct an instance of a provider-specific `OAuthService` with the required parameters: | ||
|
||
- `client`: The PKCE Client defined using `OAuth.PKCEClient` from `@raycast/api` | ||
- `clientId`: The app's client ID. | ||
- `scope`: The scope of the access requested from the provider. | ||
- `authorizeUrl`: The URL to start the OAuth flow. | ||
- `tokenUrl`: The URL to exchange the authorization code for an access token. | ||
- `refreshTokenUrl`: (Optional) The URL to refresh the access token if applicable. | ||
- `personalAccessToken`: (Optional) A personal token if the provider supports it. | ||
- `extraParameters`: (Optional) The extra parameters you may need for the authorization request. | ||
- `bodyEncoding`: (Optional) Specifies the format for sending the body of the request. Can be `json` for JSON-encoded body content or `url-encoded` for URL-encoded form data. | ||
|
||
### Example | ||
|
||
```ts | ||
const client = new OAuth.PKCEClient({ | ||
redirectMethod: OAuth.RedirectMethod.Web, | ||
providerName: "GitHub", | ||
providerIcon: "extension_icon.png", | ||
providerId: "github", | ||
description: "Connect your GitHub account", | ||
}); | ||
|
||
const github = new OAuthService({ | ||
client, | ||
clientId: "7235fe8d42157f1f38c0", | ||
scopes: "notifications repo read:org read:user read:project", | ||
authorizeUrl: "https://github.oauth.raycast.com/authorize", | ||
tokenUrl: "https://github.oauth.raycast.com/token", | ||
}); | ||
``` | ||
|
||
## Subclassing | ||
|
||
You can subclass `OAuthService` to create a tailored service for other OAuth providers by setting predefined defaults. | ||
|
||
Here's an example where `LinearOAuthService` subclasses `OAuthService`: | ||
|
||
```ts | ||
export class LinearOAuthService extends OAuthService { | ||
constructor(options: ClientConstructor) { | ||
super({ | ||
client: new OAuth.PKCEClient({ | ||
redirectMethod: OAuth.RedirectMethod.Web, | ||
providerName: "Linear", | ||
providerIcon: "linear.png", | ||
providerId: "linear", | ||
description: "Connect your Linear account", | ||
}), | ||
clientId: "YOUR_CLIENT_ID", | ||
authorizeUrl: "YOUR_AUTHORIZE_URL", | ||
tokenUrl: "YOUR_TOKEN_URL", | ||
scope: "YOUR_SCOPES" | ||
extraParameters: { | ||
actor: "user", | ||
}, | ||
}); | ||
} | ||
} | ||
``` | ||
|
||
## Built-in 3rd-party providers | ||
|
||
Some 3rd-party providers subclassing `OAuthService` are exposed by default to make it easy to authenticate with them. Here's the full list: | ||
|
||
- `AsanaOAuthService` | ||
- `GitHubOAuthService` | ||
- `GoogleOAuthService` | ||
- `JiraOAuthService` | ||
- `LinearOAuthService` | ||
- `SlackOAuthService` | ||
- `ZoomOAuthService` | ||
|
||
### Example | ||
|
||
Here's a basic example of how you'd use `GitHubOAuthService`: | ||
|
||
```tsx | ||
import { GitHubOAuthService } from "@your/library"; | ||
|
||
const github = new GitHubOAuthService({ scope: "notifications repo read:org read:user read:project" }); | ||
``` | ||
|
||
Note that you can also use your own client ID and provide a personal access token if needed: | ||
|
||
```tsx | ||
import { GitHubOAuthService } from "@your/library"; | ||
|
||
const preferences = getPreferenceValues<Preferences>() | ||
|
||
const github = new GitHubOAuthService({ | ||
clientId: "YOUR_CLIENT_ID", | ||
personalAccessToken: preferences.token, | ||
scope: "notifications repo read:org read:user read:project" | ||
}); | ||
``` |
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,62 @@ | ||
# OAuth | ||
|
||
Authenticating with OAuth in Raycast extensions is tedious. So we've built a set of utilities to make that task way easier. There's two part to our utilities: | ||
|
||
1. Authenticating with the service using [OAuthService](utils-reference/oauth/OAuthService.md) and providers we provide out of the box (e.g GitHub with `GitHubOAuthService`) | ||
2. Bringing authentication to React components using [withAccessToken](utils-reference/oauth/withAccessToken.md) and [`getAccessToken`](utils-reference/oauth/withAccessToken.md#getAccessToken) | ||
|
||
Here are two different use-cases where you can use the utilities. | ||
|
||
## Using a built-in provider | ||
|
||
We provide 3rd party providers that you can use out of the box such as GitHub or Linear. Here's how you can use them: | ||
|
||
```tsx | ||
import { Detail, LaunchProps } from "@raycast/api"; | ||
import { withAccessToken, getAccessToken, GitHubOAuthService } from "@raycast/utils"; | ||
|
||
const github = new GitHubOAuthService({ | ||
scopes: "notifications repo read:org read:user read:project" | ||
}); | ||
|
||
function AuthorizedComponent(props: LaunchProps) { | ||
const { token } = getAccessToken(); | ||
return <Detail markdown={`Access token: ${token}`} />; | ||
} | ||
|
||
export default withAccessToken(github)(AuthorizedComponent); | ||
``` | ||
|
||
## Using your own client | ||
|
||
```tsx | ||
import { OAuth, Detail, LaunchProps } from "@raycast/api"; | ||
import { withAccessToken, getAccessToken, getAuthorizeFunction } from "@raycast/utils/oauth"; | ||
|
||
const client = new OAuth.PKCEClient({ | ||
redirectMethod: OAuth.RedirectMethod.Web, | ||
providerName: "Your Provider Name", | ||
providerIcon: "provider_icon.png", | ||
providerId: "yourProviderId", | ||
description: "Connect your {PROVIDER_NAME} account", | ||
}); | ||
|
||
const provider = new OAuthService({ | ||
client, | ||
clientId: "YOUR_CLIENT_ID", | ||
scopes: "YOUR SCOPES", | ||
authorizeUrl: "YOUR_AUTHORIZE_URL", | ||
tokenUrl: "YOUR_TOKEN_URL", | ||
}); | ||
|
||
function AuthorizedComponent(props: LaunchProps) { | ||
const { token } = getAccessToken(); | ||
return <Detail markdown={`Access token: ${token}`} />; | ||
} | ||
|
||
export default withAccessToken({ authorize: provider.authorize })(AuthorizedComponent); | ||
``` | ||
|
||
## Additional information | ||
|
||
If you need more information, please take a look at the subpages: [OAuthService](utils-reference/oauth/OAuthService.md) and [withAccessToken](utils-reference/oauth/withAccessToken.md) |
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,111 @@ | ||
# `withAccessToken` | ||
|
||
Higher-order component fetching an authorization token to then access it. This makes it easier to handle OAuth in your different commands/components. | ||
|
||
## Signature | ||
|
||
```tsx | ||
type OAuthType = "oauth" | "personal"; | ||
|
||
type OnAuthorizeParams = { | ||
token: string; | ||
type: OAuthType; | ||
idToken: string | null; | ||
}; | ||
|
||
type WithAccessTokenParameters = { | ||
client?: OAuth.PKCEClient; | ||
authorize: () => Promise<string>; | ||
personalAccessToken?: string; | ||
onAuthorize?: (params: OnAuthorizeParams) => void; | ||
}; | ||
|
||
function withAccessToken<T>( | ||
options: WithAccessTokenParameters, | ||
): <U extends (() => Promise<void> | void) | React.ComponentType<T>>( | ||
fnOrComponent: U, | ||
) => U extends () => Promise<void> | void ? Promise<void> : React.FunctionComponent<T>; | ||
``` | ||
|
||
### Arguments | ||
|
||
`options` is an object containing: | ||
- `options.client` is an instance of a PKCE Client that you can create using Raycast API. | ||
- `options.authorize` is a promise that initiates the OAuth token retrieval process and resolves to a token string. | ||
- `options.personalAccessToken` is an optional string that represents an already obtained personal access token. When `options.personalAccessToken` is provided, it uses that token. Otherwise, it calls `options.authorize` to fetch an OAuth token asynchronously. | ||
- `options.onAuthorize` is a callback function that is called with the `token`, its `type`, and its `idToken` once the user has been properly logged in through OAuth. | ||
|
||
### Return | ||
|
||
Returns the wrapped component if used in a `view` command or the wrapped function if used in a `no-view` command. | ||
|
||
{% hint style="info" %} | ||
Note that the access token isn't injected into the wrapped component props. Instead, it's been set as a global variable that you can get with `getAccessToken`. | ||
{% endhint %} | ||
|
||
## Example | ||
|
||
```tsx | ||
import { Detail } from "@raycast/api"; | ||
import { withAccessToken } from "@raycast/utils"; | ||
import { authorize } from "./oauth" | ||
|
||
function AuthorizedComponent(props) { | ||
return <List ... />; | ||
} | ||
|
||
export default withAccessToken({ authorize })(AuthorizedComponent); | ||
``` | ||
|
||
Note that it also works for `no-view` commands as stated above: | ||
|
||
```tsx | ||
import { Detail } from "@raycast/api"; | ||
import { withAccessToken } from "@raycast/utils"; | ||
import { authorize } from "./oauth" | ||
|
||
async function AuthorizedCommand() { | ||
await showHUD("Authorized"); | ||
} | ||
|
||
export default withAccessToken({ authorize })(AuthorizedCommand); | ||
``` | ||
|
||
## `getAccessToken` | ||
|
||
Utility function designed for retrieving authorization tokens within a component. It ensures that your React components have the necessary authentication state, either through OAuth or a personal access token. | ||
|
||
{% hint style="info" %} | ||
`getAccessToken` **must** be used within components that are nested inside a component wrapped with `withAccessToken`. | ||
{% endhint %} | ||
|
||
### Signature | ||
|
||
```tsx | ||
function getAccessToken(): { | ||
token: string; | ||
type: "oauth" | "personal"; | ||
} | ||
``` | ||
|
||
#### Return | ||
|
||
The function returns an object containing the following properties: | ||
- `token`: A string representing the access token. | ||
- `type`: An optional string that indicates the type of token retrieved. It can either be `oauth` for OAuth tokens or `personal` for personal access tokens. | ||
|
||
### Example | ||
|
||
Here's a simple example: | ||
|
||
```tsx | ||
import { Detail } from "@raycast/api"; | ||
import { authorize } from "./oauth" | ||
|
||
function AuthorizedComponent() { | ||
const { token } = getAccessToken(); | ||
return <Detail markdown={`Access token: ${token}`} />; | ||
} | ||
|
||
export default withAccessToken({ authorize })(AuthorizedComponent); | ||
``` |
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
Oops, something went wrong.