Meet industry peers, ask questions, collaborate to find answers, and connect with Googlers who are making the products you use every day.<\/p>", "imageupload.max_uploaded_images_per_upload" : 100, "imageupload.max_uploaded_images_per_user" : 10000, "integratedprofile.connect_mode" : "", "tkb.toc_maximum_heading_level" : "2", "tkb.toc_heading_list_style" : "disc", "sharedprofile.show_hovercard_score" : true, "config.search_before_post_scope" : "community", "tkb.toc_heading_indent" : "15", "p13n.cta.recommendations_feed_dismissal_timestamp" : -1, "imageupload.max_file_size" : 10024, "layout.show_batch_checkboxes" : false, "integratedprofile.cta_connect_slim_dismissal_timestamp" : -1 }, "isAnonymous" : true, "policies" : { "image-upload.process-and-remove-exif-metadata" : true }, "registered" : false, "emailRef" : "", "id" : -1, "login" : "Former Community Member" }, "Server" : { "communityPrefix" : "/qsqph94282", "nodeChangeTimeStamp" : 1732558519018, "tapestryPrefix" : "/gc", "deviceMode" : "DESKTOP", "responsiveDeviceMode" : "DESKTOP", "membershipChangeTimeStamp" : "0", "version" : "24.7", "branch" : "24.7-release", "showTextKeys" : false }, "Config" : { "phase" : "prod", "integratedprofile.cta.reprompt.delay" : 30, "profileplus.tracking" : { "profileplus.tracking.enable" : false, "profileplus.tracking.click.enable" : false, "profileplus.tracking.impression.enable" : false }, "app.revision" : "2409051714-s8dac8f1df8-b80", "navigation.manager.community.structure.limit" : "1000" }, "Activity" : { "Results" : [ ] }, "NodeContainer" : { "viewHref" : "https://www.googlecloudcommunity.com/gc/Cloud-Forums/ct-p/cloud-forums", "description" : "Get answers to your questions and share your knowledge about the Google Cloud.", "id" : "cloud-forums", "shortTitle" : "Cloud Forums", "title" : "Cloud Forums", "nodeType" : "category" }, "Page" : { "skins" : [ "googlecloud", "theme_hermes", "responsive_peak" ], "authUrls" : { "loginUrl" : "https://www.googlecloudcommunity.com/gc/user/userloginpage?dest_url=https%3A%2F%2Fwww.googlecloudcommunity.com%2Fgc%2FApigee%2FGenerateJWT-only-for-JWT-Tokens-of-Apigee%2Fm-p%2F835963%2Fthread-id%2F81293", "loginUrlNotRegistered" : "https://www.googlecloudcommunity.com/gc/user/userloginpage?redirectreason=notregistered&dest_url=https%3A%2F%2Fwww.googlecloudcommunity.com%2Fgc%2FApigee%2FGenerateJWT-only-for-JWT-Tokens-of-Apigee%2Fm-p%2F835963%2Fthread-id%2F81293", "loginUrlNotRegisteredDestTpl" : "https://www.googlecloudcommunity.com/gc/user/userloginpage?redirectreason=notregistered&dest_url=%7B%7BdestUrl%7D%7D" }, "name" : "ForumTopicPage", "rtl" : false, "object" : { "viewHref" : "/gc/Apigee/GenerateJWT-only-for-JWT-Tokens-of-Apigee/td-p/835963", "subject" : "GenerateJWT only for JWT Tokens of Apigee", "id" : 835963, "page" : "ForumTopicPage", "type" : "Thread" } }, "WebTracking" : { "Activities" : { }, "path" : "Community:Google Cloud Community/Category:Google Cloud/Category:Cloud Forums/Board:Apigee/Message:GenerateJWT only for JWT Tokens of Apigee" }, "Feedback" : { "targeted" : { } }, "Seo" : { "markerEscaping" : { "pathElement" : { "prefix" : "@", "match" : "^[0-9][0-9]$" }, "enabled" : false } }, "TopLevelNode" : { "viewHref" : "https://www.googlecloudcommunity.com/gc/Google-Cloud/ct-p/google-cloud", "description" : "Find answers, ask questions, and connect with our community of experts.", "id" : "google-cloud", "shortTitle" : "Google Cloud", "title" : "Google Cloud", "nodeType" : "category" }, "Community" : { "viewHref" : "https://www.googlecloudcommunity.com/", "integratedprofile.lang_code" : "en", "integratedprofile.country_code" : "US", "id" : "qsqph94282", "shortTitle" : "Google Cloud Community", "title" : "Google Cloud Community" }, "CoreNode" : { "conversationStyle" : "forum", "viewHref" : "https://www.googlecloudcommunity.com/gc/Apigee/bd-p/cloud-apigee", "settings" : { }, "description" : "Have questions about Apigee? Get answers and support from a global network of experts here.", "id" : "cloud-apigee", "shortTitle" : "Apigee", "title" : "Apigee", "nodeType" : "Board", "ancestors" : [ { "viewHref" : "https://www.googlecloudcommunity.com/gc/Cloud-Forums/ct-p/cloud-forums", "description" : "Get answers to your questions and share your knowledge about the Google Cloud.", "id" : "cloud-forums", "shortTitle" : "Cloud Forums", "title" : "Cloud Forums", "nodeType" : "category" }, { "viewHref" : "https://www.googlecloudcommunity.com/gc/Google-Cloud/ct-p/google-cloud", "description" : "Find answers, ask questions, and connect with our community of experts.", "id" : "google-cloud", "shortTitle" : "Google Cloud", "title" : "Google Cloud", "nodeType" : "category" }, { "viewHref" : "https://www.googlecloudcommunity.com/", "description" : "The official home of Google Cloud and Workspace community forums, learning hub, and community blogs.", "id" : "qsqph94282", "shortTitle" : "Google Cloud Community", "title" : "Google Cloud Community", "nodeType" : "Community" } ] } }; LITHIUM.Components.RENDER_URL = "/gc/util/componentrenderpage/component-id/#{component-id}?render_behavior=raw"; LITHIUM.Components.ORIGINAL_PAGE_NAME = 'forums/v5/ForumTopicPage'; LITHIUM.Components.ORIGINAL_PAGE_ID = 'ForumTopicPage'; LITHIUM.Components.ORIGINAL_PAGE_CONTEXT = '7ji1wCpOIMOTIBOu2Wmi8qRlJ7u8tJHGZdh27iOyAcWICrFpy_l4nPrsskD6JcPxP7Z8uw4V2BaQJXDkZpAYEGXmtM7-wlAG9GrooHwFNh1bluPln7x_njJHVtA-oB3qrD6N3V7JOkELOzTySNs8PWWmLTWObr0XcPdZdEpFhcOWri69XcT-0LRHef-K215VtmNiq-Y_fY6LQQTJeooySk-088kXRBLRhSqdItW29Or_djrdII76H_1fTvBPdbrghGKlp6CGUzoq-ZlwuX4oQ9KKCe0qaUzVqPRYFWFM_aETN1_7B6SxcHOfkbaICVlgjmg8voNtVKjdGzm3kcO5oO4LwGSgT9Auit3T5hc2mGkKKm_N6dDGl59_rjT_QPvVJkUin_60ViY4GT2fYjPwig..'; LITHIUM.Css = { "BASE_DEFERRED_IMAGE" : "lia-deferred-image", "BASE_BUTTON" : "lia-button", "BASE_SPOILER_CONTAINER" : "lia-spoiler-container", "BASE_TABS_INACTIVE" : "lia-tabs-inactive", "BASE_TABS_ACTIVE" : "lia-tabs-active", "BASE_AJAX_REMOVE_HIGHLIGHT" : "lia-ajax-remove-highlight", "BASE_FEEDBACK_SCROLL_TO" : "lia-feedback-scroll-to", "BASE_FORM_FIELD_VALIDATING" : "lia-form-field-validating", "BASE_FORM_ERROR_TEXT" : "lia-form-error-text", "BASE_FEEDBACK_INLINE_ALERT" : "lia-panel-feedback-inline-alert", "BASE_BUTTON_OVERLAY" : "lia-button-overlay", "BASE_TABS_STANDARD" : "lia-tabs-standard", "BASE_AJAX_INDETERMINATE_LOADER_BAR" : "lia-ajax-indeterminate-loader-bar", "BASE_AJAX_SUCCESS_HIGHLIGHT" : "lia-ajax-success-highlight", "BASE_CONTENT" : "lia-content", "BASE_JS_HIDDEN" : "lia-js-hidden", "BASE_AJAX_LOADER_CONTENT_OVERLAY" : "lia-ajax-loader-content-overlay", "BASE_FORM_FIELD_SUCCESS" : "lia-form-field-success", "BASE_FORM_WARNING_TEXT" : "lia-form-warning-text", "BASE_FORM_FIELDSET_CONTENT_WRAPPER" : "lia-form-fieldset-content-wrapper", "BASE_AJAX_LOADER_OVERLAY_TYPE" : "lia-ajax-overlay-loader", "BASE_FORM_FIELD_ERROR" : "lia-form-field-error", "BASE_SPOILER_CONTENT" : "lia-spoiler-content", "BASE_FORM_SUBMITTING" : "lia-form-submitting", "BASE_EFFECT_HIGHLIGHT_START" : "lia-effect-highlight-start", "BASE_FORM_FIELD_ERROR_NO_FOCUS" : "lia-form-field-error-no-focus", "BASE_EFFECT_HIGHLIGHT_END" : "lia-effect-highlight-end", "BASE_SPOILER_LINK" : "lia-spoiler-link", "BASE_DISABLED" : "lia-link-disabled", "FACEBOOK_LOGOUT" : "lia-component-users-action-logout", "FACEBOOK_SWITCH_USER" : "lia-component-admin-action-switch-user", "BASE_FORM_FIELD_WARNING" : "lia-form-field-warning", "BASE_AJAX_LOADER_FEEDBACK" : "lia-ajax-loader-feedback", "BASE_AJAX_LOADER_OVERLAY" : "lia-ajax-loader-overlay", "BASE_LAZY_LOAD" : "lia-lazy-load" }; LITHIUM.noConflict = true; LITHIUM.useCheckOnline = false; LITHIUM.RenderedScripts = [ "jquery.lithium-selector-extensions.js", "jquery.position-toggle-1.0.js", "jquery.tokeninput-1.6.2.js", "plugin.js", "plugin.js", "plugin.js", "plugin.js", "jquery.delayToggle-1.0.js", "AjaxSupport.js", "InlineMessageReplyEditor.js", "jquery.hoverIntent-r6.js", "jquery.autocomplete.js", "en.js", "jquery.ui.resizable.js", "KeepSessionAlive.js", "en.js", "theme.js", "jquery.iframe-transport.js", "Tooltip.js", "PartialRenderProxy.js", "LazyLoadComponent.js", "ElementQueries.js", "Placeholder.js", "en.js", "en.js", "jquery.ui.mouse.js", "ForceLithiumJQuery.js", "plugin.js", "en.js", "plugin.js", "Video.js", "jquery.tmpl-1.1.1.js", "LiModernizr.js", "UserListActual.js", "plugin.js", "plugin.js", "DropDownMenuVisibilityHandler.js", "OoyalaPlayer.js", "AjaxFeedback.js", "PolyfillsAll.js", "SearchAutoCompleteToggle.js", "plugin.js", "AutoComplete.js", "en.js", "plugin.js", "DeferredImages.js", "plugin.js", "HelpIcon.js", "jquery.effects.core.js", "DropDownMenu.js", "plugin.js", "CustomEvent.js", "Auth.js", "ResizeSensor.js", "json2.js", "jquery.function-utils-1.0.js", "plugin.js", "Events.js", "jquery.appear-1.1.1.js", "aws-sdk.js", "jquery.clone-position-1.0.js", "jquery.ui.position.js", "jquery.tools.tooltip-1.2.6.js", "MessageViewDisplay.js", "jquery.json-2.6.0.js", "SearchForm.js", "plugin.js", "Components.js", "jquery.ajax-cache-response-1.0.js", "plugin.js", "EarlyEventCapture.js", "en.js", "jquery.ui.draggable.js", "jquery.lithium-toastmessage.js", "Text.js", "plugin.js", "NoConflict.js", "plugin.js", "jquery.placeholder-2.0.7.js", "plugin.js", "InputEditForm.js", "jquery.ui.widget.js", "BlockEvents.js", "Lithium.js", "FieldSet.js", "jquery.iframe-shim-1.0.js", "Dialog.js", "TinyMceEditor.js", "en.js", "TokenInputAutoComplete.js", "Namespace.js", "jquery.blockui.js", "Link.js", "Forms.js", "en.js", "jquery.ui.dialog.js", "InlineMessageReplyContainer.js", "Sandbox.js", "InformationBox.js", "Loader.js", "DataHandler.js", "CookieBannerAlert.js", "jquery.scrollTo.js", "ElementMethods.js", "ProductsField.js", "brightcove_uploader.js", "ThreadedDetailMessageList.js", "tinymce-patched.js", "ReCaptchaV3.js", "api.js", "plugin.js", "jquery.js", "plugin.js", "ActiveCast3.js", "jquery.viewport-1.0.js", "plugin.js", "jquery.ui.core.js", "prism.js", "jquery.fileupload.js", "jquery.css-data-1.0.js", "Throttle.js", "MessageEditor.js", "InlineMessageEditor.js", "jquery.effects.slide.js", "SpoilerToggle.js", "en.js", "Globals.js", "Cache.js", "plugin.js", "MessageBodyDisplay.js", "plugin.js" ];(function(){LITHIUM.AngularSupport=function(){function g(a,c){a=a||{};for(var b in c)"[object object]"===Object.prototype.toString.call(c[b])?a[b]=g(a[b],c[b]):a[b]=c[b];return a}var d,f,b={coreModule:"li.community",coreModuleDeps:[],noConflict:!0,bootstrapElementSelector:".lia-page .min-width .lia-content",bootstrapApp:!0,debugEnabled:!1,useCsp:!0,useNg2:!1},k=function(){var a;return function(b){a||(a=document.createElement("a"));a.href=b;return a.href}}();LITHIUM.Angular={};return{preventGlobals:LITHIUM.Globals.preventGlobals, restoreGlobals:LITHIUM.Globals.restoreGlobals,init:function(){var a=[],c=document.querySelector(b.bootstrapElementSelector);a.push(b.coreModule);b.customerModules&&0

