OAuth
Last updated
Last updated
A Raycast extension can use OAuth for authorizing access to a provider's resources on the user's behalf. Since Raycast is a desktop app and the extensions are considered "public", we only support the PKCE flow (Proof Key for Code Exchange, pronounced “pixy”). This flow is the official recommendation for native clients that cannot keep a client secret. With PKCE, the client dynamically creates a secret and uses the secret again during code exchange, ensuring that only the client that performed the initial request can exchange the code for the access token (”proof of possession”).
Providers such as Google, Twitter, GitLab, Spotify, Zoom, Asana or Dropbox are all PKCE-ready.
However, if your provider doesn't support PKCE, you can use our PKCE proxy. It allows extensions to securely use an OAuth flow without exposing any secret.
The OAuth flow from an extension looks like this:
The extension initiates the OAuth flow and starts authorization
Raycast shows the OAuth overlay ("Connect to provider…")
The user opens the provider's consent page in the web browser
After the user consent, the provider redirects back to Raycast
Raycast opens the extension where authorization is completed
When the flow is complete, the extension has received an access token from the provider and can perform API calls. The API provides functions for securely storing and retrieving token sets, so that an extension can check whether the user is already logged in and whether an expired access token needs to be refreshed. Raycast also automatically shows a logout preference.
You first need to register a new OAuth app with your provider. This is usually done in the provider's developer portal. After registering, you will receive a client ID. You also need to configure a redirect URI, see the next section.
Note: Make sure to choose an app type that supports PKCE. Some providers still show you a client secret, which you don't need and should not hardcode in the extension, or support PKCE only for certain types such as "desktop", "native" or "mobile" app types.
An extension can initiate the OAuth flow and authorize by using the methods on OAuth.PKCEClient.
You can create a new client and configure it with a provider name, icon and description that will be shown in the OAuth overlay. You can also choose between different redirect methods; depending on which method you choose, you need to configure this value as redirect URI in your provider's registered OAuth app. (See the OAuth.RedirectMethod docs for each method to get concrete examples for supported redirect URI.) If you can choose, use OAuth.RedirectMethod.Web
and enter https://raycast.com/redirect?packageName=Extension
(whether you have to add the ?packageName=Extension
depends on the provider).
Next you create an authorization request with the authorization endpoint, client ID, and scope values. You receive all values from your provider's docs and when you register a new OAuth app.
The returned AuthorizationRequest contains parameters such as the code challenge, verifier, state and redirect URI as standard OAuth authorization request. You can also customize the authorization URL through OAuth.AuthorizationOptions if you need to.
To get the authorization code needed for the token exchange, you call authorize with the request from the previous step. This call shows the Raycast OAuth overlay and provides the user with an option to open the consent page in the web browser. The authorize promise is resolved after the redirect back to Raycast and into the extension:
When in development mode, make sure not to trigger auto-reloading (e.g. by saving a file) while you're testing an active OAuth authorization and redirect. This would cause an OAuth state mismatch when you're redirected back into the extension since the client would be reinitialized on reload.
Now that you have received the authorization code, you can exchange this code for an access token using your provider's token endpoint. This token exchange (and the following API calls) can be done with your preferred Node HTTP client library. Example using node-fetch
:
The PKCE client exposes methods for storing, retrieving and deleting token sets. A TokenSet contains an access token and typically also a refresh token, expires value, and the current scope. Since this data is returned by the provider's token endpoint as standard OAuth JSON response, you can directly store the response (OAuth.TokenResponse) or alternatively use OAuth.TokenSetOptions:
Once the token set is stored, Raycast will automatically show a logout preference for the extension. When the user logs out, the token set gets removed.
The TokenSet also enables you to check whether the user is logged in before starting the authorization flow:
Since access tokens usually expire, an extension should provide a way to refresh the access token, otherwise users would be logged out or see errors. Some providers require you to add an offline scope so that you get a refresh token. (Twitter, for example, needs the scope offline.access
or it only returns an access token.) A basic refresh flow could look like this:
This code would run before starting the authorization flow. It checks the presence of a token set to see whether the user is logged in and then checks whether there is a refresh token and the token set is expired (through the convenience method isExpired()
on the TokenSet). If it is expired, the token is refreshed and updated in the token set. Example using node-fetch
:
We've provided OAuth example integrations for Google, Twitter, and Dropbox that demonstrate the entire flow shown above.
Use OAuth.PKCEClient.Options to configure what's shown on the OAuth overlay.
Method |
---|
Creates an authorization request for the provided authorization endpoint, client ID, and scopes. You need to first create the authorization request before calling authorize.
The generated code challenge for the PKCE request uses the S256 method.
Name | Type | Description |
---|---|---|
options* | The options used to create the authorization request. |
A promise for an AuthorizationRequest that you can use as input for authorize.
Starts the authorization and shows the OAuth overlay in Raycast. As parameter you can either directly use the returned request from authorizationRequest, or customize the URL by extracting parameters from AuthorizationRequest and providing your own URL via AuthorizationOptions. Eventually the URL will be used to open the authorization page of the provider in the web browser.
Name | Type | Description |
---|---|---|
options* | The options used to authorize. |
A promise for an AuthorizationResponse, which contains the authorization code needed for the token exchange. The promise is resolved when the user was redirected back from the provider's authorization page to the Raycast extension.
Securely stores a TokenSet for the provider. Use this after fetching the access token from the provider. If the provider returns a a standard OAuth JSON token response, you can directly pass the TokenResponse. At a minimum, you need to set the accessToken
, and typically you also set refreshToken
and isExpired
.
Raycast automatically shows a logout preference for the extension when a token set was saved.
If you want to make use of the convenience isExpired()
method, the property expiresIn
must be configured.
Name | Type | Description |
---|---|---|
options* | The options used to store the token set. |
A promise that resolves when the token set has been stored.
Retrieves the stored TokenSet for the client. You can use this to initially check whether the authorization flow should be initiated or the user is already logged in and you might have to refresh the access token.
A promise that resolves when the token set has been retrieved.
Removes the stored TokenSet for the client. Raycast automatically shows a logout preference that removes the token set. Use this method only if you need to provide an additional logout option in your extension or you want to remove the token set because of a migration.
A promise that resolves when the token set has been removed.
The options for creating a new PKCEClient.
Property | Description | Type |
---|---|---|
providerName* | The name of the provider, displayed in the OAuth overlay. |
|
redirectMethod* | The redirect method for the OAuth flow. Make sure to set this to the correct method for the provider, see OAuth.RedirectMethod for more information. | |
description | An optional description, shown in the OAuth overlay. You can use this to customize the message for the end user, for example for handling scope changes or other migrations. Raycast shows a default message if this is not configured. |
|
providerIcon | An icon displayed in the OAuth overlay. Make sure to provide at least a size of 64x64 pixels. | |
providerId | An optional ID for associating the client with a provider. Only set this if you use multiple different clients in your extension. |
|
Defines the supported redirect methods for the OAuth flow. You can choose between web and app-scheme redirect methods, depending on what the provider requires when setting up the OAuth app. For examples on what redirect URI you need to configure, see the docs for each method.
Name | Value |
---|---|
Web | Use this type for a redirect back to the Raycast website, which will then open the extension. In the OAuth app, configure |
App | Use this type for an app-scheme based redirect that directly opens Raycast. In the OAuth app, configure |
AppURI | Use this type for a URI-style app scheme that directly opens Raycast. In the OAuth app, configure |
The options for an authorization request via authorizationRequest.
Property | Description | Type |
---|---|---|
clientId* | The client ID of the configured OAuth app. |
|
endpoint* | The URL to the authorization endpoint for the OAuth provider. |
|
scope* | A space-delimited list of scopes for identifying the resources to access on the user's behalf. The scopes are typically shown to the user on the provider's consent screen in the browser. Note that some providers require the same scopes be configured in the registered OAuth app. |
|
extraParameters | Optional additional parameters for the authorization request. Note that some providers require additional parameters, for example to obtain long-lived refresh tokens. |
|
Values of AuthorizationRequest. The PKCE client automatically generates the values for you and returns them for authorizationRequest
Property | Description | Type |
---|---|---|
codeChallenge* | The PKCE |
|
codeVerifier* | The PKCE |
|
redirectURI* | The OAuth |
|
state* | The OAuth |
|
The request returned by authorizationRequest. Can be used as direct input to authorize, or to extract parameters for constructing a custom URL in AuthorizationOptions.
Property | Description | Type |
---|---|---|
codeChallenge* | The PKCE |
|
codeVerifier* | The PKCE |
|
redirectURI* | The OAuth |
|
state* | The OAuth |
|
toURL* | Constructs the full authorization URL. |
|
Name | Type | Description |
---|---|---|
toURL() |
| Constructs the full authorization URL. |
Options for customizing authorize. You can use values from AuthorizationRequest to build your own URL.
Property | Description | Type |
---|---|---|
url* | The full authorization URL. |
|
The response returned by authorize, containing the authorization code after the provider redirect. You can then exchange the authorization code for an access token using the provider's token endpoint.
Property | Description | Type |
---|---|---|
authorizationCode* | The authorization code from the OAuth provider. |
|
Describes the TokenSet created from an OAuth provider's token response. The accessToken
is the only required parameter but typically OAuth providers also return a refresh token, an expires value, and the scope. Securely store a token set via setTokens and retrieve it via getTokens.
Property | Description | Type |
---|---|---|
accessToken* | The access token returned by an OAuth token request. |
|
updatedAt* | The date when the token set was stored via OAuth.PKCEClient.setTokens. |
|
isExpired* | A convenience method for checking whether the access token has expired. The method factors in some seconds of "buffer", so it returns true a couple of seconds before the actual expiration time. This requires the |
|
expiresIn | An optional expires value (in seconds) returned by an OAuth token request. |
|
idToken | An optional id token returned by an identity request (e.g. /me, Open ID Connect). |
|
refreshToken | An optional refresh token returned by an OAuth token request. |
|
scope | The optional space-delimited list of scopes returned by an OAuth token request. You can use this to compare the currently stored access scopes against new access scopes the extension might require in a future version, and then ask the user to re-authorize with new scopes. |
|
Name | Type | Description |
---|---|---|
isExpired() |
| A convenience method for checking whether the access token has expired. The method factors in some seconds of "buffer", so it returns true a couple of seconds before the actual expiration time. This requires the |
Options for a TokenSet to store via setTokens.
Property | Description | Type |
---|---|---|
accessToken* | The access token returned by an OAuth token request. |
|
expiresIn | An optional expires value (in seconds) returned by an OAuth token request. |
|
idToken | An optional id token returned by an identity request (e.g. /me, Open ID Connect). |
|
refreshToken | An optional refresh token returned by an OAuth token request. |
|
scope | The optional scope value returned by an OAuth token request. |
|
Defines the standard JSON response for an OAuth token request. The response can be directly used to store a TokenSet via setTokens.
Property | Description | Type |
---|---|---|
access_token* | The |
|
expires_in | An optional |
|
id_token | An optional |
|
refresh_token | An optional |
|
scope | The optional |
|