Skip to content

Commit a57ec5c

Browse files
committed
Implement revokeAccessToken
1 parent f73b24d commit a57ec5c

File tree

7 files changed

+122
-12
lines changed

7 files changed

+122
-12
lines changed

common/api-review/auth.api.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -725,6 +725,9 @@ export class RecaptchaVerifier implements ApplicationVerifierInternal {
725725
// @public
726726
export function reload(user: User): Promise<void>;
727727

728+
// @public
729+
export function revokeAccessToken(auth: Auth, token: string): Promise<void>;
730+
728731
// Warning: (ae-forgotten-export) The symbol "FederatedAuthProvider" needs to be exported by the entry point index.d.ts
729732
//
730733
// @public

packages/auth/demo/src/index.js

Lines changed: 56 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,8 @@ import {
7373
browserPopupRedirectResolver,
7474
connectAuthEmulator,
7575
initializeRecaptchaConfig,
76-
validatePassword
76+
validatePassword,
77+
revokeAccessToken
7778
} from '@firebase/auth';
7879

7980
import { config } from './config';
@@ -1730,13 +1731,60 @@ function logAdditionalUserInfo(response) {
17301731
* Deletes the user account.
17311732
*/
17321733
function onDelete() {
1733-
activeUser()
1734-
['delete']()
1735-
.then(() => {
1736-
log('User successfully deleted.');
1737-
alertSuccess('User successfully deleted.');
1738-
refreshUserData();
1739-
}, onAuthError);
1734+
var isAppleProviderLinked = false;
1735+
1736+
for (const provider of activeUser().providerData) {
1737+
console.log('provider.providerId: ' + provider.providerId);
1738+
if (provider.providerId == 'apple.com') {
1739+
isAppleProviderLinked = true;
1740+
break;
1741+
}
1742+
}
1743+
1744+
if (isAppleProviderLinked) {
1745+
revokeAppleTokenAndDeleteUser();
1746+
} else {
1747+
activeUser()
1748+
['delete']()
1749+
.then(() => {
1750+
log('User successfully deleted.');
1751+
alertSuccess('User successfully deleted.');
1752+
refreshUserData();
1753+
}, onAuthError);
1754+
}
1755+
}
1756+
1757+
function revokeAppleTokenAndDeleteUser() {
1758+
// Re-auth then revoke the token
1759+
const provider = new OAuthProvider('apple.com');
1760+
provider.addScope('email');
1761+
provider.addScope('name');
1762+
1763+
const auth = getAuth();
1764+
// TODO: Make this pop up or redirect. Can't use signInWithPopupRedirect because we need `then`.
1765+
signInWithPopup(auth, provider).then(result => {
1766+
// The signed-in user info.
1767+
const user = result.user;
1768+
const credential = OAuthProvider.credentialFromResult(result);
1769+
const accessToken = credential.accessToken;
1770+
1771+
revokeAccessToken(auth, accessToken)
1772+
.then(() => {
1773+
log('Token successfully revoked.');
1774+
1775+
// Usual user deletion
1776+
activeUser()
1777+
['delete']()
1778+
.then(() => {
1779+
log('User successfully deleted.');
1780+
alertSuccess('User successfully deleted.');
1781+
refreshUserData();
1782+
}, onAuthError);
1783+
})
1784+
.catch(error => {
1785+
console.log(error.message);
1786+
});
1787+
});
17401788
}
17411789

17421790
/**

packages/auth/src/api/authentication/token.ts

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,26 @@ import { querystring } from '@firebase/util';
2222
import {
2323
_getFinalTarget,
2424
_performFetchWithErrorHandling,
25+
_performApiRequest,
26+
_addTidIfNecessary,
2527
HttpMethod,
26-
HttpHeader
28+
HttpHeader,
29+
Endpoint
2730
} from '../index';
2831
import { FetchProvider } from '../../core/util/fetch_provider';
2932
import { Auth } from '../../model/public_types';
3033
import { AuthInternal } from '../../model/auth';
3134

32-
export const enum Endpoint {
35+
export const enum Path {
3336
TOKEN = '/v1/token'
3437
}
3538

39+
export const enum TokenType {
40+
UNSPECIFIED = 'TOKEN_TYPE_UNSPECIFIED',
41+
REFRESH_TOKEN = 'REFRESH_TOKEN',
42+
ACCESS_TOKEN = 'ACCESS_TOKEN'
43+
}
44+
3645
/** The server responses with snake_case; we convert to camelCase */
3746
interface RequestStsTokenServerResponse {
3847
access_token: string;
@@ -46,6 +55,17 @@ export interface RequestStsTokenResponse {
4655
refreshToken: string;
4756
}
4857

58+
export interface RevokeTokenRequest {
59+
provider_id: string;
60+
tokenType: TokenType;
61+
token: string;
62+
idToken: string;
63+
tenantId?: string;
64+
redirectUri?: string;
65+
}
66+
67+
export interface RevokeTokenResponse {}
68+
4969
export async function requestStsToken(
5070
auth: Auth,
5171
refreshToken: string
@@ -63,7 +83,7 @@ export async function requestStsToken(
6383
const url = _getFinalTarget(
6484
auth,
6585
tokenApiHost,
66-
Endpoint.TOKEN,
86+
Path.TOKEN,
6787
`key=${apiKey}`
6888
);
6989

@@ -85,3 +105,15 @@ export async function requestStsToken(
85105
refreshToken: response.refresh_token
86106
};
87107
}
108+
109+
export async function revokeToken(
110+
auth: Auth,
111+
request: RevokeTokenRequest
112+
): Promise<RevokeTokenResponse> {
113+
return _performApiRequest<RevokeTokenRequest, RevokeTokenResponse>(
114+
auth,
115+
HttpMethod.POST,
116+
Endpoint.REVOKE_TOKEN,
117+
_addTidIfNecessary(auth, request)
118+
);
119+
}

packages/auth/src/api/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,8 @@ export const enum Endpoint {
6868
WITHDRAW_MFA = '/v2/accounts/mfaEnrollment:withdraw',
6969
GET_PROJECT_CONFIG = '/v1/projects',
7070
GET_RECAPTCHA_CONFIG = '/v2/recaptchaConfig',
71-
GET_PASSWORD_POLICY = '/v2/passwordPolicy'
71+
GET_PASSWORD_POLICY = '/v2/passwordPolicy',
72+
REVOKE_TOKEN = '/v2/accounts:revokeToken'
7273
}
7374

7475
export const enum RecaptchaClientType {

packages/auth/src/core/auth/auth_impl.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ import { _getInstance } from '../util/instantiator';
6363
import { _getUserLanguage } from '../util/navigator';
6464
import { _getClientVersion } from '../util/version';
6565
import { HttpHeader } from '../../api';
66+
import { TokenType, revokeToken } from '../../api/authentication/token';
6667
import { AuthMiddlewareQueue } from './middleware';
6768
import { RecaptchaConfig } from '../../platform_browser/recaptcha/recaptcha';
6869
import { _logWarn } from '../util/log';
@@ -514,6 +515,22 @@ export class AuthImpl implements AuthInternal, _FirebaseService {
514515
});
515516
}
516517

518+
/**
519+
* Revokes the given access token. Currently only supports Apple OAuth Access token.
520+
*/
521+
async revokeAccessToken(token: string): Promise<void> {
522+
if (this.currentUser) {
523+
const idToken = await this.currentUser.getIdToken();
524+
// Generalize this to accept other providers once supported.
525+
const response = await revokeToken(this, {
526+
provider_id: 'apple.com',
527+
tokenType: TokenType.ACCESS_TOKEN,
528+
token: token,
529+
idToken: idToken
530+
});
531+
}
532+
}
533+
517534
toJSON(): object {
518535
return {
519536
apiKey: this.config.apiKey,

packages/auth/src/core/index.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,14 @@ export function signOut(auth: Auth): Promise<void> {
245245
return getModularInstance(auth).signOut();
246246
}
247247

248+
/**
249+
* Revokes the given access token. Currently only supports Apple OAuth Access token.
250+
*/
251+
export function revokeAccessToken(auth: Auth, token: string): Promise<void> {
252+
const authInternal = _castAuth(auth);
253+
return authInternal.revokeAccessToken(token);
254+
}
255+
248256
export { initializeAuth } from './auth/initialize';
249257
export { connectAuthEmulator } from './auth/emulator';
250258

packages/auth/src/model/auth.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,4 +105,5 @@ export interface AuthInternal extends Auth {
105105
useDeviceLanguage(): void;
106106
signOut(): Promise<void>;
107107
validatePassword(password: string): Promise<PasswordValidationStatus>;
108+
revokeAccessToken(token: string): Promise<void>;
108109
}

0 commit comments

Comments
 (0)