Get hands-on experience with 20+ free Google Cloud products and $300 in free credit for new customers.

GenerateJWT only for JWT Tokens of Apigee

Hi,

According to the documentation found at https://cloud.google.com/apigee/docs/api-platform/reference/policies/generate-jwt-policy, I am uncertain whether the JWT token generated by Apigee is solely issued by Apigee.

In the VerifyJWT policy, it is possible to validate the JWT token from EntraID. I would like to clarify whether the GenerateJWT policy can be utilized to create a JWT token from EntraID, or if I need to employ a ServiceCallOut to generate the JWT token from EntraID.

Thanks,

Surekha

Solved Solved
0 2 42
1 ACCEPTED SOLUTION


@surekhavuchuru wrote:

I am uncertain whether the JWT token generated by Apigee is solely issued by Apigee.


I am not clear on the question you are asking. [I will suppose that, for the rest of this discussion, we are discussing a signed JWT, using asymmetric signing algorithms (RSA or ECDSA). That means a private key is used to sign, and the matching public key will be used to verify.  If this is not correct, please advise. ]

If you use the GenerateJWT policy, you are telling Apigee to generate a JWT.  Therefore the "signer" will be Apigee, using the private signing key you provide.  Will it be "issued by" Apigee?  I dunno.  That depends on your situation.  In JWT there is an "iss" claim which asserts the issuer.  You can insert whatever you like in that claim.  "iss" can be "Jesse Owens" if you want.   Does that mean Jesse Owens issued the resulting token?  I guess it depends on what you mean by "issued" and "issuer", and what meaning you impute to the "iss" claim.

