# OAuth 2.1 (Sign in with Roboflow)

You can build applications that authenticate users with their Roboflow account using the OAuth 2.1 authorization code flow with PKCE. This lets your app act on behalf of a Roboflow user, scoped to only the permissions they approve.

OAuth tokens work everywhere API keys work: as a Bearer header, query parameter, or body parameter. See [Authenticate with the REST API](/developer/rest-api/authenticate-with-the-rest-api.md) for details.

## Create an OAuth App

To register your application:

{% stepper %}
{% step %}

### Open Developer Settings

Go to **Workspace Settings > Developer** in your Roboflow dashboard.
{% endstep %}

{% step %}

### Create a new OAuth app

Click "Create OAuth App" and fill in:

* **Name** - your app's display name
* **Redirect URIs** - one or more callback URLs (HTTPS required for public hosts; HTTP is allowed for `localhost`, `127.0.0.1`, and `[::1]`)
* **Allowed Scopes** - the scopes your app will request

You will receive a **Client ID** and **Client Secret**. The secret is shown only once, so store it securely.
{% endstep %}
{% endstepper %}

## Authorization Flow

Roboflow uses the authorization code grant with PKCE (Proof Key for Code Exchange). PKCE is required for all clients.

{% stepper %}
{% step %}

### Generate a PKCE code verifier and challenge

Create a random `code_verifier` (43-128 characters) and derive a `code_challenge` from it using 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 to the Roboflow authorization endpoint:

```
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
```

The user will see a consent screen showing the permissions your app is requesting. After they approve, Roboflow redirects back to your `redirect_uri` with a `code` and `state` parameter.
{% endstep %}

{% step %}

### Exchange the code for tokens

```bash
curl -X POST https://app.roboflow.com/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=authorization_code" \
  -d "client_id=YOUR_CLIENT_ID" \
  -d "client_secret=YOUR_CLIENT_SECRET" \
  -d "code=AUTHORIZATION_CODE" \
  -d "redirect_uri=https://yourapp.com/callback" \
  -d "code_verifier=YOUR_CODE_VERIFIER"
```

The response includes:

* `access_token` - use this to call Roboflow APIs (valid for 1 hour)
* `refresh_token` - use this to get new access tokens (valid for 30 days)
* `id_token` - a JWT containing the user's identity claims
  {% endstep %}
  {% endstepper %}

## Using OAuth Tokens

Once you have an access token, use it like any other Roboflow API key:

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

Or as a query parameter:

```bash
curl "https://api.roboflow.com/?api_key=rfoa_..."
```

## Refresh a Token

Access tokens expire after 1 hour. Use the refresh token to get a new one:

```bash
curl -X POST https://app.roboflow.com/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=refresh_token" \
  -d "client_id=YOUR_CLIENT_ID" \
  -d "client_secret=YOUR_CLIENT_SECRET" \
  -d "refresh_token=YOUR_REFRESH_TOKEN"
```

## Revoke a Token

To revoke an access or refresh token:

```bash
curl -X POST https://app.roboflow.com/oauth/revoke \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "token=TOKEN_TO_REVOKE" \
  -d "client_id=YOUR_CLIENT_ID" \
  -d "client_secret=YOUR_CLIENT_SECRET"
```

## User Info

Retrieve profile information for the authenticated user:

```bash
curl -H "Authorization: Bearer rfoa_..." https://app.roboflow.com/oauth/userinfo
```

## Available Scopes

Your app can request any combination of the following scopes:

### Identity Scopes

| Scope     | Description                                            |
| --------- | ------------------------------------------------------ |
| `openid`  | Required. Returns a stable user ID in the `sub` claim. |
| `profile` | Read the user's display name and avatar.               |
| `email`   | Read the user's email address.                         |

### API Scopes

| Scope                 | Description                           |
| --------------------- | ------------------------------------- |
| `workspace:read`      | Read workspace details, list projects |
| `project:create`      | Create projects                       |
| `project:read`        | Read project details                  |
| `project:update`      | Update project settings               |
| `image:create`        | Upload images                         |
| `image:read`          | Read and download images              |
| `image:tag`           | Add and remove image tags             |
| `image:annotate`      | Create and update annotations         |
| `model:infer`         | Run inference                         |
| `model:deploy`        | Deploy models                         |
| `model:manage`        | Manage model settings                 |
| `model-eval:read`     | Read model evaluation results         |
| `workflow:create`     | Create Workflows                      |
| `workflow:read`       | Read Workflows                        |
| `workflow:update`     | Update Workflows                      |
| `version:create`      | Create dataset versions               |
| `version:read`        | Read dataset versions                 |
| `version:update`      | Update dataset versions               |
| `training-job:create` | Start training jobs                   |
| `folder:create`       | Create project folders                |
| `folder:read`         | Read project folders                  |
| `folder:update`       | Update project folders                |
| `folder:delete`       | Delete project folders                |

<details>

<summary>Additional scopes</summary>

| Scope                        | Description                   |
| ---------------------------- | ----------------------------- |
| `device:read`                | Read devices                  |
| `device:update`              | Update device settings        |
| `vision-events:read`         | Read vision events            |
| `vision-events:write`        | Create vision events          |
| `vision-events:manage`       | Manage vision event use cases |
| `annotation-job:create`      | Create annotation jobs        |
| `annotation-job:read`        | Read annotation jobs          |
| `video-inference-job:create` | Create video inference jobs   |
| `video-inference-job:read`   | Read video inference jobs     |
| `integration:create`         | Create integrations           |
| `integration:delete`         | Delete integrations           |
| `credentials:create`         | Create credentials            |
| `credentials:read`           | Read credentials              |
| `credentials:update`         | Update credentials            |
| `credentials:delete`         | Delete credentials            |
| `data-staging:read`          | Read staged data              |
| `data-staging:write`         | Write staged data             |
| `data-staging:delete`        | Delete staged data            |
| `batch-processing:read`      | Read batch jobs               |
| `batch-processing:trigger`   | Trigger batch processing      |
| `batch:read`                 | Read batches                  |
| `workspace-stats:read`       | Read workspace statistics     |

</details>

## OIDC Discovery

Roboflow publishes standard OpenID Connect discovery documents:

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


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.roboflow.com/developer/authentication/oauth.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
