Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Test: Finalized getAccounts API & AuthenticationProvider changes #226540

Closed
2 tasks done
TylerLeonhardt opened this issue Aug 24, 2024 · 8 comments
Closed
2 tasks done

Test: Finalized getAccounts API & AuthenticationProvider changes #226540

TylerLeonhardt opened this issue Aug 24, 2024 · 8 comments

Comments

@TylerLeonhardt
Copy link
Member

TylerLeonhardt commented Aug 24, 2024

Refs: #152399

Complexity: 5

Create Issue


This iteration we've finalized the getAccounts API that was previously tested here.

An "Account" is basically an identity, without access to anything. It just says who you are... while a "Session", on the other hand, has an accessToken that can access whatever scopes (or permissions) were requested. This also means that the concept of scopes doesn't matter to an "Account"... and scopes only matter to "session".

Put plainly, 1 account can have multiple sessions tied to it.

Next context! An AuthenticationProvider can be marked as supporting only 1 account or multiple accounts at a time. For this TPI, it's really only applicable when you support multiple accounts so make sure you do that.

Alright, enough chat... let's test.

Prereqs

  • Have an extension (don't have one? create one!)
  • Run npx @vscode/dts main to get the latest API file

Implement an Authentication Provider

You'll want to:

  • Contribute an Auth Provider in the authentication contribution section of the package.json
  • Then register an Auth Provider using:
    vscode.authentication.registerAuthenticationProvider(id, name, yourAuthProvider, { supportsMultipleAccounts: true });

You can absolutely attempt to implement a full auth provider if you'd like... I'm not gonna stop you :) Here's what my Spotify one looks like (but it's not multi-account).

But it's not necessary. Having getSessions and createSession return dummy data is totally fine for this TPI. Just make sure you test having it:

  • return zero sessions (which causes createSession to run if you pass in the createIfNone flag)
  • return 1 or many sessions but of only 1 account
  • return several sessions with different accounts

The important part is having getSessions and createSession take in the new:

	export interface AuthenticationProviderSessionOptions {
		/**
		 * The account that is being asked about. If this is passed in, the provider should
		 * attempt to return the sessions that are only related to this account.
		 */
		account?: AuthenticationSessionAccountInformation;
	}

and do something with it. This property will be used to filter down the list of sessions we have to only the account passed in or used to create a session specific to that account.

Once you have an Auth Provider, it's time to use it.

Implement something that uses the new getAccounts & additions to getSession API

Now time for the consumer! (you can do this in the same extension via a Command or something)

Play around with the vscode.authentication.getAccounts API which should return all accounts that you are logged in to.

Additionally, play around with passing an account returned by that API into vscode.authentication.getSession via the options.

@chrmarti
Copy link
Contributor

Unlike stated in the description above, createSession did not get called when getSessions returned an empty array. I don't necessarily think it should, but am not sure if that's an issue with the description above or my understanding:

// The module 'vscode' contains the VS Code extensibility API
// Import the module and reference it with the alias vscode in your code below
import * as vscode from 'vscode';
import * as crypto from 'crypto';

// This method is called when your extension is activated
// Your extension is activated the very first time the command is executed
export function activate(context: vscode.ExtensionContext) {

	// Use the console to output diagnostic information (console.log) and errors (console.error)
	// This line of code will only be executed once when your extension is activated
	console.log('Congratulations, your extension "multi-account-test" is now active!');

	// The command has been defined in the package.json file
	// Now provide the implementation of the command with registerCommand
	// The commandId parameter must match the command field in package.json
	const disposable = vscode.commands.registerCommand('multi-account-test.helloWorld', async () => {
		// The code you place here will be executed every time your command is executed
		// Display a message box to the user
		vscode.window.showInformationMessage('Hello World from multi-account-test!');
		
		const accounts = await vscode.authentication.getAccounts('multi-account-test');
		console.log('accounts', accounts);
		const sessions = await vscode.authentication.getSession('multi-account-test', [], {});
		console.log('sessions', sessions);
	});

	context.subscriptions.push(disposable);

	const emitter = new vscode.EventEmitter<vscode.AuthenticationProviderAuthenticationSessionsChangeEvent>();
	vscode.authentication.registerAuthenticationProvider('multi-account-test', 'Multi Account Test', {
		onDidChangeSessions: emitter.event,
		getSessions: async (scopes: readonly string[] | undefined, options: vscode.AuthenticationProviderSessionOptions): Promise<vscode.AuthenticationSession[]> => {
			return [];
		},
		createSession: async (scopes: readonly string[], options: vscode.AuthenticationProviderSessionOptions): Promise<vscode.AuthenticationSession> => {
			return {
				id: 'test-id-' + crypto.randomUUID(),
				accessToken: 'test-token-' + crypto.randomUUID(),
				account: options.account || { id: 'test-account-id', label: 'Test Account' },
				scopes: scopes,
			};
		},
		removeSession: async (sessionId: string): Promise<void> => {
			return;
		},
	}, { supportsMultipleAccounts: true });
}