A verifying party should first verify the signature, and check that the JWT is not expired. The verifier ought to also look at

  • the key that can be used to verify the signature.  Often, the key is published on a well-known JWKS endpoint.  Something like www.issuing-party.com/.well-known/JWKS.json  . If you get your public key from a URL like that, you can be certain that the organization that owns issuing-party.com "owns" the public key, and presumably the matching private key.  This check is therefore implicit:  when you verify  a JWT with that JWKS URI, you can be sure that issuing-party.com was the signer. (This  may or may not be the same as "issuer", see my comments above).
  • The issuer (iss claim), maybe.  Depends on if your app or system considers this claim to be meaningful.
  • The audience (aud claim).  To make sure the token is intended to be consumed by the verifying party. 
  • any other meaningful claims. 

 


@surekhavuchuru wrote:

In the VerifyJWT policy, it is possible to validate the JWT token from EntraID. I would like to clarify whether the GenerateJWT policy can be utilized to create a JWT token from EntraID,


Absolutely not.  Apigee cannot "generate a token from EntraID" .  Only EntraID has the private key that is used to sign JWTs from EntraID.   It is not possible for other signers to sign JWT that claim to be from EntraID.   This is the basis for trust of digital signatures in general. 

Here's an analogy: am I able to sign a mortgage document on your behalf?  Could I take out a loan, signing YOUR name to a document? No.  That's not permitted.  Well, I could sign your name, but it would be legally invalid.  Any party verifying the signature would see "this signature is not valid."   And similarly, your Apigee API proxy cannot sign a digital document that is from EntraID.   You could create a JWT with the "iss" claim pointing to some EntraID urn, but any party verifying the signature would see that it was not signed with a key owned by EntraID. 

