@@ -23,6 +23,7 @@ import (
2323"github.com/coder/coder/v2/coderd/database/dbauthz"
2424"github.com/coder/coder/v2/coderd/database/dbtestutil"
2525"github.com/coder/coder/v2/coderd/database/dbtime"
26+ "github.com/coder/coder/v2/coderd/httpmw"
2627"github.com/coder/coder/v2/coderd/oauth2provider"
2728"github.com/coder/coder/v2/coderd/userpassword"
2829"github.com/coder/coder/v2/coderd/util/ptr"
@@ -1607,18 +1608,22 @@ func TestOAuth2RegistrationAccessToken(t *testing.T) {
16071608func TestOAuth2CoderClient (t * testing.T ) {
16081609t .Parallel ()
16091610
1610- owner := coderdtest .New (t ,nil )
1611+ db ,pubsub := dbtestutil .NewDB (t )
1612+ owner := coderdtest .New (t ,& coderdtest.Options {
1613+ Database :db ,
1614+ Pubsub :pubsub ,
1615+ })
16111616first := coderdtest .CreateFirstUser (t ,owner )
16121617
16131618// Setup an oauth app
1614- ctx := testutil .Context (t ,testutil .WaitLong )
1615- app ,err := owner .PostOAuth2ProviderApp (ctx , codersdk.PostOAuth2ProviderAppRequest {
1619+ setupCtx := testutil .Context (t ,testutil .WaitLong )
1620+ app ,err := owner .PostOAuth2ProviderApp (setupCtx , codersdk.PostOAuth2ProviderAppRequest {
16161621Name :"new-app" ,
16171622CallbackURL :"http://localhost" ,
16181623})
16191624require .NoError (t ,err )
16201625
1621- appsecret ,err := owner .PostOAuth2ProviderAppSecret (ctx ,app .ID )
1626+ appsecret ,err := owner .PostOAuth2ProviderAppSecret (setupCtx ,app .ID )
16221627require .NoError (t ,err )
16231628
16241629cfg := & oauth2.Config {
@@ -1635,47 +1640,76 @@ func TestOAuth2CoderClient(t *testing.T) {
16351640}
16361641
16371642// Make a new user
1638- client ,user := coderdtest .CreateAnotherUser (t ,owner ,first .OrganizationID )
1643+ userClient ,user := coderdtest .CreateAnotherUser (t ,owner ,first .OrganizationID )
1644+
1645+ // userOAuthFlow is a helper function that runs the oauth flow and returns
1646+ // the codersdk userClient using oauth as the means of authentication.
1647+ userOAuthFlow := func (t * testing.T ) (* codersdk.Client ,* oauth2.Token ) {
1648+ // Do an OAuth2 token exchange and get a new userClient with an oauth token
1649+ state := uuid .NewString ()
1650+
1651+ // Get an OAuth2 code for a token exchange
1652+ code ,err := oidctest .OAuth2GetCode (
1653+ cfg .AuthCodeURL (state ),
1654+ func (req * http.Request ) (* http.Response ,error ) {
1655+ // Change to POST to simulate the form submission
1656+ req .Method = http .MethodPost
1657+
1658+ // Prevent automatic redirect following
1659+ userClient .HTTPClient .CheckRedirect = func (req * http.Request ,via []* http.Request )error {
1660+ return http .ErrUseLastResponse
1661+ }
1662+ return userClient .Request (setupCtx ,req .Method ,req .URL .String (),nil )
1663+ },
1664+ )
1665+ require .NoError (t ,err )
16391666
1640- // Do an OAuth2 token exchange and get a new client with an oauth token
1641- state := uuid . NewString ( )
1667+ token , err := cfg . Exchange ( setupCtx , code )
1668+ require . NoError ( t , err )
16421669
1643- // Get an OAuth2 code for a token exchange
1644- code ,err := oidctest .OAuth2GetCode (
1645- cfg .AuthCodeURL (state ),
1646- func (req * http.Request ) (* http.Response ,error ) {
1647- // Change to POST to simulate the form submission
1648- req .Method = http .MethodPost
1670+ // Use the oauth userClient's authentication
1671+ // TODO: The SDK could probably support this with a better syntax/api.
1672+ oauthClient := oauth2 .NewClient (setupCtx ,oauth2 .StaticTokenSource (token ))
1673+ usingOauth := codersdk .New (owner .URL )
1674+ usingOauth .HTTPClient = oauthClient
16491675
1650- // Prevent automatic redirect following
1651- client .HTTPClient .CheckRedirect = func (req * http.Request ,via []* http.Request )error {
1652- return http .ErrUseLastResponse
1653- }
1654- return client .Request (ctx ,req .Method ,req .URL .String (),nil )
1655- },
1656- )
1657- require .NoError (t ,err )
1676+ me ,err := usingOauth .User (setupCtx ,codersdk .Me )
1677+ require .NoError (t ,err )
1678+ require .Equal (t ,user .ID ,me .ID )
1679+ return usingOauth ,token
1680+ }
16581681
1659- token ,err := cfg .Exchange (ctx ,code )
1660- require .NoError (t ,err )
1682+ //nolint:tparallel,paralleltest
1683+ t .Run ("OauthRevoke" ,func (t * testing.T ) {
1684+ // OauthRevoke uses the proper oauth revocation endpoint to revoke the token.
1685+ ctx := testutil .Context (t ,testutil .WaitShort )
1686+ client ,token := userOAuthFlow (t )
1687+ // Revoking the refresh token should prevent further access
1688+ // Revoking the refresh also invalidates the associated access token.
1689+ err = client .RevokeOAuth2Token (ctx ,app .ID ,token .RefreshToken )
1690+ require .NoError (t ,err )
16611691
1662- // Use the oauth client's authentication
1663- // TODO: The SDK could probably support this with a better syntax/api.
1664- oauthClient := oauth2 .NewClient (ctx ,oauth2 .StaticTokenSource (token ))
1665- usingOauth := codersdk .New (owner .URL )
1666- usingOauth .HTTPClient = oauthClient
1692+ _ ,err = client .User (ctx ,codersdk .Me )
1693+ require .Error (t ,err )
1694+ })
16671695
1668- me ,err := usingOauth .User (ctx ,codersdk .Me )
1669- require .NoError (t ,err )
1670- require .Equal (t ,user .ID ,me .ID )
1696+ //nolint:tparallel,paralleltest
1697+ t .Run ("DeleteAPIKey" ,func (t * testing.T ) {
1698+ // DeleteAPIKey uses the coder api to delete the underlying api key used by the
1699+ // oauth token. This is not the recommended way to revoke oauth tokens, but is
1700+ // supported and should work.
1701+ ctx := testutil .Context (t ,testutil .WaitShort )
1702+ client ,token := userOAuthFlow (t )
16711703
1672- // Revoking the refresh token should prevent further access
1673- // Revoking the refresh also invalidates the associated access token.
1674- err = usingOauth .RevokeOAuth2Token (ctx ,app .ID ,token .RefreshToken )
1675- require .NoError (t ,err )
1704+ id ,_ ,err := httpmw .SplitAPIToken (token .AccessToken )
1705+ require .NoError (t ,err )
16761706
1677- _ ,err = usingOauth .User (ctx ,codersdk .Me )
1678- require .Error (t ,err )
1707+ err = db .DeleteAPIKeyByID (ctx ,id )
1708+ require .NoError (t ,err )
1709+
1710+ _ ,err = client .User (ctx ,codersdk .Me )
1711+ require .Error (t ,err )
1712+ })
16791713}
16801714
16811715// NOTE: OAuth2 client registration validation tests have been migrated to