-
Notifications
You must be signed in to change notification settings - Fork 15
Account Linking Url: Combined Auth Flow #188
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
base: main
Are you sure you want to change the base?
Conversation
|
What scenarios does this enable? |
the new combined auth flow |
heyitsaamir
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be possible to include what the new flow will look like? Maybe just text or a simple mermaid diagram? The actual change seems small, but I'm not sure how exactly this enables the scenario
| public IList<IRoute> Select(IActivity activity) | ||
| { | ||
| return _routes | ||
| .OrderBy(route => route.Type == RouteType.User ? 0 : 1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so user routes run before system? We should make sure this is in other languages too
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes it works that way in TS as well, this is to ensure that if you register a route over a system (default) route, your route should be the priority. If you defer by calling next it would then use the default implementation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
7ba99ef to
857a402
Compare
Merge Conflicts Resolved ✅I've rebased this PR on the latest Changes MadeThe conflicts were in
Resolution: Combined both changes - all methods now have both Testing✅ Build: Success Core FunctionalityThis PR adds support for the combined auth flow by:
@lilyydu @heyitsaamir - This PR is now ready for review and merge. All conflicts have been resolved and all tests pass. Fixes #163 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR adds support for a combined authentication flow by introducing an optional AccountLinkingUrl configuration. When configured, this URL is returned in the response body of the verify state invoke handler, enabling clients to perform tab authentication and link NAA accounts to bot login accounts.
Key Changes:
- Added
AccountLinkingUrlproperty toOAuthSettingsandTeamsSettingsclasses for configuration - Updated default verify state handler in
AppRouting.csto returnaccountLinkingUrlin the response when configured - Added comprehensive test coverage for the new feature with override capability
Reviewed changes
Copilot reviewed 21 out of 21 changed files in this pull request and generated 13 comments.
Show a summary per file
| File | Description |
|---|---|
| Tests/Microsoft.Teams.Apps.Tests/Activities/Invokes/SignIn/VerifyStateActivityTests.cs | New test file with two test cases: one verifying the default AccountLinkingUrl is returned, another testing override capability |
| Libraries/Microsoft.Teams.Extensions/Microsoft.Teams.Extensions.Configuration/Microsoft.Teams.Apps.Extensions/TeamsSettings.cs | Added AccountLinkingUrl property and Apply method logic to configure it; improved Empty property implementation; added XML documentation |
| Libraries/Microsoft.Teams.Common/Http/HttpCredentials.cs | Added XML documentation for the IHttpCredentials interface |
| Libraries/Microsoft.Teams.Apps/Routing/Router.cs | Modified route selection to prioritize User routes over System routes using OrderBy |
| Libraries/Microsoft.Teams.Apps/OAuthSettings.cs | Added AccountLinkingUrl property and converted from primary constructor to standard class with XML documentation |
| Libraries/Microsoft.Teams.Apps/Contexts/Context.cs | Added new Next(IContext) overload to allow passing a different context through the handler chain |
| Libraries/Microsoft.Teams.Apps/AppRouting.cs | Updated verify state handler to return accountLinkingUrl in response body when configured |
| Libraries/Microsoft.Teams.Apps/AppOptions.cs | Added comprehensive XML documentation for all properties |
| Libraries/Microsoft.Teams.Apps/AppBuilder.cs | Added AddOAuth(OAuthSettings) overload and modified existing AddOAuth(string) to update rather than replace |
| Libraries/Microsoft.Teams.Api/Clients/UserTokenClient.cs | Added parameterless constructor and made methods virtual for testability |
| Libraries/Microsoft.Teams.Api/Clients/UserClient.cs | Made Token property virtual and added parameterless constructor |
| Libraries/Microsoft.Teams.Api/Clients/TeamClient.cs | Made methods virtual for better testability |
| Libraries/Microsoft.Teams.Api/Clients/MemberClient.cs | Made methods virtual for better testability |
| Libraries/Microsoft.Teams.Api/Clients/MeetingClient.cs | Made methods virtual for better testability |
| Libraries/Microsoft.Teams.Api/Clients/ConversationClient.cs | Changed Activities and Members from readonly fields to virtual properties |
| Libraries/Microsoft.Teams.Api/Clients/BotTokenClient.cs | Changed constructor chain and made GetGraphAsync virtual |
| Libraries/Microsoft.Teams.Api/Clients/BotSignInClient.cs | Made methods virtual for better testability |
| Libraries/Microsoft.Teams.Api/Clients/BotClient.cs | Made SignIn property virtual |
| Libraries/Microsoft.Teams.Api/Clients/ActivityClient.cs | Made all public methods virtual for better testability |
| Libraries/Microsoft.Teams.Api/Auth/TokenCredentials.cs | Added XML documentation and renamed unused parameter from _client to _ |
| Libraries/Microsoft.Teams.Api/Auth/ClientCredentials.cs | Added XML documentation with reference link |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
...ns/Microsoft.Teams.Extensions.Configuration/Microsoft.Teams.Apps.Extensions/TeamsSettings.cs
Outdated
Show resolved
Hide resolved
Tests/Microsoft.Teams.Apps.Tests/Activities/Invokes/SignIn/VerifyStateActivityTests.cs
Outdated
Show resolved
Hide resolved
| public UserTokenClient() : base() | ||
| { | ||
|
|
||
| } |
Copilot
AI
Jan 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The parameterless constructor calls base() which doesn't exist in the abstract Client class. The base Client class only has constructors that accept parameters (CancellationToken, IHttpClient, etc.). This will cause a compilation error. Either remove this constructor or ensure the base class has a parameterless constructor.
...ns/Microsoft.Teams.Extensions.Configuration/Microsoft.Teams.Apps.Extensions/TeamsSettings.cs
Outdated
Show resolved
Hide resolved
Tests/Microsoft.Teams.Apps.Tests/Activities/Invokes/SignIn/VerifyStateActivityTests.cs
Outdated
Show resolved
Hide resolved
...ns/Microsoft.Teams.Extensions.Configuration/Microsoft.Teams.Apps.Extensions/TeamsSettings.cs
Outdated
Show resolved
Hide resolved
Tests/Microsoft.Teams.Apps.Tests/Activities/Invokes/SignIn/VerifyStateActivityTests.cs
Outdated
Show resolved
Hide resolved
…s.Configuration/Microsoft.Teams.Apps.Extensions/TeamsSettings.cs Co-authored-by: Copilot <[email protected]>
Co-authored-by: Copilot <[email protected]>
…s.Configuration/Microsoft.Teams.Apps.Extensions/TeamsSettings.cs Co-authored-by: Copilot <[email protected]>
Co-authored-by: Copilot <[email protected]>
…s.Configuration/Microsoft.Teams.Apps.Extensions/TeamsSettings.cs Co-authored-by: Copilot <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 21 out of 21 changed files in this pull request and generated 9 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| public static readonly string GraphScope = "https://graph.microsoft.com/.default"; | ||
|
|
||
| public BotTokenClient() : this(default) | ||
| public BotTokenClient() : base() |
Copilot
AI
Jan 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This parameterless constructor calls base(), but the parent Client class does not have a parameterless constructor. This will cause a compilation error. The previous code was calling base(default) which correctly called the Client(CancellationToken) constructor. Either revert this change to base(default) or add a parameterless constructor to the Client base class.
| public BotTokenClient() : base() | |
| public BotTokenClient() : base(default) |
| /// Called to continue the chain of route handlers using the specified context instance. | ||
| /// Use this overload when you want to invoke the next handler with a different or wrapped | ||
| /// <see cref="IContext{TActivity}"/> than the current one; if not called, no other handlers | ||
| /// in the sequence will be executed. | ||
| /// </summary> | ||
| /// <param name="context">The context to pass to the next handler in the chain.</param> | ||
| public Task<object?> Next(IContext<TActivity> context); | ||
|
|
||
| /// <summary> |
Copilot
AI
Jan 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new Next(IContext<TActivity> context) overload appears redundant. It converts the passed context to IActivity type and calls OnNext, which is the same as what Next() does with the current context. In the test at line 70, context.Next(context) is called, which is functionally equivalent to just calling context.Next(). Consider removing this overload unless there's a specific use case where a different context instance needs to be passed.
| /// Called to continue the chain of route handlers using the specified context instance. | |
| /// Use this overload when you want to invoke the next handler with a different or wrapped | |
| /// <see cref="IContext{TActivity}"/> than the current one; if not called, no other handlers | |
| /// in the sequence will be executed. | |
| /// </summary> | |
| /// <param name="context">The context to pass to the next handler in the chain.</param> | |
| public Task<object?> Next(IContext<TActivity> context); | |
| /// <summary> |
| public virtual ActivityClient Activities { get; } | ||
| public virtual MemberClient Members { get; } |
Copilot
AI
Jan 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Activities and Members properties are changed to virtual with auto-property syntax, but they are initialized in the constructor. This means they cannot be overridden in derived classes since they're set in the base constructor. Consider making them virtual with explicit backing fields, or ensure this pattern is intentional for mocking purposes only.
| namespace Microsoft.Teams.Common.Http; | ||
|
|
||
| /// <summary> | ||
| /// Http Credential resolver used to fetch some access token. |
Copilot
AI
Jan 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a trailing space after "token." in the documentation comment.
| public UserTokenClient() : base() | ||
| { | ||
|
|
||
| } | ||
|
|
Copilot
AI
Jan 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This parameterless constructor calls base(), but the parent Client class does not have a parameterless constructor. This will cause a compilation error. Either add a parameterless constructor to the Client base class, or remove this constructor if it's not needed.
| public UserTokenClient() : base() | |
| { | |
| } |
| public UserClient() : base() | ||
| { | ||
| Token = new UserTokenClient(_http, _cancellationToken); | ||
| } | ||
|
|
||
| public UserClient(CancellationToken cancellationToken = default) : base(cancellationToken) |
Copilot
AI
Jan 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This parameterless constructor calls base(), but the parent Client class does not have a parameterless constructor. This will cause a compilation error. Either add a parameterless constructor to the Client base class, or remove this constructor if it's not needed.
| public UserClient() : base() | |
| { | |
| Token = new UserTokenClient(_http, _cancellationToken); | |
| } | |
| public UserClient(CancellationToken cancellationToken = default) : base(cancellationToken) | |
| public UserClient(CancellationToken cancellationToken = default) : base(cancellationToken) | |
| { | |
| Token = new UserTokenClient(_http, cancellationToken); | |
| } | |
| public UserClient(IHttpClient client, CancellationToken cancellationToken = default) : base(client, cancellationToken) |
| activity = Activity; | ||
| reference = Ref; | ||
| client = new IContext.Client(ToActivityType()); | ||
| } |
Copilot
AI
Jan 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new Next(IContext<TActivity> context) overload appears redundant. It converts the passed context to IActivity type and calls OnNext, which is the same as what Next() does with the current context. In the test at line 70, context.Next(context) is called, which is functionally equivalent to just calling context.Next(). Consider removing this overload unless there's a specific use case where a different context instance needs to be passed.
| public string? ClientId { get; set; } | ||
|
|
||
| /// <summary> | ||
| /// The secret (i.e. password) for your application. |
Copilot
AI
Jan 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The abbreviation "ie" should be "i.e." with periods for proper Latin abbreviation format.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot open a new pull request to apply changes based on this feedback
| return _routes | ||
| .OrderBy(route => route.Type == RouteType.User ? 0 : 1) | ||
| .Where(route => route.Select(activity)) | ||
| .ToList(); |
Copilot
AI
Jan 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The OrderBy operation is applied on every Select call, which could impact performance if there are many routes. Since routes are added through the Register method, consider ordering routes once during registration rather than on every selection. This would avoid repeated sorting operations.
- Fix redundant JwtSecurityTokenHandler creation in tests (reuse existing tokenHandler variable) - Fix inconsistent assertion method (use Assert.Equivalent for anonymous object comparison) All 561 tests pass Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
Addressed Remaining Copilot Review Comments ✅I've synced with the latest changes and addressed the remaining review feedback: Fixes Applied
Already Fixed in Previous CommitsThe following issues were already addressed in earlier commits:
Testing✅ Build: Success All Copilot review comments have been addressed. Ready for final review and merge. |
|
@rajan-chari I've opened a new pull request, #263, to work on those changes. Once the pull request is ready, I'll request review from you. |
|
@copilot open a new pull request to apply changes based on the comments in this thread |
|
@rajan-chari I've opened a new pull request, #264, to work on those changes. Once the pull request is ready, I'll request review from you. |
To support the new combined auth flow, developers can now optionally configure an
accountLinkingUrlthat when present, will be returned by the apps default verify state invoke handler to the server.https://skype.visualstudio.com/SCC/_git/async_messaging_botapiservice/pullrequest/1264762?_a=files&path=/BotNotifications.Library/Services/SendBotInvokeHandler.cs