A fully functioning demonstration of authentication and authorization for a visual studio code extension using OAuth 2 device code flow.
- IDE - An integrated development environment is used by software engineers to build software. Typically includes a text editor combined with a compiler in a convenient way.
- Examples: emacs, XCode, Visual Studio Code
- Extension/PlugIn - In this context, an extension is a 3rd party addition to an existing IDE that extends its functionality. Typically this extended functionality is to aid developer productivity.
- API Key - Similar to an access token, an API Key is a string used to gain access to an API. They are long lived and typically are issued on a per developer basis. They are a simple way to integrate with an external service.
There are a number of service-based SaaS companies that offer developer tooling that integrates with common software development environments (IDE) to provide interactivity with their service. As an example, consider Twilio and Vonage's VSCode Extensions. A common pattern for authorization is to have the user retrieve an API key from the service and configure the developer tool using it.
This of course leads to the propagation of API keys in insecure ways where the key is exposed to leakage and usage in ways they was not issued for specifically. A better solution would be to require the user to communicate with an authorization server to gain access to the API in a limited secure method that does not expose the API keys outside of the running instance of the developer tool.
- As a software engineer, when I am developing integrations with 3rd party services, I would like to stay in the context of my software development workflow so that I do not have to switch to a browser to manage/gather information form those 3rd party services.
- As a SaaS, when offering API access to software developers for my platform, I would like to limit the scope of access to the context of the task at hand by the devloper so that there are ample opprotunities to make authorization decisions.
Device code flow uses a disconnected workflow that is tied together by matching a Device Code via both sides of the workflow. This workflow begins in the IDE, transfers to the User's browser, and returns to the IDE for completion.
The IDE is configured to do Device Code Grant to get id, access and refresh tokens. Once authorized, when the user interacts with the extension features, it can use the access token to authorize request to the external API.
sequenceDiagram
autonumber
User->>IDE: Issue Sign In Command
IDE->>Auth0 Tenant: Authorization request to /oauth/device/code
Auth0 Tenant->>IDE: Device Code + User Code + Verification URL
IDE->>User: Display User Code
IDE->>User: Open Verification URL in Browser
Note over User: User switches to Browser Flow
loop Polling
IDE->>Auth0 Tenant: Access token request to /oauth/token
end
Note over Auth0 Tenant: Once user has completed Browser Flow
Auth0 Tenant->>IDE: Returns Access Token
IDE->>API: Request user data with Access Token
API->>IDE: Response with data
- User issues the sign in command to the IDE.
- The IDE makes a POST request to the
/oauth/device/code
endpoint on the Auth0 Tenant passing the following elements:- Extension Client ID
- API Audience
- Requested Scopes
- The Tenant responds with:
- Device Code
- User Code
- Verification URL
- The IDE displays the User Code to the user
- The IDE prompts the user to open the Verification URL in the system browser.
- At this point the flow splits with the user entering the Browser Flow and the IDE begins polling the
/oauth/token
endpoint of the Auth0 tenant. - Once the user has completed the Browser Flow, the Auth0 Tenant returns requested tokens to the IDE.
- The IDE request user data using the Access Token.
- The API responds with the data.
sequenceDiagram
autonumber
User->>Auth0 Tenant: User Navigates to the Verification Url
Auth0 Tenant->>User: Tenant displays the device code to user
User->>Auth0 Tenant: User confirms the device code matches the code displayed in the IDE
Auth0 Tenant->>User: Redirect to login/authorization prompt
User->>Auth0 Tenant: User authenticates and gives consent
Auth0 Tenant->>User: Mark device as authorized and displays success message
- IDE opens system browser to the Verification Url on the Auth0 Tenant.
- Tenant displays the device code to the user.
- User confirms the device code displayed matches the device code displayed in the IDE.
- Tenant redirects to the Universal Login
/login/authorization
prompt. - User authenticates and gives consent to requested scopes.
- Auth0 Tenant markes device as authorized and displays success message.
- User returns to IDE in the process of completing the IDE flow.
- Add command references to package.json manifest. Command text should be name spaced in a meaningful way to avoid command text collisions with other extensions.
- Register command texts with command handlers. It is a good idea to seperate UI related implementation from low level implementation communicating with the authorization server.
- Implement command handlers to interact with the user through status updates and display messages.
- Token recieved should be stored securely using builtin storage APIs
- Implement token fetching asyncronously to provide an opprotunity to detect token expiration and request new token sets using the refresh token.
- Implement a notification mechanism to notify listeners of authorization status changes.
- abort-controller
- openid-client
First clone the repository and install needed dependencies.
git clone git@github.com:NotMyself/vscode-extension-device-code-flow.git
cd labs-vscode-extension
npm install
Open the repository as a folder in Visual Studio Code and
under the Debug Tab, select Run Extension
.