@@ -3,27 +3,104 @@ import { ref } from "vue";
33import { useDBSLoginWebcomponentPlugin } from "@/components/DBSLoginWebcomponentPlugin" ;
44import AuthorizationEventDetails from "@/types/AuthorizationEventDetails" ;
55
6- function parseJwt ( token : string ) {
7- const base64Url = token . split ( "." ) [ 1 ] ;
6+ class JwtParseError extends Error {
7+ constructor ( message : string , options ?: { cause ?: unknown } ) {
8+ super ( message ) ;
9+ this . name = "JwtParseError" ;
10+ if ( options ?. cause !== undefined ) {
11+ this . cause = options . cause ;
12+ }
13+ }
14+ }
15+
16+ function getJwtPayloadSegment ( token : string ) : string {
17+ if ( ! token ?. trim ( ) ) {
18+ throw new JwtParseError ( "Invalid JWT: token must be a non-empty string" ) ;
19+ }
20+
21+ const parts = token . split ( "." ) ;
22+ if ( parts . length !== 3 ) {
23+ throw new JwtParseError (
24+ `Invalid JWT: expected 3 dot-separated segments, got ${ parts . length } `
25+ ) ;
26+ }
27+
28+ const payloadSegment = parts [ 1 ] ;
29+ if ( ! payloadSegment ) {
30+ throw new JwtParseError ( "Invalid JWT: payload segment is missing" ) ;
31+ }
32+
33+ return payloadSegment ;
34+ }
35+
36+ function base64UrlToBase64 ( base64Url : string ) : string {
837 const base64 = base64Url . replace ( / - / g, "+" ) . replace ( / _ / g, "/" ) ;
9- const jsonPayload = decodeURIComponent (
10- window
11- . atob ( base64 )
12- . split ( "" )
13- . map ( function ( c ) {
14- return "%" + ( "00" + c . charCodeAt ( 0 ) . toString ( 16 ) ) . slice ( - 2 ) ;
15- } )
16- . join ( "" )
17- ) ;
18- return JSON . parse ( jsonPayload ) ;
38+ const paddingLength = ( 4 - ( base64 . length % 4 ) ) % 4 ;
39+ return base64 + "=" . repeat ( paddingLength ) ;
40+ }
41+
42+ function decodeJwtPayloadSegment ( payloadSegment : string ) : string {
43+ const base64 = base64UrlToBase64 ( payloadSegment ) ;
44+
45+ let decoded : string ;
46+ try {
47+ decoded = window . atob ( base64 ) ;
48+ } catch ( error ) {
49+ throw new JwtParseError ( "Invalid JWT: failed to base64-decode payload" , {
50+ cause : error ,
51+ } ) ;
52+ }
53+
54+ try {
55+ return decodeURIComponent (
56+ decoded
57+ . split ( "" )
58+ . map ( ( character ) => {
59+ return "%" + ( "00" + character . charCodeAt ( 0 ) . toString ( 16 ) ) . slice ( - 2 ) ;
60+ } )
61+ . join ( "" )
62+ ) ;
63+ } catch ( error ) {
64+ throw new JwtParseError ( "Invalid JWT: failed to decode payload bytes" , {
65+ cause : error ,
66+ } ) ;
67+ }
68+ }
69+
70+ function parseJwt ( token : string ) : Record < string , unknown > {
71+ const payloadSegment = getJwtPayloadSegment ( token ) ;
72+ const jsonPayload = decodeJwtPayloadSegment ( payloadSegment ) ;
73+
74+ try {
75+ const parsed : unknown = JSON . parse ( jsonPayload ) ;
76+ if (
77+ parsed === null ||
78+ typeof parsed !== "object" ||
79+ Array . isArray ( parsed )
80+ ) {
81+ throw new JwtParseError ( "Invalid JWT: payload must be a JSON object" ) ;
82+ }
83+ return parsed as Record < string , unknown > ;
84+ } catch ( error ) {
85+ if ( error instanceof JwtParseError ) {
86+ throw error ;
87+ }
88+ throw new JwtParseError ( "Invalid JWT: payload is not valid JSON" , {
89+ cause : error ,
90+ } ) ;
91+ }
1992}
2093
2194export function getTokenData ( accessToken : string ) : {
2295 email ?: string ;
2396 given_name ?: string ;
2497 family_name ?: string ;
2598} {
26- return parseJwt ( accessToken ) ;
99+ return parseJwt ( accessToken ) as {
100+ email ?: string ;
101+ given_name ?: string ;
102+ family_name ?: string ;
103+ } ;
27104}
28105
29106export function useLogin ( ) {
0 commit comments