Skip to content

Commit

Permalink
Merge pull request #120 from washyking/main
Browse files Browse the repository at this point in the history
Panopto-oauth2-integration documentation
  • Loading branch information
aNebula authored Dec 21, 2024
2 parents 48b3813 + 0e73811 commit 73b7100
Show file tree
Hide file tree
Showing 2 changed files with 317 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@

# Panopto OAuth2 Integration Guide (Updated)

This guide provides a detailed, step-by-step process to integrate Panopto’s OAuth2-based authentication into your backend application (e.g., OnTrack or Doubtfire-API). It covers creating an API client on Panopto, configuring OAuth2 settings, obtaining authorization codes, exchanging them for access tokens, and integrating the process into your application’s workflow. Technical improvements, corrections, and additional recommendations based on best practices have been included.

## OAuth2 Panopto API Client Setup
To upload videos to a user's personal Panopto instance, we need to authenticate using OAuth2. This involves creating an API client on Panopto, configuring redirect URIs and CORS, then performing the OAuth2 Authorization Code flow to retrieve the tokens required for API calls.

## Step 1: Create an API Client on Panopto
1. Navigate to the Panopto website:
- Panopto Login: [https://deakin.au.panopto.com/Panopto/Pages/Home.aspx](https://deakin.au.panopto.com/Panopto/Pages/Home.aspx)

2. Access User Settings:
- Click on the User Settings icon (usually in the top-right corner).

3. Create a New API Client:
- Under the API Client section, click "Create New Client".

4. Configure the API Client:
- Set a name for the client (e.g., "OnTrack Integration Client" or "Doubtfire Integration Client").
- Choose "Server-side Application" as the client type since the integration is backend-based.

5. Save Your Credentials:
- Note down your Client ID and Client Secret. These will be used to authenticate requests.
- Store them securely (e.g., environment variables). Do not commit these to version control.

**Example:**
```
CLIENT_ID=your_panopto_client_id
CLIENT_SECRET=your_panopto_client_secret
```
<img width="400" alt="Screenshot 2024-12-05 at 5 58 26 pm" src="https://github.com/user-attachments/assets/26e91cd0-c986-4c32-88e4-c111283f4650">

## Step 2: Configure Allowed URLs and Redirect URI
1. Set CORS (Cross-Origin Resource Sharing):
- In the Allowed URL section of the API Client configuration, set CORS to `https://localhost` for local development.

2. Set Redirect URI:
- Set the Redirect URI to `http://localhost:9127/redirect`.
- The port number (9127) is arbitrary and used for local testing. It must match the `redirect_uri` parameter in your application’s OAuth flow exactly.

## Step 3: Exchange the Code for an Access Token
Once the API client is set up, the next step is to perform the OAuth2 Authorization Code flow:

### Obtain the Authorization Code
Replace `YOUR_CLIENT_ID` and `YOUR_PORT` as needed:

```
https://deakin.au.panopto.com/Panopto/oauth2/connect/authorize?client_id=YOUR_CLIENT_ID&response_type=code&redirect_uri=http://localhost:9127/redirect&scope=openid%20api&nonce=12345
```

1. Navigate to the above URL in a browser.
2. Log in and grant access when prompted.
3. After approval, Panopto redirects to:
```
http://localhost:9127/redirect?code=AUTHORIZATION_CODE
```

### Exchange Authorization Code for Access Token
Use the code to request an access token. Note the correction in `grant_type` spelling (`authorization_code`):

```bash
curl -X POST "https://deakin.au.panopto.com/Panopto/oauth2/connect/token" -H "Content-Type: application/x-www-form-urlencoded" -d "grant_type=authorization_code" -d "code=YOUR_AUTHORIZATION_CODE" -d "redirect_uri=http://localhost:9127/redirect" -d "client_id=YOUR_CLIENT_ID" -d "client_secret=YOUR_CLIENT_SECRET"
```

**Example Response:**
```json
{
"access_token": "eyJ...<snip>",
"expires_in": 3600,
"token_type": "Bearer",
"scope": "openid api",
"refresh_token": "optional_refresh_token_if_provided"
}
```

This `access_token` can be used to call Panopto’s API for video uploads. If a `refresh_token` is included, you can use it to obtain new access tokens without user re-authorization.

## Step 4: Integrating with OnTrack (or Your Backend)
1. **Store Credentials Securely:**
- Create an `.env` file (for local development):
```env
PANOPTO_CLIENT_ID=your_panopto_client_id
PANOPTO_CLIENT_SECRET=your_panopto_client_secret
PANOPTO_REDIRECT_URI=http://localhost:9127/redirect
```
- Load these environment variables in your backend application.
2. **Authorization Flow Integration:**
- Your backend can present a link to the authorization URL. The user clicks it to start the process.
- After granting access, the backend receives the authorization code at the redirect URI.
- The backend exchanges the code for an access token automatically.
3. **Video Upload:**
- With a valid access token, your backend can call Panopto’s upload APIs to programmatically upload videos to the user’s personal Panopto instance.
## Recommendations and Updates
- **Security:**
- Use HTTPS in production for all communications.
- Do not log sensitive tokens (e.g., access tokens or refresh tokens).
- Store secrets securely using a tool like AWS Secrets Manager or HashiCorp Vault.
- **Scalability:**
- Use a shared token storage mechanism (e.g., a database) if running multiple instances of your backend behind a load balancer.
- **Error Handling:**
- Implement retry logic with exponential backoff for transient failures.
- Log errors but ensure no sensitive information (e.g., client secret) is exposed.
- **Version Control:**
- Ensure Panopto API versions are checked periodically for updates.
- Test all API changes in a staging environment before deploying them to production.
## References
- Panopto Documentation: [https://support.panopto.com/s/docs](https://support.panopto.com/s/docs)
- OAuth2 Specification: [https://oauth.net/2/](https://oauth.net/2/)
- Secret Management: Consider [HashiCorp Vault](https://www.vaultproject.io/) or [AWS Secrets Manager](https://aws.amazon.com/secrets-manager/) for production.
---
By following these steps and best practices, you can seamlessly integrate Panopto’s OAuth2 authentication flow into your backend (e.g., OnTrack or Doubtfire-API), ensuring a smooth and secure process for uploading videos to a user’s Panopto instance.
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
# Panopto Video Upload Process

## Overview
This document outlines key information about the process of uploading videos to Panopto using the Panopto REST API. While this isn't a comprehensive guide, it highlights the steps involved in creating a session, performing a multipart upload of the video file, creating the manifest, and finalising the upload. This serves as an informational resource for implementing the video upload functionality in the future. Additional research and context will be needed to fully integrate these steps.

---

## Step 1: Create a Session for Video Upload

Before uploading a video, a session must be created. The session provides the necessary details for the upload process, including the upload target and session ID.

### Call the Session Creation API
The session creation process is triggered by sending a POST request to the `sessionUpload` endpoint.

- **API Endpoint:**
```ruby
POST https://{server}/Panopto/PublicAPI/REST/sessionUpload
```
- **Payload:**
```http
{
"FolderId": "{folder_id}"
}
```
- **Example Session Creation:**
```ruby
response = RestClient.post(
"https://#{server}/Panopto/PublicAPI/REST/sessionUpload",
{ "FolderId" => folder_id }.to_json,
{ content_type: :json, accept: :json, authorization: "Bearer #{access_token}" }
)
```

- **Example Response:**
```http
{
"ID": "session_id",
"UploadTarget": "upload_target_url",
"FolderId": "{folder_id}"
}
```
## Step 2: Upload Video via Multipart Upload
Panopto supports multipart uploads for large video files. This step uploads the video in parts to the ```upload target``` specified in the session creation response.

#### 1. Initiate Multipart Upload:
- Get the Upload URL: After creating a session, extract the ```UploadTarget``` URL from the session creation response. This URL specifies where the video should be uploaded.

- Use `Net::HTTP` and `URI` for Multipart Upload: Use Ruby's standard libraries to handle the multipart upload. The following example demonstrates how to upload a file in parts using `Net::HTTP:`

```ruby

# Extract the Upload Target URL from the session creation response
upload_target = "https://deakin.au.panopto.com/Panopto/Upload/..."


# Define the chunk size for multipart upload (5MB per part)
chunk_size = 5 * 1024 * 1024

# Initialise upload process
uri = URI(upload_target)
request = Net::HTTP::Post.new(uri)
request['Content-Type'] = 'multipart/form-data'

# Read and upload the video file in chunks
while chunk = file.read(chunk_size)
form_data = [['file', chunk]]
request.set_form form_data, 'multipart/form-data'

response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end

# Check the response (e.g., for successful upload)
puts response.body
end
```
### 2. Upload Parts:
- Split the Video File: Split the video into parts, each no larger than 5MB. You can adjust the part size as needed.

- Upload Each Part: Iterate over the parts and upload them using `Net::HTTP:`

```ruby
# Read video file in 5MB chunks and upload each part
File.open('video_path.mp4', 'rb') do |file|
part_number = 1
while (chunk = file.read(5 * 1024 * 1024)) # 5MB per part
form_data = [['file', chunk]]
request.set_form form_data, 'multipart/form-data'

response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end

# Handle response
puts "Part #{part_number} uploaded: #{response.body}"
part_number += 1
end
end
```
### 3. Complete Multipart Upload:
- Finalise the Upload: Once all parts have been uploaded, call the ``complete_multipart_upload`` method to combine the parts into one video file in Panopto.

```ruby
# Finalise the upload once all parts are uploaded
complete_upload_uri = URI("#{upload_target}/complete")
complete_request = Net::HTTP::Post.new(complete_upload_uri)
complete_request['Content-Type'] = 'application/json'

# Send the finalisation request
response = Net::HTTP.start(complete_upload_uri.hostname, complete_upload_uri.port, use_ssl: true) do |http|
http.request(complete_request)
end
```
## Step 3: Create and Upload the Manifest File
Once the video is uploaded, the next step is to create the manifest file. The manifest provides metadata for the video, including its title, description, and the file name.

### 1. Create the Manifest File:
- The manifest file is an XML file that contains the following key elements:

```xml
Copy code
<?xml version="1.0" encoding="utf-8"?>
<Session xmlns="http://tempuri.org/UniversalCaptureSpecification/v1">
<Title>{Video_Title}</Title>
<Description>{Video_Description}</Description>
<Date>{Current_Date}</Date>
<Videos>
<Video>
<Start>PT0S</Start>
<File>{Video_File_Name}</File>
<Type>Primary</Type>
</Video>
</Videos>
</Session>
```
### 2. Upload the Manifest File:
- The manifest file is uploaded in the same way as the video parts, using `multipart upload`.

```ruby
manifest_file = 'upload_manifest_generated.xml'
file = File.open(manifest_file, 'rb')

# Prepare the POST request for multipart upload
request = Net::HTTP::Post.new(uri)
request['Content-Type'] = 'multipart/form-data'

# Upload the manifest in chunks
while chunk = file.read(5 * 1024 * 1024) # 5MB per part
form_data = [['file', chunk]]
request.set_form form_data, 'multipart/form-data'

# Send the request to upload the part
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
```
## Step 4: Finalise the Upload
After uploading the video and the manifest file, the final step is to finalise the session marking it as complete.

### 1. Send the PUT Request to Finalise Session:
API Endpoint:

```ruby
PUT https://{server}/Panopto/PublicAPI/REST/sessionUpload/{session_id}
```
Payload:

```ruby

{
"State": 1, # Mark as completed
"FolderId": "{folder_id}"
}
```
Example Code:

```ruby
RestClient.put(
"https://#{@server}/Panopto/PublicAPI/REST/sessionUpload/#{@session_id}",
{ "State" => 1, "FolderId" => @folder_id }.to_json,
{ content_type: :json, accept: :json, authorization: "Bearer #{@access_token}" }
)
```
## 2. Monitor the Upload Status:
- Check for Processing: After finalising, periodically check the `session state` to ensure it is processed and completed.

Polling Example:

```ruby

while true
sleep(5) # Wait a few seconds before checking status
session = RestClient.get("https://#{@server}/Panopto/PublicAPI/REST/sessionUpload/#{@session_id}")
if JSON.parse(session.body)["State"] == 4 # State 4 means processing complete
break
end
end
```

0 comments on commit 73b7100

Please sign in to comment.