ok, so I hope that clears things up.

But WHY Are you asking these questions? What  would be the purpose of Apigee "creating" a JWT "from Entra ID" ?  It's not possible, but why would you want that?


@surekhavuchuru wrote:

if I need to employ a ServiceCallOut to generate the JWT token from EntraID.


If you want a JWT signed by EntraID, you need to ask EntraID to provide that.  ServiceCallout is a good way to make that request.

 

View solution in original post

2 REPLIES 2


@surekhavuchuru wrote:

I am uncertain whether the JWT token generated by Apigee is solely issued by Apigee.


I am not clear on the question you are asking. [I will suppose that, for the rest of this discussion, we are discussing a signed JWT, using asymmetric signing algorithms (RSA or ECDSA). That means a private key is used to sign, and the matching public key will be used to verify.  If this is not correct, please advise. ]

If you use the GenerateJWT policy, you are telling Apigee to generate a JWT.  Therefore the "signer" will be Apigee, using the private signing key you provide.  Will it be "issued by" Apigee?  I dunno.  That depends on your situation.  In JWT there is an "iss" claim which asserts the issuer.  You can insert whatever you like in that claim.  "iss" can be "Jesse Owens" if you want.   Does that mean Jesse Owens issued the resulting token?  I guess it depends on what you mean by "issued" and "issuer", and what meaning you impute to the "iss" claim.

