2
2
// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information.
3
3
// ------------------------------------------------------------------------------
4
4
5
+ using Microsoft . Graph . PowerShell . Authentication . Core . Models ;
6
+ using Microsoft . Graph . PowerShell . Authentication . Models ;
5
7
using Microsoft . Identity . Client ;
6
8
using Newtonsoft . Json ;
7
9
using System ;
8
10
using System . Globalization ;
9
- using System . IdentityModel . Tokens . Jwt ;
11
+ using System . Text ;
10
12
11
13
namespace Microsoft . Graph . PowerShell . Authentication . Core . Utilities
12
14
{
@@ -23,7 +25,7 @@ internal static class JwtHelpers
23
25
/// <param name="authContext">An <see cref="IAuthContext"/> to store JWT claims in.</param>
24
26
internal static void DecodeJWT ( string jwToken , IAccount account , ref IAuthContext authContext )
25
27
{
26
- var jwtPayload = DecodeToObject < Models . JwtPayload > ( jwToken ) ;
28
+ var jwtPayload = DecodeToObject < JwtPayload > ( jwToken ) ;
27
29
if ( authContext . AuthType == AuthenticationType . UserProvidedAccessToken )
28
30
{
29
31
if ( jwtPayload == null )
@@ -50,22 +52,6 @@ internal static void DecodeJWT(string jwToken, IAccount account, ref IAuthContex
50
52
authContext . Account = jwtPayload ? . Upn ?? account ? . Username ;
51
53
}
52
54
53
- /// <summary>
54
- /// Decodes a JWT token by extracting claims from the payload.
55
- /// </summary>
56
- /// <param name="jwToken">A JWT string.</param>
57
- internal static string Decode ( string jwToken )
58
- {
59
- JwtSecurityTokenHandler jwtHandler = new JwtSecurityTokenHandler ( ) ;
60
- if ( jwtHandler . CanReadToken ( jwToken ) )
61
- {
62
- JwtSecurityToken token = jwtHandler . ReadJwtToken ( jwToken ) ;
63
- return token . Payload . SerializeToJson ( ) ;
64
- } else {
65
- return null ;
66
- }
67
- }
68
-
69
55
/// <summary>
70
56
/// Decodes a JWT token by extracting claims from the payload to an object of type T.
71
57
/// </summary>
@@ -75,17 +61,49 @@ internal static T DecodeToObject<T>(string jwtString)
75
61
{
76
62
try
77
63
{
78
- string decodedJWT = Decode ( jwtString ) ;
79
- if ( decodedJWT == null )
64
+ var decodedJWT = DecodeJWT ( jwtString ) ;
65
+ if ( string . IsNullOrWhiteSpace ( decodedJWT ? . Payload ) )
80
66
return default ;
81
- return JsonConvert . DeserializeObject < T > ( decodedJWT ) ;
67
+ return JsonConvert . DeserializeObject < T > ( decodedJWT . Payload ) ;
82
68
}
83
69
catch ( Exception ex )
84
70
{
85
71
throw new AuthenticationException ( ErrorConstants . Message . InvalidJWT , ex ) ;
86
72
}
87
73
}
88
74
75
+ internal static JwtContent DecodeJWT ( string jwtString )
76
+ {
77
+ // See https://tools.ietf.org/html/rfc7519
78
+ if ( string . IsNullOrWhiteSpace ( jwtString ) || ! jwtString . Contains ( "." ) || ! jwtString . StartsWith ( "eyJ" ) )
79
+ throw new ArgumentException ( "Invalid JSON Web Token (JWT)." ) ;
80
+
81
+ var jwtSegments = jwtString . Split ( '.' ) ;
82
+
83
+ if ( jwtSegments . Length <= 1 )
84
+ throw new ArgumentException ( "Invalid JWT. JWT does not have a payload." ) ;
85
+
86
+ // Header
87
+ var jwtHeader = DecodeJwtSegment ( jwtSegments [ 0 ] ) ;
88
+
89
+ // Payload
90
+ var jwtPayload = DecodeJwtSegment ( jwtSegments [ 1 ] ) ;
91
+
92
+ return new JwtContent { Header = jwtHeader , Payload = jwtPayload } ;
93
+ }
94
+
95
+ private static string DecodeJwtSegment ( string jwtSegment )
96
+ {
97
+ jwtSegment = jwtSegment . Replace ( '-' , '+' ) . Replace ( '_' , '/' ) ;
98
+ // Fixes padding by adding '=' until header length modulus 4 equals 0.
99
+ while ( ( jwtSegment . Length % 4 ) != 0 )
100
+ jwtSegment += "=" ;
101
+
102
+ var jwtTokenBytes = Convert . FromBase64String ( jwtSegment ) ;
103
+ var jwtSegmentInJson = Encoding . UTF8 . GetString ( jwtTokenBytes ) ;
104
+ return jwtSegmentInJson ;
105
+ }
106
+
89
107
/// <summary>
90
108
/// Converts a DateTime to Unix timestamp in seconds past epoch.
91
109
/// </summary>
0 commit comments