Skip to main content
onenote-security-basics Implement secure authentication, token management, and permission scoping for OneNote Graph API.
Use when hardening OneNote integrations, implementing least-privilege permissions, or managing token lifecycle.
Trigger with "onenote security", "onenote permissions", "onenote token management", "onenote least privilege".
설치로 이동 Skills Marketplace 커뮤니티가 만든 AI 스킬을 발견하고 탐색하세요.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
직접 명령은 검토 Prompt를 거치지 않습니다. 실행하기 전에 소스를 확인하세요.
npx skills add https://github.com/jeremylongshore/claude-code-plugins-plus-skills --skill onenote-security-basics명령은 한 줄로 유지됩니다. 복사하기 전에 가로로 스크롤해 전체 내용을 확인하세요.
로컬 사본을 원하시나요? SkillsMP에서 현재 제공할 수 있는 파일을 다운로드하세요.
Zip 다운로드 다운로드 중... 이 저장소의 다른 Skills Implement user sign-up and sign-in flows with Clerk.
Use when building authentication UI, customizing sign-in experience,
or implementing OAuth social login.
Trigger with phrases like "clerk sign-in", "clerk sign-up",
"clerk login flow", "clerk OAuth", "clerk social login".
Implement session management and middleware with Clerk.
Use when managing user sessions, configuring route protection,
or implementing token refresh and custom JWT templates.
Trigger with phrases like "clerk session", "clerk middleware",
"clerk route protection", "clerk token", "clerk JWT".
Configure enterprise SSO, role-based access control, and organization management.
Use when implementing SSO integration, configuring role-based permissions,
or setting up organization-level controls.
Trigger with phrases like "clerk SSO", "clerk RBAC",
"clerk enterprise", "clerk roles", "clerk permissions", "clerk organizations".
jeremylongshore
jeremylongshore/claude-code-plugins-plus-skills
GitHub 저장소 열기 name onenote-security-basics description Implement secure authentication, token management, and permission scoping for OneNote Graph API.
Use when hardening OneNote integrations, implementing least-privilege permissions, or managing token lifecycle.
Trigger with "onenote security", "onenote permissions", "onenote token management", "onenote least privilege".
allowed-tools Read, Write, Edit, Bash(npm:*), Bash(pip:*), Grep version 1.6.0 license MIT author Jeremy Longshore <jeremy@intentsolutions.io> tags ["saas","onenote","microsoft"] compatibility Designed for Claude Code
OneNote Security Basics
Overview
OneNote Graph API security changed fundamentally on March 31, 2025, when Microsoft deprecated app-only authentication for OneNote endpoints. Every integration must now use delegated authentication through MSAL, which means real users must sign in — no more background service accounts with client secrets. This skill covers the full security surface: permission scoping, token lifecycle management, MSAL cache serialization, credential storage, and multi-tenant hardening. Get any of these wrong and your integration either breaks silently (expired tokens returning 401s) or over-provisions access (Notes.ReadWrite.All when Notes.Read suffices).
Prerequisites
Azure AD app registration with redirect URI configured at https://portal.azure.com/#blade/Microsoft_AAD_RegisteredApps
Microsoft 365 license (E3/E5/Business) with OneNote enabled
Python: pip install msgraph-sdk azure-identity msal or Node: npm install @microsoft/microsoft-graph-client @azure/identity @azure/msal-node
Understanding of OAuth 2.0 authorization code flow and delegated permissions
Instructions
Permission Scope Matrix
Choose the minimum scope required for your use case:
Scope Read notebooks Read pages Create pages Create notebooks Admin consent? Notes.ReadYes Yes No No No Notes.ReadWriteYes Yes Yes Yes No Notes.ReadWrite.AllYes Yes Yes Yes Yes Notes.CreateNo No Yes Yes No
Least-privilege recommendations:
Read-only dashboards: Notes.Read (user consent only)
Personal note creation: Notes.ReadWrite (user consent only)
Cross-user/organizational access: Notes.ReadWrite.All (requires tenant admin approval)
Write-only ingestion: Notes.Create (cannot read back what was written)
Delegated Authentication Setup (Post-2025 Mandatory) CRITICAL: App-only authentication (ClientSecretCredential) was deprecated for OneNote endpoints on March 31, 2025. All code below uses delegated auth exclusively.
Python — Device Code Flow (headless/CLI environments):
from azure.identity import DeviceCodeCredential
from msgraph import GraphServiceClient
import os
CLIENT_ID = os.environ["AZURE_CLIENT_ID" ]
TENANT_ID = os.environ["AZURE_TENANT_ID" ]
scopes = ["Notes.ReadWrite" ]
credential = DeviceCodeCredential(
client_id=CLIENT_ID,
tenant_id=TENANT_ID,
)
client = GraphServiceClient(credentials=credential, scopes=scopes)
TypeScript — Interactive Browser Flow (web apps):
import { DeviceCodeCredential } from "@azure/identity" ;
import { Client } from "@microsoft/microsoft-graph-client" ;
import { TokenCredentialAuthenticationProvider }
from "@microsoft/microsoft-graph-client/authProviders/azureTokenCredentials" ;
const credential = new DeviceCodeCredential ({
clientId : process.env .AZURE_CLIENT_ID !,
tenantId : process.env .AZURE_TENANT_ID !,
});
const scopes = ["Notes.ReadWrite" ];
const authProvider = new TokenCredentialAuthenticationProvider (credential, { scopes });
const client = Client .initWithMiddleware ({ authProvider });
Token Lifecycle Management Access tokens expire after 1 hour . Refresh tokens last 90 days but can be revoked by admin policy. Your code must handle silent renewal:
import msal
import json
import os
CACHE_FILE = os.path.expanduser("~/.onenote-token-cache.json" )
def get_msal_app ():
cache = msal.SerializableTokenCache()
if os.path.exists(CACHE_FILE):
cache.deserialize(open (CACHE_FILE).read())
app = msal.PublicClientApplication(
client_id=os.environ["AZURE_CLIENT_ID" ],
authority=f"https://login.microsoftonline.com/{os.environ['AZURE_TENANT_ID' ]} " ,
token_cache=cache,
)
return app, cache
def acquire_token (app, cache ):
accounts = app.get_accounts()
if accounts:
result = app.acquire_token_silent(
scopes=["https://graph.microsoft.com/Notes.ReadWrite" ],
account=accounts[0 ],
)
if result and "access_token" in result:
save_cache(cache)
return result["access_token" ]
flow = app.initiate_device_flow(
scopes=["https://graph.microsoft.com/Notes.ReadWrite" ]
)
print (flow["message" ])
result = app.acquire_token_by_device_flow(flow)
save_cache(cache)
return result.get("access_token" )
def save_cache (cache ):
if cache.has_state_changed:
with open (CACHE_FILE, "w" ) as f:
f.write(cache.serialize())
os.chmod(CACHE_FILE, 0o600 )
Secure Credential Storage Never store client IDs or tenant IDs in source code. Use environment variables at minimum, Azure Key Vault for production:
echo ".env" >> .gitignore
cat > .env << 'EOF'
AZURE_CLIENT_ID=your-app-registration-client-id
AZURE_TENANT_ID=your-directory-tenant-id
EOF
chmod 600 .env
from azure.keyvault.secrets import SecretClient
from azure.identity import DefaultAzureCredential
vault_url = "https://your-vault.vault.azure.net"
kv_client = SecretClient(vault_url=vault_url, credential=DefaultAzureCredential())
client_id = kv_client.get_secret("onenote-client-id" ).value
tenant_id = kv_client.get_secret("onenote-tenant-id" ).value
Multi-Tenant Security Considerations For apps serving multiple organizations:
Register as a multi-tenant app (set supportedAccountTypes to AzureADMultipleOrgs)
Validate the tid (tenant ID) claim in every token — reject tokens from unexpected tenants
Store per-tenant token caches separately (never mix tenant tokens)
Handle Conditional Access policies: catch claims challenge in 401 responses and re-authenticate with the required claims
Security Checklist for Production
Output After applying this skill, your OneNote integration will have: least-privilege permission scoping matched to actual usage, persistent MSAL token cache with silent renewal, secure credential storage using environment variables or Key Vault, and a verified security checklist. Authentication failures will produce actionable error messages instead of silent 401 loops.
Error Handling Error Cause Fix AADSTS65001: user needs to consentScope not yet granted by user Redirect to consent URL or use admin consent endpoint AADSTS700016: app not foundWrong client ID or wrong tenant Verify AZURE_CLIENT_ID matches portal registration AADSTS50076: MFA requiredConditional Access policy Use InteractiveBrowserCredential (device code cannot handle MFA prompts) 403 Forbidden on OneNote callsMissing Notes.* permission or using app-only auth Check scope in token; switch to delegated auth 401 Unauthorized after workingAccess token expired, silent renewal failed Check refresh token validity; re-serialize cache Token cache file empty after restart Cache not serialized on shutdown Call save_cache() in atexit handler
Examples Verify your current token scopes:
import requests
def check_token_scopes (access_token: str ) -> list [str ]:
"""Decode token to inspect granted scopes (without validation)."""
import base64, json
payload = access_token.split("." )[1 ]
payload += "=" * (4 - len (payload) % 4 )
claims = json.loads(base64.urlsafe_b64decode(payload))
return claims.get("scp" , "" ).split(" " )
scopes = check_token_scopes(token)
if "Notes.ReadWrite" not in scopes:
raise PermissionError(f"Token only has: {scopes} . Need Notes.ReadWrite." )
Rotate to new credentials without downtime:
az keyvault secret set --vault-name your-vault --name onenote-client-id --value NEW_CLIENT_ID
rm ~/.onenote-token-cache.json
Resources
Next Steps
Apply onenote-prod-checklist for full production readiness review
Use onenote-reference-architecture to understand API path differences across notebook locations
See onenote-rate-limits for throttling and Retry-After handling