A verifying party should first verify the signature, and check that the JWT is not expired. The verifier ought to also look at

  • the key that can be used to verify the signature.  Often, the key is published on a well-known JWKS endpoint.  Something like www.issuing-party.com/.well-known/JWKS.json  . If you get your public key from a URL like that, you can be certain that the organization that owns issuing-party.com "owns" the public key, and presumably the matching private key.  This check is therefore implicit:  when you verify  a JWT with that JWKS URI, you can be sure that issuing-party.com was the signer. (This  may or may not be the same as "issuer", see my comments above).
  • The issuer (iss claim), maybe.  Depends on if your app or system considers this claim to be meaningful.
  • The audience (aud claim).  To make sure the token is intended to be consumed by the verifying party. 
  • any other meaningful claims. 

 


@surekhavuchuru wrote:

In the VerifyJWT policy, it is possible to validate the JWT token from EntraID. I would like to clarify whether the GenerateJWT policy can be utilized to create a JWT token from EntraID,


Absolutely not.  Apigee cannot "generate a token from EntraID" .  Only EntraID has the private key that is used to sign JWTs from EntraID.   It is not possible for other signers to sign JWT that claim to be from EntraID.   This is the basis for trust of digital signatures in general. 

Here's an analogy: am I able to sign a mortgage document on your behalf?  Could I take out a loan, signing YOUR name to a document? No.  That's not permitted.  Well, I could sign your name, but it would be legally invalid.  Any party verifying the signature would see "this signature is not valid."   And similarly, your Apigee API proxy cannot sign a digital document that is from EntraID.   You could create a JWT with the "iss" claim pointing to some EntraID urn, but any party verifying the signature would see that it was not signed with a key owned by EntraID. 

ok, so I hope that clears things up.

But WHY Are you asking these questions? What  would be the purpose of Apigee "creating" a JWT "from Entra ID" ?  It's not possible, but why would you want that?


@surekhavuchuru wrote:

if I need to employ a ServiceCallOut to generate the JWT token from EntraID.


If you want a JWT signed by EntraID, you need to ask EntraID to provide that.  ServiceCallout is a good way to make that request.

 

Hi Dino,

Thanks for answering.

But WHY Are you asking these questions? What  would be the purpose of Apigee "creating" a JWT "from Entra ID" ?  It's not possible, but why would you want that?

I wanted to verify whether GenerateJWT or ServiceCallOut could be used to generate a token from EntraID. However, the explanation you provided has clarified my concerns.

Thanks,

Surekha