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

remove default AuthorizationGate implementation, remove Authorization… #3

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 0 additions & 48 deletions packages/react-app-auth/src/AuthorizationGate.tsx

This file was deleted.

30 changes: 29 additions & 1 deletion packages/react-app-auth/src/apollo/createRefreshHandler.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { AuthorizationServiceConfiguration, BaseTokenRequestHandler, FetchRequestor, GRANT_TYPE_REFRESH_TOKEN, TokenRequest } from "@openid/appauth";

import { AuthorizationManager } from "../createAuthorizationManager";
import { OAuthData } from "../OAuthData";
import { AuthConfiguration } from "../types";
Expand All @@ -24,6 +26,32 @@ export interface RefreshHandler {
stopAutomaticRefresh: () => void;
}

const refresh = async (authorizationConfig: AuthConfiguration, authorizationManager: AuthorizationManager) => {
const tokenHandler = new BaseTokenRequestHandler(new FetchRequestor());

if (authorizationManager.state.oAuth?.refreshToken) {
const request = new TokenRequest({
client_id: authorizationConfig.clientId,
redirect_uri: authorizationConfig.redirectUrl,
grant_type: GRANT_TYPE_REFRESH_TOKEN,
code: undefined,
refresh_token: authorizationManager.state.oAuth.refreshToken,
extras: undefined,
});
try {
const configuration = await AuthorizationServiceConfiguration.fetchFromIssuer(authorizationConfig.issuer, new FetchRequestor());
const tokenResponse = await tokenHandler.performTokenRequest(configuration, request);
await authorizationManager.saveOAuth(tokenResponse);
return tokenResponse;
} catch (error) {
console.error("Error", error);
throw new Error(`can not refresh Token - error occured${JSON.stringify(error)}`);
}
}

throw new Error("can not refresh Token because there is no refresh_token");
};

/**
* The RefreshHandler knows if an access token - refresh is currently in progress.
* The RefreshHandler is also responsible for temporary storing callback of pending
Expand Down Expand Up @@ -69,8 +97,8 @@ export const createRefreshHandler = (authorizationManager: AuthorizationManager)

const refreshAccessToken = (authorizationConfig: AuthConfiguration, onOAuthRefreshedCallback: (oAuth: OAuthData) => void) => {
setIsRefreshing(true);
const refreshPromise = authorizationManager.refresh();

const refreshPromise = refresh(authorizationConfig, authorizationManager);
refreshPromise
.then((refreshedOAuth) => {
if (refreshedOAuth.refreshToken) {
Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

45 changes: 2 additions & 43 deletions packages/react-app-auth/src/createAuthorizationManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import {
BaseTokenRequestHandler,
DefaultCrypto,
FetchRequestor,
GRANT_TYPE_REFRESH_TOKEN,
LocalStorageBackend,
RedirectRequestHandler,
RevokeTokenRequest,
Expand All @@ -30,20 +29,9 @@ export interface AuthorizationManager {
onOAuthChange: (next: (value: OAuthData | null) => void) => Subscription;
saveOAuth: (oauth: OAuthData | null) => Promise<void>;
signOut: () => Promise<void>;
refresh: () => Promise<OAuthData>;
isProcessingToken: (location: Location) => boolean;
}

export interface CreateAuthorizationManagerOptions {
authorizationConfig: AuthConfiguration;
isProcessingToken?: (location: Location) => boolean;
}
export const createAuthorizationManager = ({
authorizationConfig,
isProcessingToken = (location) => {
return window.location.href.startsWith(authorizationConfig.redirectUrl ?? "");
},
}: CreateAuthorizationManagerOptions): AuthorizationManager => {
export const createAuthorizationManager = (authorizationConfig: AuthConfiguration): AuthorizationManager => {
const state: AuthorizationManager["state"] = {
oAuth: null,
userProfile: null,
Expand Down Expand Up @@ -115,7 +103,7 @@ export const createAuthorizationManager = ({
});

// if redirect url matches configuration and code parameter is available then go further with the authorization process
if (isProcessingToken(window.location)) {
if (window.location.toString().startsWith(authorizationConfig.redirectUrl)) {
const params = new URLSearchParams(window.location.search);
if (params.get("code")) {
try {
Expand Down Expand Up @@ -211,34 +199,5 @@ export const createAuthorizationManager = ({
await saveOAuth(null);
signOutSubject.next();
},
refresh: async () => {
return new Promise<OAuthData>((resolve, reject) => {
if (state.oAuth?.refreshToken) {
const request = new TokenRequest({
client_id: authorizationConfig.clientId,
redirect_uri: authorizationConfig.redirectUrl,
grant_type: GRANT_TYPE_REFRESH_TOKEN,
code: undefined,
refresh_token: state.oAuth.refreshToken,
extras: undefined,
});
AuthorizationServiceConfiguration.fetchFromIssuer(authorizationConfig.issuer, new FetchRequestor())
.then((response) => {
return tokenHandler.performTokenRequest(response, request);
})
.then((response) => {
saveOAuth(response);
resolve(response);
})
.catch((error) => {
console.error("Error", error);
reject(`can not refresh Token - error occured${JSON.stringify(error)}`);
});
} else {
reject("can not refresh Token because there is no refresh_token");
}
});
},
isProcessingToken: isProcessingToken,
};
};
3 changes: 0 additions & 3 deletions packages/react-app-auth/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@ export { createOnErrorRefreshTokenLink } from "./apollo/links/createOnErrorRefre
export { createRefreshTokenLink } from "./apollo/links/createRefreshTokenLink";
export { setAuthorizationContext } from "./apollo/links/setAuthorizationContext";
export { setOAuthContext } from "./apollo/links/setOAuthContext";
export { AuthorizationProvider } from "./authorizationcontext/AuthorizationProvider";
export { useAuthorization } from "./authorizationcontext/useAuthorization";
export { AuthorizationGate } from "./AuthorizationGate";
export { AuthorizationManager, createAuthorizationManager } from "./createAuthorizationManager";
export { AuthConfiguration, AuthError } from "./types";
export { useOAuth } from "./useOAuth";
Expand Down
88 changes: 74 additions & 14 deletions packages/react-app-auth/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { AuthorizationRequest } from "@openid/appauth";

//TODO: align web - native
export interface OAuthResult {
accessToken: string;
Expand All @@ -11,33 +9,95 @@ export interface OAuthResult {
[other: string]: unknown;
}

export type UserProfile = {
name?: string;
given_name?: string;
family_name?: string;
middle_name?: string;
email?: string;
email_verified?: boolean;
gender?: string;
birthdate?: string;
locale?: string;
updated_at?: number;
export type UserProfile = IDTokenClaims & ProfileStandardClaims;

interface IDTokenClaims {
/** Issuer Identifier */
iss: string;
/** Subject identifier */
sub: string;
/** Audience(s): client_id ... */
aud: string;
/** Expiration time */
exp: number;
/** Issued at */
iat: number;
/** Time when the End-User authentication occurred */
auth_time?: number;
/** Time when the End-User authentication occurred */
nonce?: number;
/** Access Token hash value */
at_hash?: string;
/** Authentication Context Class Reference */
acr?: string;
/** Authentication Methods References */
amr?: string[];
/** Authorized Party - the party to which the ID Token was issued */
azp?: string;
/** Session ID - String identifier for a Session */
sid?: string;