// This method is called when your extension is deactivated
export function deactivate() {}

@chrmarti
Copy link
Contributor

Not getting a session here, please clarify:

// The module 'vscode' contains the VS Code extensibility API
// Import the module and reference it with the alias vscode in your code below
import * as vscode from 'vscode';
import * as crypto from 'crypto';

// This method is called when your extension is activated
// Your extension is activated the very first time the command is executed
export function activate(context: vscode.ExtensionContext) {

	// Use the console to output diagnostic information (console.log) and errors (console.error)
	// This line of code will only be executed once when your extension is activated
	console.log('Congratulations, your extension "multi-account-test" is now active!');

	// The command has been defined in the package.json file
	// Now provide the implementation of the command with registerCommand
	// The commandId parameter must match the command field in package.json
	const disposable = vscode.commands.registerCommand('multi-account-test.helloWorld', async () => {
		// The code you place here will be executed every time your command is executed
		// Display a message box to the user
		vscode.window.showInformationMessage('Hello World from multi-account-test!');
		
		const accounts = await vscode.authentication.getAccounts('multi-account-test');
		console.log('accounts', accounts);
		const session = await vscode.authentication.getSession('multi-account-test', ['scope1'], { account: accounts[0] });
		console.log('session', session);
	});

	context.subscriptions.push(disposable);

	const sessions: vscode.AuthenticationSession[] = [
		{
			id: 'test-id-' + crypto.randomUUID(),
			accessToken: 'test-token-' + crypto.randomUUID(),
			account: { id: 'test-account-id-1', label: 'Test Account 1' },
			scopes: ['scope1'],
		}
	];

	const emitter = new vscode.EventEmitter<vscode.AuthenticationProviderAuthenticationSessionsChangeEvent>();
	vscode.authentication.registerAuthenticationProvider('multi-account-test', 'Multi Account Test', {
		onDidChangeSessions: emitter.event,
		getSessions: async (scopes: readonly string[] | undefined, options: vscode.AuthenticationProviderSessionOptions): Promise<vscode.AuthenticationSession[]> => {
			return sessions;
		},
		createSession: async (scopes: readonly string[], options: vscode.AuthenticationProviderSessionOptions): Promise<vscode.AuthenticationSession> => {
			return {
				id: 'test-id-' + crypto.randomUUID(),
				accessToken: 'test-token-' + crypto.randomUUID(),
				account: options.account || { id: 'test-account-id', label: 'Test Account' },
				scopes: scopes,
			};
		},
		removeSession: async (sessionId: string): Promise<void> => {
			return;
		},
	}, { supportsMultipleAccounts: true });
}

// This method is called when your extension is deactivated
export function deactivate() {}

@TylerLeonhardt
Copy link
Member Author

@chrmarti your call to:

vscode.authentication.getSession

Will only show a badge on the Account menu. When you click on it createSession will be called. You can also use createIfNone: true in the options to force session creation.

@chrmarti
Copy link
Contributor

Got it, that helped, thanks.

@roblourens
Copy link
Member

I got a little stuck on #226904, I also see #226783, but Tyler is out. We can find someone else who understands this or just get back to it when Tyler is back.

@roblourens roblourens removed their assignment Aug 28, 2024
@chrmarti chrmarti removed their assignment Aug 28, 2024
@chrmarti
Copy link
Contributor

chrmarti commented Aug 28, 2024

Left a few more notes in #226783.

How would an auth provider indicate that it knows one or several accounts, but has no session to them yet? This doesn't seem possible, is that an intentional limitation?

@TylerLeonhardt
Copy link
Member Author

TylerLeonhardt commented Sep 5, 2024

How would an auth provider indicate that it knows one or several accounts, but has no session to them yet? This doesn't seem possible, is that an intentional limitation?

@chrmarti The intent is that you should have a session. I suppose one way this could be done is by having a session with scopes [] or something to signify that you have an account.

@TylerLeonhardt
Copy link
Member Author

TylerLeonhardt commented Sep 5, 2024

@roblourens can you see @chrmarti's latest notes in #226783 and see if maybe you were seeing the same (it was his implementation, not the platform)?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants