> For the complete documentation index, see [llms.txt](https://docs.roboflow.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.roboflow.com/reference/authentication/authentication/sign-in-with-roboflow-getting-started.md).

# Sign In With Roboflow (Getting Started)

Let users sign in to your application with their Roboflow account using OAuth 2.1 and PKCE.

You can let users sign in to your application with their Roboflow account, using the OAuth 2.1 authorization code flow with PKCE. Your app then acts for that user, limited to the permissions they approve.

OAuth access tokens work on `api.roboflow.com` with `Authorization: Bearer`. See [Authenticate with the REST API](/reference/platform/rest-api/authenticate-with-the-rest-api.md) for details.

For hosts, visibility, errors, and a runnable sample app, see [Sign In With Roboflow (Developer Reference)](/reference/authentication/authentication/sign-in-with-roboflow-developer-reference.md).

## Create an OAuth App

To register your application:

{% stepper %}
{% step %}

### Open Developer Settings

Go to "Workspace Settings > Developer" in your Roboflow dashboard at [app.roboflow.com](https://app.roboflow.com).

<figure><img src="https://2143050199-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FgmbAGf4KNeNPXGuUuKYv%2Fuploads%2Fgit-blob-4023eba1338a5f7415538890ca8a1d0b17af4a8a%2Fsiwf-workspace-settings-developer.png?alt=media" alt="Developer settings with OAuth applications"><figcaption></figcaption></figure>
{% endstep %}

{% step %}

### Create a new OAuth app

Click "Create OAuth App" (or "New app") and fill in:

<table data-search="false"><thead><tr><th>Field</th><th>Description</th></tr></thead><tbody><tr><td>Name</td><td>Display name on the consent screen and in your OAuth apps list.</td></tr><tr><td>Homepage URL</td><td>Your product URL. Shown on the consent screen for information.</td></tr><tr><td>Redirect URIs</td><td>One or more callback URLs. Each must match the <code>redirect_uri</code> your code sends exactly.</td></tr><tr><td>Token endpoint authentication</td><td>How your app sends its secret to the token endpoint: <code>client_secret_post</code> (in the request body, the default) or <code>client_secret_basic</code> (in an HTTP Basic <code>Authorization</code> header). Most MCP gateways (ex: Azure, TrueFoundry) use <code>client_secret_basic</code>.</td></tr><tr><td>Allowed scopes</td><td>Every scope you will request at sign-in.</td></tr><tr><td>Visibility</td><td>Internal, Unlisted, or Public. See <a href="/reference/authentication/authentication/sign-in-with-roboflow-developer-reference.md#visibility">Visibility</a>.</td></tr></tbody></table>

<figure><img src="https://2143050199-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FgmbAGf4KNeNPXGuUuKYv%2Fuploads%2Fgit-blob-822549b57159083c3cd1dc87019e973ce44df7bf%2Fsiwf-oauth-apps-list.png?alt=media" alt="OAuth applications list on the Developer page"><figcaption></figcaption></figure>

<figure><img src="https://2143050199-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FgmbAGf4KNeNPXGuUuKYv%2Fuploads%2Fgit-blob-aa529ca046c38a2926caff5c41f5d496878f4e98%2Fsiwf-oauth-create-app-form.png?alt=media" alt="Create OAuth application form"><figcaption></figcaption></figure>

You get a Client ID and a Client Secret (`rfcs_…`). The secret is shown only once, so store it on your server.
{% endstep %}
{% endstepper %}

### Redirect URI Examples

<table data-search="false"><thead><tr><th>Redirect URI</th><th>Typical use</th></tr></thead><tbody><tr><td><code>http://localhost:3001/oauth/callback</code></td><td>Local development on port 3001</td></tr><tr><td><code>http://127.0.0.1:3001/oauth/callback</code></td><td>The same, if your app uses <code>127.0.0.1</code></td></tr><tr><td><code>https://yourapp.com/oauth/callback</code></td><td>Production</td></tr></tbody></table>

Public hosts need HTTPS. HTTP works only for loopback addresses (`localhost`, `127.0.0.1`, `::1`).

## Authorization Flow

Roboflow uses the authorization code grant with PKCE (Proof Key for Code Exchange). Every client must use PKCE with the `S256` method.

{% stepper %}
{% step %}

### Generate a PKCE code verifier and challenge

Create a random `code_verifier` (43 to 128 characters) and derive a `code_challenge` from it with SHA-256:

```python
import hashlib, base64, secrets

code_verifier = secrets.token_urlsafe(32)
code_challenge = base64.urlsafe_b64encode(
    hashlib.sha256(code_verifier.encode()).digest()
).rstrip(b"=").decode()
```

{% endstep %}

{% step %}

### Redirect the user to authorize

Send the user's browser to the Roboflow authorization URL:

```
https://app.roboflow.com/oauth/authorize?
  client_id=YOUR_CLIENT_ID&
  redirect_uri=https://yourapp.com/callback&
  response_type=code&
  scope=openid profile email workspace:read&
  code_challenge=YOUR_CODE_CHALLENGE&
  code_challenge_method=S256&
  state=YOUR_STATE_VALUE
```

Use a random `state` value and check it on the callback. Roboflow does not require `state`, but your app needs it to block forged callbacks. Keep `code_verifier` on your server until you exchange the code.

The user sees a consent screen with the permissions your app asked for, and picks the workspace to grant.

<figure><img src="https://2143050199-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FgmbAGf4KNeNPXGuUuKYv%2Fuploads%2Fgit-blob-942df7ec61e36430c7df0770a51d0c22c1600deb%2Fsiwf-oauth-consent-screen.png?alt=media" alt="OAuth consent screen with workspace selection and scopes"><figcaption></figcaption></figure>

After they approve, Roboflow redirects to your `redirect_uri` with `code` and `state`.
{% endstep %}

{% step %}

### Exchange the code for tokens

On your server (never in the browser), send the code and your `code_verifier` to the token endpoint with `grant_type=authorization_code`. The code is single use and expires after 60 seconds, so exchange it right away. See [Get or Refresh Tokens](#get-or-refresh-tokens).
{% endstep %}
{% endstepper %}

## Tokens

### Get or Refresh Tokens

The token endpoint handles both the code exchange and refreshes. Send `grant_type=authorization_code` with the code from the callback, or `grant_type=refresh_token` with a refresh token.

An access token lasts 1 hour (24 hours for MCP clients) and a refresh token 30 days. When the access token expires, refresh it. If the refresh fails with `invalid_grant`, send the user through sign-in again.

{% openapi src="/files/GmCZhLnIVw9cO9RErdRH" path="/oauth/token" method="post" %}
[sign-in-with-roboflow.yaml](https://2143050199-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FgmbAGf4KNeNPXGuUuKYv%2Fuploads%2Fgit-blob-0802abe0d57bdbc6ffbebb35e4ab713b3b85db69%2Fsign-in-with-roboflow.yaml?alt=media)
{% endopenapi %}

### Use an Access Token

Send the access token in the `Authorization` header on `api.roboflow.com`:

```bash
curl -H "Authorization: Bearer rfoa_..." https://api.roboflow.com/
```

### Validate a Token

Checks an access token's status and expiry without client credentials. Resource servers that receive `rfoa_` tokens (ex: an MCP server) use it to cache a token until it expires.

{% openapi src="/files/GmCZhLnIVw9cO9RErdRH" path="/oauth/validate" method="get" %}
[sign-in-with-roboflow.yaml](https://2143050199-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FgmbAGf4KNeNPXGuUuKYv%2Fuploads%2Fgit-blob-0802abe0d57bdbc6ffbebb35e4ab713b3b85db69%2Fsign-in-with-roboflow.yaml?alt=media)
{% endopenapi %}

### Revoke a Token

Revokes an access token or a refresh token. Call it when the user signs out of your app.

{% openapi src="/files/GmCZhLnIVw9cO9RErdRH" path="/oauth/revoke" method="post" %}
[sign-in-with-roboflow.yaml](https://2143050199-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FgmbAGf4KNeNPXGuUuKYv%2Fuploads%2Fgit-blob-0802abe0d57bdbc6ffbebb35e4ab713b3b85db69%2Fsign-in-with-roboflow.yaml?alt=media)
{% endopenapi %}

### Get User Info

Returns the signed-in user's profile. The token needs the `openid` scope.

{% openapi src="/files/GmCZhLnIVw9cO9RErdRH" path="/oauth/userinfo" method="get" %}
[sign-in-with-roboflow.yaml](https://2143050199-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FgmbAGf4KNeNPXGuUuKYv%2Fuploads%2Fgit-blob-0802abe0d57bdbc6ffbebb35e4ab713b3b85db69%2Fsign-in-with-roboflow.yaml?alt=media)
{% endopenapi %}

## Available Scopes

Your app can request any combination of these scopes. Each one must also be on your OAuth app's "Allowed scopes" list.

### Identity Scopes

<table data-search="false"><thead><tr><th>Scope</th><th>Description</th></tr></thead><tbody><tr><td><code>openid</code></td><td>Returns a stable user ID in the <code>sub</code> claim. Needed for an <code>id_token</code> and for user info.</td></tr><tr><td><code>profile</code></td><td>Read the user's display name and email address.</td></tr><tr><td><code>email</code></td><td>Read the user's email address.</td></tr></tbody></table>

### API Scopes

<table data-search="false"><thead><tr><th>Scope</th><th>Description</th></tr></thead><tbody><tr><td><code>workspace:read</code></td><td>Read workspace details, list projects</td></tr><tr><td><code>project:create</code></td><td>Create projects</td></tr><tr><td><code>project:read</code></td><td>Read project details</td></tr><tr><td><code>project:update</code></td><td>Update project settings</td></tr><tr><td><code>image:create</code></td><td>Upload images</td></tr><tr><td><code>image:read</code></td><td>Read and download images</td></tr><tr><td><code>image:tag</code></td><td>Add and remove image tags</td></tr><tr><td><code>image:annotate</code></td><td>Create and update annotations</td></tr><tr><td><code>model:infer</code></td><td>Run inference</td></tr><tr><td><code>model:deploy</code></td><td>Deploy models</td></tr><tr><td><code>model:manage</code></td><td>Manage model settings</td></tr><tr><td><code>model-eval:read</code></td><td>Read model evaluation results</td></tr><tr><td><code>workflow:create</code></td><td>Create Workflows</td></tr><tr><td><code>workflow:read</code></td><td>Read Workflows</td></tr><tr><td><code>workflow:update</code></td><td>Update Workflows</td></tr><tr><td><code>version:create</code></td><td>Create dataset versions</td></tr><tr><td><code>version:read</code></td><td>Read dataset versions</td></tr><tr><td><code>version:update</code></td><td>Update dataset versions</td></tr><tr><td><code>training-job:create</code></td><td>Start training jobs</td></tr><tr><td><code>folder:create</code></td><td>Create project folders</td></tr><tr><td><code>folder:read</code></td><td>Read project folders</td></tr><tr><td><code>folder:update</code></td><td>Update project folders</td></tr><tr><td><code>folder:delete</code></td><td>Delete project folders</td></tr></tbody></table>

<details>

<summary>Additional scopes</summary>

<table data-search="false"><thead><tr><th>Scope</th><th>Description</th></tr></thead><tbody><tr><td><code>device:read</code></td><td>Read devices</td></tr><tr><td><code>device:update</code></td><td>Update device settings</td></tr><tr><td><code>vision-events:read</code></td><td>Read vision events</td></tr><tr><td><code>vision-events:write</code></td><td>Create vision events</td></tr><tr><td><code>vision-events:manage</code></td><td>Manage vision event use cases</td></tr><tr><td><code>annotation-job:create</code></td><td>Create annotation jobs</td></tr><tr><td><code>annotation-job:read</code></td><td>Read annotation jobs</td></tr><tr><td><code>video-inference-job:create</code></td><td>Create video inference jobs</td></tr><tr><td><code>video-inference-job:read</code></td><td>Read video inference jobs</td></tr><tr><td><code>integration:create</code></td><td>Create integrations</td></tr><tr><td><code>integration:delete</code></td><td>Delete integrations</td></tr><tr><td><code>credentials:create</code></td><td>Create credentials</td></tr><tr><td><code>credentials:read</code></td><td>Read credentials</td></tr><tr><td><code>credentials:update</code></td><td>Update credentials</td></tr><tr><td><code>credentials:delete</code></td><td>Delete credentials</td></tr><tr><td><code>data-staging:read</code></td><td>Read staged data</td></tr><tr><td><code>data-staging:write</code></td><td>Write staged data</td></tr><tr><td><code>data-staging:delete</code></td><td>Delete staged data</td></tr><tr><td><code>batch-processing:read</code></td><td>Read batch jobs</td></tr><tr><td><code>batch-processing:trigger</code></td><td>Trigger batch processing</td></tr><tr><td><code>batch:read</code></td><td>Read batches</td></tr><tr><td><code>workspace-stats:read</code></td><td>Read workspace statistics</td></tr></tbody></table>

</details>

## OIDC Discovery

Roboflow publishes standard OpenID Connect discovery documents. OAuth and OIDC client libraries read them to find the endpoints above.

* OpenID Configuration: `https://app.roboflow.com/.well-known/openid-configuration`
* JWKS, for verifying ID tokens: `https://app.roboflow.com/.well-known/jwks.json`

## Next Steps

* [Sign In With Roboflow (Developer Reference)](/reference/authentication/authentication/sign-in-with-roboflow-developer-reference.md): hosts, visibility, errors, example app
* [Authenticate with the REST API](/reference/platform/rest-api/authenticate-with-the-rest-api.md)
