Before you can use brightspaceR, you need to register an OAuth2 application in your Brightspace instance and configure your R environment with the credentials. This guide walks through every step.
You need administrator access (or help from an admin) to register an app.
https://myschool.brightspace.com).| Field | Value |
|---|---|
| Application Name | brightspaceR (or any name you like – this is shown to
users on the consent page) |
| Authentication Workflow | Authorization Code Grant |
| Redirect URI | https://localhost:1410/ |
| Scope | See About Scopes below |
| Access Token Lifetime | Leave at default (3600 seconds is fine) |
| Enable Refresh Tokens | Yes (recommended) |
| Prompt User for Consent | Optional (Yes if you want users to see a consent screen) |
After registration you’ll receive a Client ID and Client Secret. Save these securely – you’ll need them in the next step.
Brightspace requires all redirect URIs to use HTTPS –
http:// is not accepted. brightspaceR uses
https://localhost:1410/ by default.
How the flow works: When you run
bs_auth(), the package opens your browser to the
Brightspace authorization page. After you authorize, Brightspace
redirects to https://localhost:1410/?code=.... Since
there’s no local HTTPS server listening, your browser will show a
connection error – that’s expected. You simply copy the full URL from
your browser’s address bar and paste it back into R. The package
extracts the authorization code from the URL and exchanges it for an
access token.
You can use a different redirect URI by setting the
BRIGHTSPACE_REDIRECT_URI environment variable or passing
redirect_uri to bs_auth(). Just make sure it
matches what you registered in Brightspace exactly.
{#about-scopes}
Scopes control what API endpoints your application can access.
Brightspace scopes follow the pattern
<group>:<resource>:<action>. brightspaceR
needs scopes from two tiers depending on which features you use.
These scopes are sufficient for bs_get_dataset(), joins,
grade and enrollment analytics – everything except Advanced Data
Sets:
| Scope | Used by |
|---|---|
datasets:bds:read |
bs_list_datasets(), bs_get_schema() |
datahub:dataexports:read |
bs_list_extracts(),
bs_download_dataset() |
datahub:dataexports:download |
bs_get_dataset(), bs_download_all() |
users:profile:read |
bs_check_scopes() |
Scope string for Tier 1:
datasets:bds:read datahub:dataexports:read datahub:dataexports:download users:profile:read
Add these scopes to also use bs_get_ads() for Advanced
Data Sets like Learner Usage. The ADS functions power the engagement,
retention, and risk analytics (bs_course_engagement(),
bs_identify_at_risk(), bs_retention_summary(),
etc.):
| Scope | Used by |
|---|---|
reporting:dataset:list |
bs_list_ads() |
reporting:dataset:fetch |
bs_create_ads_job() (filter auto-detection) |
reporting:job:create |
bs_create_ads_job(), bs_get_ads() |
reporting:job:list |
bs_list_ads_jobs() |
reporting:job:fetch |
bs_ads_job_status() (polling) |
reporting:job:download |
bs_download_ads() |
Scope string for Tier 2 (recommended – paste this into Brightspace):
datasets:bds:read datahub:dataexports:read datahub:dataexports:download reporting:dataset:list reporting:dataset:fetch reporting:job:create reporting:job:list reporting:job:fetch reporting:job:download users:profile:read
Note: If you register with Tier 1 scopes only, ADS functions like
bs_get_ads()will returnNULLwith an informative warning instead of crashing. BDS workflows are completely unaffected. You can upgrade to Tier 2 later by updating the scopes in Manage Extensibility and re-authenticating withbs_deauth(); bs_auth().
After authenticating, run bs_check_scopes() to confirm
which capabilities are available:
If any checks fail, compare the registered scopes in Brightspace (Admin Tools > Manage Extensibility > OAuth 2.0 > your app) with the scope strings above.
The canonical list of Brightspace OAuth2 scopes is published at:
There are two ways to store your credentials: a config
file (recommended for projects) or environment
variables (traditional approach). Both are picked up
automatically by bs_auth().
{#config-file}
Create a config.yml file in your project root:
default:
brightspace:
client_id: "your-client-id"
client_secret: "your-client-secret"
instance_url: "https://myschool.brightspace.com"
redirect_uri: "https://localhost:1410/"
scope: "datasets:bds:read datahub:dataexports:read datahub:dataexports:download reporting:dataset:list reporting:dataset:fetch reporting:job:create reporting:job:list reporting:job:fetch reporting:job:download users:profile:read"Or use bs_config_set() to create it interactively:
bs_config_set(
client_id = "your-client-id",
client_secret = "your-client-secret",
instance_url = "https://myschool.brightspace.com"
)The config file supports environment-based profiles via the config package. Set the
R_CONFIG_ACTIVE environment variable to switch
profiles:
default:
brightspace:
client_id: "dev-id"
instance_url: "https://dev.brightspace.com"
production:
inherits: default
brightspace:
client_id: "prod-id"
instance_url: "https://myschool.brightspace.com"Security note: Make sure
config.ymlis in your.gitignoreto avoid committing secrets to version control.
You can pass credentials directly to bs_auth(), but it’s
more convenient (and safer) to store them as environment variables. Add
the following to your .Renviron file:
Then add these lines:
BRIGHTSPACE_CLIENT_ID=your-client-id-here
BRIGHTSPACE_CLIENT_SECRET=your-client-secret-here
BRIGHTSPACE_INSTANCE_URL=https://myschool.brightspace.com
Restart R for the changes to take effect.
Security note: Never commit
.Renvironto version control. It should already be listed in.gitignoreby default.
bs_auth() resolves each credential in this order:
bs_auth(client_id = "..."))config.yml in the working directory (if present)BRIGHTSPACE_CLIENT_ID)This will:
https://localhost:1410/?code=...&state=....You should see:
v Authenticated with Brightspace at <https://myschool.brightspace.com>
Tokens are cached to disk automatically. On subsequent calls,
bs_auth() will reuse the cached token and refresh it if
expired – no browser interaction needed.
To force re-authentication:
For scripts that run unattended (e.g., cron jobs, scheduled ETL pipelines), use a refresh token obtained from a prior interactive session:
This exchanges the refresh token for a new access token without any browser interaction. Store the refresh token as an environment variable or in a secure secrets manager.
# Check authentication status
bs_has_token()
#> [1] TRUE
# Verify API scopes are configured correctly
bs_check_scopes()
#> i Testing API access with current token...
#> v All 4 scope checks passed.
# List available BDS datasets
datasets <- bs_list_datasets()
datasets
#> # A tibble: 67 x 5
#> schema_id plugin_id name description created_date
#> <chr> <chr> <chr> <chr> <chr>
#> 1 abc123 def456 Users User demographics ... 2024-01-01...
#> 2 ghi789 jkl012 User Enrollments Enrollment records ... 2024-01-01...
#> ...
# If you have Tier 2 (ADS) scopes, also verify ADS access
ads <- bs_list_ads()
ads
#> # A tibble: 12 x 4
#> dataset_id name description category
#> <chr> <chr> <chr> <chr>
#> 1 abc-def-... Learner Usage Activity metrics ... Engagement
#> ...Make sure your environment variables are set. Check with:
If empty, re-check your .Renviron file and restart
R.
If you’re in an environment without a browser (e.g., RStudio Server), the authorization URL is printed to the console. Copy it into a browser on any machine, authorize, then copy the redirect URL back.
Your OAuth2 app may not have the correct scopes, or the user account you authenticated with may not have permission to access Data Hub. Check:
bs_check_scopes() to see which API capabilities are
available.datasets:bds:read,
datahub:dataexports:read, and
datahub:dataexports:download for BDS.reporting:* scopes listed
above.