/** Other custom claims */
[claimKey: string]: unknown;
};
}

interface ProfileStandardClaims {
/** End-User's full name */
name?: string;
/** Given name(s) or first name(s) of the End-User */
given_name?: string;
/** Surname(s) or last name(s) of the End-User */
family_name?: string;
/** Middle name(s) of the End-User */
middle_name?: string;
/** Casual name of the End-User that may or may not be the same as the given_name. */
nickname?: string;
/** Shorthand name that the End-User wishes to be referred to at the RP, such as janedoe or j.doe. */
preferred_username?: string;
/** URL of the End-User's profile page */
profile?: string;
/** URL of the End-User's profile picture */
picture?: string;
/** URL of the End-User's Web page or blog */
website?: string;
/** End-User's preferred e-mail address */
email?: string;
/** True if the End-User's e-mail address has been verified; otherwise false. */
email_verified?: boolean;
/** End-User's gender. Values defined by this specification are female and male. */
gender?: string;
/** End-User's birthday, represented as an ISO 8601:2004 [ISO8601‑2004] YYYY-MM-DD format */
birthdate?: string;
/** String from zoneinfo [zoneinfo] time zone database representing the End-User's time zone. */
zoneinfo?: string;
/** End-User's locale, represented as a BCP47 [RFC5646] language tag. */
locale?: string;
/** End-User's preferred telephone number. */
phone_number?: string;
/** True if the End-User's phone number has been verified; otherwise false. */
phone_number_verified?: boolean;
/** object End-User's preferred address in JSON [RFC4627] */
address?: OidcAddress;
/** Time the End-User's information was last updated. */
updated_at?: number;
}

interface OidcAddress {
/** Full mailing address, formatted for display or use on a mailing label */
formatted?: string;
/** Full street address component, which MAY include house number, street name, Post Office Box, and multi-line extended street address information */
street_address?: string;
/** City or locality component */
locality?: string;
/** State, province, prefecture, or region component */
region?: string;
/** Zip code or postal code component */
postal_code?: string;
/** Country name component */
country?: string;
}

import { AuthorizationRequest } from "@openid/appauth";

export type AuthConfiguration = {
issuer: string;
Expand Down
19 changes: 8 additions & 11 deletions packages/react-app-auth/src/useOAuth.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,25 @@
import * as React from "react";

import { useAuthorization } from "./authorizationcontext/useAuthorization";
import { AuthorizationManager } from "./createAuthorizationManager";
import { OAuthData } from "./OAuthData";

/*
* returns the stored oAuth information
* */
export function useOAuth(): OAuthData | null {
const authorization = useAuthorization();

export function useOAuth(authorizationManager: AuthorizationManager): OAuthData | null {
const [oAuth, setOAuth] = React.useState<OAuthData | null>(null);
React.useEffect(() => {
const subscription = authorization?.authorizationManager.onOAuthChange(() => {
if (authorization?.authorizationManager.state.oAuth != null) {
setOAuth(authorization?.authorizationManager.state.oAuth);
const subscription = authorizationManager.onOAuthChange(() => {
if (authorizationManager.state.oAuth != null) {
setOAuth(authorizationManager.state.oAuth);
} else {
setOAuth(null);
}
});
return () => {
if (subscription) {
subscription.unsubscribe();
}
subscription.unsubscribe();
};
}, [authorization]);
/* eslint-disable-next-line react-hooks/exhaustive-deps */
}, []);
return oAuth;
}
3 changes: 2 additions & 1 deletion packages/react-app-auth/src/useSetAuthorizationCookies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,6 @@ export function useSetAuthorizationCookies({
return () => {
subscription.unsubscribe();
};
}, [accessTokenCookieDomain, accessTokenCookieName, accessTokenCookieOptions, authorizationManager]);
/* eslint-disable-next-line react-hooks/exhaustive-deps */
}, []);
}
Loading