%3CLINGO-SUB%20id%3D%22lingo-sub-1539553%22%20slang%3D%22en-US%22%3EUsing%20Azure%20AD%20App%20and%20Certificate%20with%20Office%20365%20CLI%20in%20Azure%20DevOps%20for%20SPFx%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-1539553%22%20slang%3D%22en-US%22%3E%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CH2%20id%3D%22toc-hId--1298906076%22%20id%3D%22toc-hId--1298906076%22%3E%3CA%20target%3D%22_blank%22%20name%3D%22_Toc44343286%22%3E%3C%2FA%3EINTRODUCTION%3C%2FH2%3E%0A%3CP%3EWhile%20using%20Azure%20DevOps%20Continuous%20Integration%20and%20Continuous%20Delivery%20(CICD)%20pipelines%2C%20most%20of%20the%20documentation%20and%20articles%20show%20how%20to%20use%20Office%20365%20Command%20Line%20Interface%20(CLI)%20to%20upload%2C%20add%20and%20deploy%20the%20SPFx%20packages.%20It%E2%80%99s%20because%20Office%20365%20CLI%20is%20a%20cross-platform%20command%20line%20tool%20and%20thus%20you%20get%20the%20benefit%20of%20using%20either%20a%20Windows%20or%20a%20Linux%20machine%20as%20your%20build%20agent.%20To%20login%20with%20Office%20365%20CLI%20using%20username%20and%20password%3A%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CPRE%20class%3D%22lia-code-sample%20language-bash%22%3E%3CCODE%3Elogin%20--authType%20password%20--userName%20user%40contoso.com%20--password%20pass%40word1%3C%2FCODE%3E%3C%2FPRE%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3EThere%20are%20ways%20to%20secure%20the%20password%20in%20Azure%20DevOps%20using%20variables%20or%20Azure%20Key%20Vault.%20However%2C%20enterprise%20organizations%20who%20are%20still%20not%20comfortable%20to%20use%20passwords%20and%20looking%20for%20other%20secure%20means%20like%20certificates.%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3EWith%20this%20blog%20post%20I%20highlight%20two%20aspects%3A%3C%2FP%3E%0A%3COL%3E%0A%3CLI%3EHow%20to%20setup%20Office%20365%20CLI%20with%20Azure%20AD%20App%20and%20Certificate%20based%20authentication%20and%3C%2FLI%3E%0A%3CLI%3EHow%20to%20login%20using%20O365%20CLI%20and%20certificates%20in%20Azure%20DevOps%20YAML%20pipelines%3C%2FLI%3E%0A%3C%2FOL%3E%0A%3CP%3EYou%20can%20find%20the%20-ERR%3AREF-NOT-FOUND-documentation%20on%20how%20to%20use%20certificate%20to%20login%20using%20Office%20365%20CLI.%20This%20article%20goes%20into%20detailed%20steps%20complementing%20the%20documentation.%20I%20will%20also%20touch%20upon%20some%20issues%20that%20I%20faced%20while%20setting%20this%20up.%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3ENote%3A%20Another%20advantage%20that%20you%20get%20from%20following%20these%20steps%20will%20be%20the%20ability%20to%20define%20fine%20grained%20permissions%20limited%20for%20the%20required%20for%20use%20case%20(Example%3A%20deploy%20to%20SPO%20app%20catalog).%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CH2%20id%3D%22toc-hId-1188606757%22%20id%3D%22toc-hId-1188606757%22%3E%3CA%20target%3D%22_blank%22%20name%3D%22_Toc44343287%22%3E%3C%2FA%3ECERTIFICATE%20GENERATION%3C%2FH2%3E%0A%3COL%3E%0A%3CLI%3ECreate%20self-signed%20certificate%20of%20type%20Personal%20Information%20Exchange%20(PFX)%20or%20Privacy%20Enhanced%20Mail%20(PEM)%3C%2FLI%3E%0A%3CLI%3EFor%20windows%2C%20install%20openssl%20client.%20I%20used%3A%20-ERR%3AREF-NOT-FOUND-%3CA%20href%3D%22http%3A%2F%2Fslproweb.com%2Fproducts%2FWin32OpenSSL.html%22%20target%3D%22_blank%22%20rel%3D%22nofollow%20noopener%20noreferrer%22%3Ehttp%3A%2F%2Fslproweb.com%2Fproducts%2FWin32OpenSSL.html%3C%2FA%3E%3C%2FLI%3E%0A%3C%2FOL%3E%0A%3CP%20class%3D%22lia-indent-padding-left-60px%22%3EInstructions%20are%20assuming%20openssl%20client%20is%20extracted%20to%20%3CSTRONG%3Ec%3A%5COpenSSL%3C%2FSTRONG%3E%20folder.%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%20class%3D%22lia-indent-padding-left-30px%22%3ENOTE%3A%20After%20trying%20couple%20of%20openssl%20clients%2C%20I%20had%20success%20with%20this%20ssl%20client.%20I%20hope%20that%20saves%20some%20time%20for%20you%20in%20researching%20which%20client%20works.%20If%20you%20WSL%20enabled%2Fconfigured%2C%20then%20this%20is%20a%20non-issue.%3C%2FP%3E%0A%3CP%20class%3D%22lia-indent-padding-left-30px%22%3E%26nbsp%3B%3C%2FP%3E%0A%3COL%20start%3D%223%22%3E%0A%3CLI%3ENavigate%20to%20the%20OpenSSL%20bin%20directory.%0A%3COL%20class%3D%22lia-list-style-type-lower-alpha%22%3E%0A%3CLI%3Ec%3A%5COpenSSL%5Cbin%5C%20in%20our%20example.%3C%2FLI%3E%0A%3C%2FOL%3E%0A%3C%2FLI%3E%0A%3CLI%3ERight-click%20the%20openssl.exe%20file%20and%20select%20Run%20as%20administrator.%3C%2FLI%3E%0A%3CLI%3EEnter%20the%20following%20command%20to%20begin%20generating%20a%20certificate%20and%20private%20key%3C%2FLI%3E%0A%3C%2FOL%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CPRE%20class%3D%22lia-code-sample%20language-bash%22%3E%3CCODE%3Ereq%20-x509%20-sha256%20-nodes%20-days%20365%20-newkey%20rsa%3A2048%20-keyout%20privateKey.key%20-out%20certificate.cer%3C%2FCODE%3E%3C%2FPRE%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3COL%20start%3D%227%22%3E%0A%3CLI%3EYou%20will%20then%20be%20prompted%20to%20enter%20applicable%20Distinguished%20Name%20(DN)%20information%2C%20totaling%20seven%20fields%3A%3C%2FLI%3E%0A%3C%2FOL%3E%0A%3CP%20class%3D%22lia-indent-padding-left-30px%22%3E%3CSPAN%20class%3D%22lia-inline-image-display-wrapper%20lia-image-align-inline%22%20image-alt%3D%22openssl-dn.png%22%20style%3D%22width%3A%20999px%3B%22%3E%3CIMG%20src%3D%22https%3A%2F%2Fgxcuf89792.i.lithium.com%2Ft5%2Fimage%2Fserverpage%2Fimage-id%2F207674iAFA69F23CC49CA53%2Fimage-size%2Flarge%3Fv%3D1.0%26amp%3Bpx%3D999%22%20title%3D%22openssl-dn.png%22%20alt%3D%22openssl-dn.png%22%20%2F%3E%3C%2FSPAN%3E%3C%2FP%3E%0A%3COL%20start%3D%227%22%3E%0A%3CLI%3EOnce%20completed%2C%20you%20will%20find%20the%20certificate.crt%20and%20privateKey.key%20files%20created%20under%20the%20%5COpenSSL%5Cbin%5C%20directory.%3C%2FLI%3E%0A%3CLI%3ECreate%20a%20new%20Personal%20Information%20Exchange%20(.PFX)%20file%20using%20the%20certificate%20and%20private%20key%20as%20inputs%20from%20above%20step.%3C%2FLI%3E%0A%3C%2FOL%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CPRE%20class%3D%22lia-code-sample%20language-bash%22%3E%3CCODE%3Epkcs12%20-export%20-out%20protected.pfx%20-inkey%20privateKey.key%20-in%20certificate.cer%20-password%20pass%3Apass%40word1%3C%2FCODE%3E%3C%2FPRE%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%20class%3D%22lia-indent-padding-left-30px%22%3ENOTE%3A%20I%E2%80%99d%20would%20like%20to%20highlight%20and%20note%20that%20I%20spent%20many%20hours%20troubleshooting%20an%20issue%20related%20to%20this%20command.%20If%20you%20use%20double%20quotes%20for%20the%20password%20string%20as%20-ERR%3AREF-NOT-FOUND-documented%20(Example%3A%20%3CEM%3Eopenssl%20pkcs12%20-export%20-out%20protected.pfx%20-inkey%20privateKey.key%20-in%20certificate.cer%20-password%20pass%3A%22pass%40word1%22%3C%2FEM%3E%20)%2C%20the%20quotes%20are%20also%20considered%20to%20be%20part%20of%20the%20password.%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3COL%20start%3D%229%22%3E%0A%3CLI%3EAt%20this%20point%20the%20protected.pfx%20file%20can%20be%20used%20to%20log%20in%20the%20Office%20365%20CLI.%20We%20will%20come%20back%20to%20this%20step%20later.%3C%2FLI%3E%0A%3C%2FOL%3E%0A%3CP%3EArtifacts%20from%20this%20section%3A%3C%2FP%3E%0A%3COL%20class%3D%22lia-list-style-type-lower-alpha%22%3E%0A%3CLI%3ECertificate.cer%3C%2FLI%3E%0A%3CLI%3EprivateKey.key%3C%2FLI%3E%0A%3CLI%3Eprotected.pfx%3C%2FLI%3E%0A%3C%2FOL%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CH2%20id%3D%22toc-hId--618847706%22%20id%3D%22toc-hId--618847706%22%3E%3CA%20target%3D%22_blank%22%20name%3D%22_Toc44343288%22%3E%3C%2FA%3EAZURE%20AD%20APPLICATION%20REGISTRATION%3C%2FH2%3E%0A%3COL%3E%0A%3CLI%3ECreating%20AAD%20app%20is%20well%20documented%20in%20many%20articles%2C%20so%20I%20sparsely%20documented%20it%20here.%20Also%2C%20please%20check%20out%20-ERR%3AREF-NOT-FOUND-Garry%20Tinder%E2%80%99s%20post%20which%20goes%20into%20details%20on%20how%20to%20create%20AAD%20app%20to%20log%20in%20using%20Office%20365%20CLI.%3C%2FLI%3E%0A%3CLI%3ECreate%20new%20Azure%20AD%20App%20with%20a%20valid%20name.%20Leave%20all%20other%20fields%2Foptions%20as-is.%3C%2FLI%3E%0A%3C%2FOL%3E%0A%3CP%20class%3D%22lia-indent-padding-left-30px%22%3E%3CSPAN%20class%3D%22lia-inline-image-display-wrapper%20lia-image-align-inline%22%20image-alt%3D%22image003.png%22%20style%3D%22width%3A%20501px%3B%22%3E%3CIMG%20src%3D%22https%3A%2F%2Fgxcuf89792.i.lithium.com%2Ft5%2Fimage%2Fserverpage%2Fimage-id%2F207289i883EAB92B1D4433D%2Fimage-size%2Flarge%3Fv%3D1.0%26amp%3Bpx%3D999%22%20title%3D%22image003.png%22%20alt%3D%22image003.png%22%20%2F%3E%3C%2FSPAN%3E%3C%2FP%3E%0A%3COL%20start%3D%223%22%3E%0A%3CLI%3ESave%20the%20app%20id%20and%20tenant%20id.%3C%2FLI%3E%0A%3C%2FOL%3E%0A%3CP%20class%3D%22lia-indent-padding-left-30px%22%3E%3CSPAN%20class%3D%22lia-inline-image-display-wrapper%20lia-image-align-inline%22%20image-alt%3D%22image004.png%22%20style%3D%22width%3A%20512px%3B%22%3E%3CIMG%20src%3D%22https%3A%2F%2Fgxcuf89792.i.lithium.com%2Ft5%2Fimage%2Fserverpage%2Fimage-id%2F207290i4EA0B29711FEBE0E%2Fimage-size%2Flarge%3Fv%3D1.0%26amp%3Bpx%3D999%22%20title%3D%22image004.png%22%20alt%3D%22image004.png%22%20%2F%3E%3C%2FSPAN%3E%3C%2FP%3E%0A%3COL%20start%3D%224%22%3E%0A%3CLI%3EGive%20below%20%E2%80%9Capplication%E2%80%9D%20permissions%20to%20the%20app%3C%2FLI%3E%0A%3C%2FOL%3E%0A%3CP%20class%3D%22lia-indent-padding-left-30px%22%3E%3CSPAN%20class%3D%22lia-inline-image-display-wrapper%20lia-image-align-inline%22%20image-alt%3D%22image005.png%22%20style%3D%22width%3A%20610px%3B%22%3E%3CIMG%20src%3D%22https%3A%2F%2Fgxcuf89792.i.lithium.com%2Ft5%2Fimage%2Fserverpage%2Fimage-id%2F207291iE7F69BB6ED7FF120%2Fimage-size%2Flarge%3Fv%3D1.0%26amp%3Bpx%3D999%22%20title%3D%22image005.png%22%20alt%3D%22image005.png%22%20%2F%3E%3C%2FSPAN%3E%3C%2FP%3E%0A%3CP%20class%3D%22lia-indent-padding-left-30px%22%3ENOTE%3A%20Microsoft%20Graph%20permission%20is%20not%20a%20prerequisite.%20Ignore%20it.%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3COL%20start%3D%225%22%3E%0A%3CLI%3EMake%20sure%20the%20Admin%20Consent%20is%20provided%20for%20all%20the%20permissions.%3C%2FLI%3E%0A%3CLI%3EGo%20to%20%E2%80%9CCertificates%20%26amp%3B%20Secrets%E2%80%9D%20and%20choose%20%E2%80%9CUpload%20certificate%E2%80%9D%20to%20upload%20the%20certificate.cer%20file%20created%20in%20step%207%20in%20first%20section.%3C%2FLI%3E%0A%3C%2FOL%3E%0A%3CP%20class%3D%22lia-indent-padding-left-30px%22%3E%3CSPAN%20class%3D%22lia-inline-image-display-wrapper%20lia-image-align-inline%22%20image-alt%3D%22image006.png%22%20style%3D%22width%3A%20886px%3B%22%3E%3CIMG%20src%3D%22https%3A%2F%2Fgxcuf89792.i.lithium.com%2Ft5%2Fimage%2Fserverpage%2Fimage-id%2F207292iDB167DAA0AA6EBBA%2Fimage-size%2Flarge%3Fv%3D1.0%26amp%3Bpx%3D999%22%20title%3D%22image006.png%22%20alt%3D%22image006.png%22%20%2F%3E%3C%2FSPAN%3E%3C%2FP%3E%0A%3CP%20class%3D%22lia-indent-padding-left-30px%22%3ENOTE%3A%20Instead%20of%20upload%20certificate%2C%20it%E2%80%99s%20also%20possible%20to%20manually%20update%20the%20manifest%20file.%3C%2FP%3E%0A%3CP%20class%3D%22lia-indent-padding-left-30px%22%3E%26nbsp%3B%3C%2FP%3E%0A%3COL%20start%3D%227%22%3E%0A%3CLI%3ESave%20the%20thumbprint%20to%20use%20later.%3C%2FLI%3E%0A%3C%2FOL%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3EArtifacts%20from%20this%20section%3A%3C%2FP%3E%0A%3COL%20class%3D%22lia-list-style-type-lower-alpha%22%3E%0A%3CLI%3EApp%20Id%3C%2FLI%3E%0A%3CLI%3ETenant%20ID%3C%2FLI%3E%0A%3CLI%3EThumbprint%3C%2FLI%3E%0A%3C%2FOL%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CH2%20id%3D%22toc-hId-1868665127%22%20id%3D%22toc-hId-1868665127%22%3E%3CA%20target%3D%22_blank%22%20name%3D%22_Toc44343289%22%3E%3C%2FA%3ETEST%20LOCALLY%3C%2FH2%3E%0A%3COL%3E%0A%3CLI%3EBefore%20we%20can%20use%20these%20artifacts%20in%20Azure%20DevOps%20pipeline%2C%20lets%20test%20locally%20to%20ensure%20the%20certificate%20is%20usable%20with%20Office%20365%20CLI%20login.%20We%20need%20to%20make%20the%20AAD%20App%20ID%20and%20the%20Tenant%20ID%20available%20to%20Office%20365%20CLI%20using%20environment%20variables.%20If%20you%20are%20looking%20to%20script%20this%20or%20looking%20for%20steps%20to%20do%20in%20other%20operating%20systems%2C%20I%E2%80%99d%20refer%20to%20Garry%26nbsp%3B%20Tinder%E2%80%99s%20-ERR%3AREF-NOT-FOUND-blog%20post.%3C%2FLI%3E%0A%3CLI%3EAdd%20below%20environment%20variables%20on%20your%20PC.%0A%3COL%20class%3D%22lia-list-style-type-lower-alpha%22%3E%0A%3CLI%3EOFFICE365CLI_AADAPPID%20%3D%20App%20Id%3C%2FLI%3E%0A%3CLI%3EOFFICE365CLI_TENANT%20%3D%20Tenant%20ID%3C%2FLI%3E%0A%3C%2FOL%3E%0A%3C%2FLI%3E%0A%3C%2FOL%3E%0A%3CP%20class%3D%22lia-indent-padding-left-60px%22%3E%3CSPAN%20class%3D%22lia-inline-image-display-wrapper%20lia-image-align-inline%22%20image-alt%3D%22image007.png%22%20style%3D%22width%3A%20999px%3B%22%3E%3CIMG%20src%3D%22https%3A%2F%2Fgxcuf89792.i.lithium.com%2Ft5%2Fimage%2Fserverpage%2Fimage-id%2F207293i0223D19775ADE4DE%2Fimage-size%2Flarge%3Fv%3D1.0%26amp%3Bpx%3D999%22%20title%3D%22image007.png%22%20alt%3D%22image007.png%22%20%2F%3E%3C%2FSPAN%3E%3C%2FP%3E%0A%3CP%20class%3D%22lia-indent-padding-left-60px%22%3E%26nbsp%3B%3C%2FP%3E%0A%3COL%20start%3D%223%22%3E%0A%3CLI%3ETest%20your%20certificate%20by%20trying%20to%20login%20using%20O365%20CLI%20in%20terminal%20window%20(PS%20or%20Command%20Win)%3C%2FLI%3E%0A%3C%2FOL%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CPRE%20class%3D%22lia-code-sample%20language-bash%22%3E%3CCODE%3Elogin%20--authType%20certificate%20--certificateFile%20C%3A%5COpenSSL-Win64%5Cbin%5Cprotected.pfx%20--thumbprint%205D500FE3BTRUNCATED563173009BC%20--password%20pass%40word1%3C%2FCODE%3E%3C%2FPRE%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%20class%3D%22lia-indent-padding-left-30px%22%3ENote%3A%20Change%20the%20certificateFile%2C%20thumbprint%2C%20password%20as%20per%20your%20environment%3C%2FP%3E%0A%3CP%20class%3D%22lia-indent-padding-left-30px%22%3E%26nbsp%3B%3C%2FP%3E%0A%3COL%20start%3D%224%22%3E%0A%3CLI%3ERun%20some%20sample%20commands.%20Example%3A%0A%3COL%20class%3D%22lia-list-style-type-lower-alpha%22%3E%0A%3CLI%3EStatus%3C%2FLI%3E%0A%3CLI%3ESpo%20app%20list%3C%2FLI%3E%0A%3C%2FOL%3E%0A%3C%2FLI%3E%0A%3C%2FOL%3E%0A%3CP%20class%3D%22lia-indent-padding-left-60px%22%3E%3CSPAN%20class%3D%22lia-inline-image-display-wrapper%20lia-image-align-inline%22%20image-alt%3D%22image008.png%22%20style%3D%22width%3A%20999px%3B%22%3E%3CIMG%20src%3D%22https%3A%2F%2Fgxcuf89792.i.lithium.com%2Ft5%2Fimage%2Fserverpage%2Fimage-id%2F207294i8FA3393033D98A2A%2Fimage-size%2Flarge%3Fv%3D1.0%26amp%3Bpx%3D999%22%20title%3D%22image008.png%22%20alt%3D%22image008.png%22%20%2F%3E%3C%2FSPAN%3E%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CH2%20id%3D%22toc-hId-61210664%22%20id%3D%22toc-hId-61210664%22%3E%3CA%20target%3D%22_blank%22%20name%3D%22_Toc44343290%22%3E%3C%2FA%3EUSE%20CERTIFICATE%20IN%20AZURE%20DEVOPS%20PIPELINE%3C%2FH2%3E%0A%3COL%3E%0A%3CLI%3EIn%20this%20section%2C%20we%20will%20configure%20Azure%20DevOps%20repository%20so%20that%20the%20pipelines%20can%20use%20the%20certificate%20when%20logging%20with%20Office%20365%20CLI.%20Here%20is%20a%20-ERR%3AREF-NOT-FOUND-demo%20repository%20on%20GitHub%20that%20contains%20two%20files%3A%0A%3COL%20class%3D%22lia-list-style-type-lower-alpha%22%3E%0A%3CLI%3ESPFX%20Package%20file%20(sppkg%20file)%0A%3COL%20class%3D%22lia-list-style-type-lower-roman%22%3E%0A%3CLI%3EThis%20is%20a%20sample%20SPFx%20application%20customizer%20extension%20that%20adds%20Azure%20Application%20Insights%20to%20SPO%20sites.%20Note%3A%20It%20can%20be%20any%20other%20SPFx%20package%20file.%3C%2FLI%3E%0A%3C%2FOL%3E%0A%3C%2FLI%3E%0A%3CLI%3EAzure-pipelines.yml%0A%3COL%20class%3D%22lia-list-style-type-lower-roman%22%3E%0A%3CLI%3EYAML%20pipeline%20that%20uses%20the%20certificate%20to%20login%20using%20Office%20365%20CLI.%20This%20pipeline%20takes%20the%20SPFx%20package%2C%20uploads%2C%20deploys%20to%20SharePoint%20Online%20App%20Catalog%20site.%3C%2FLI%3E%0A%3C%2FOL%3E%0A%3C%2FLI%3E%0A%3C%2FOL%3E%0A%3C%2FLI%3E%0A%3CLI%3EFirst%2C%20we%20need%20to%20upload%20the%20certificate%20to%20the%20repository.%20Open%20your%20Azure%20DevOps%20(ADO)%20project.%20Go%20to%20Pipelines%20%26gt%3B%20Library%20page.%3C%2FLI%3E%0A%3CLI%3ESelect%20%E2%80%9C%3CSTRONG%3ESecure%20files%3C%2FSTRONG%3E%E2%80%9D%20tab.%20Use%20the%20%3CSTRONG%3E%2B%20Secure%20file%3C%2FSTRONG%3E%20button%20to%20upload%20the%20pfx%20file.%3C%2FLI%3E%0A%3C%2FOL%3E%0A%3CP%20class%3D%22lia-indent-padding-left-30px%22%3E%3CSPAN%20class%3D%22lia-inline-image-display-wrapper%20lia-image-align-inline%22%20image-alt%3D%22image009.png%22%20style%3D%22width%3A%20656px%3B%22%3E%3CIMG%20src%3D%22https%3A%2F%2Fgxcuf89792.i.lithium.com%2Ft5%2Fimage%2Fserverpage%2Fimage-id%2F207295i6D09D8CE6A7EEAF6%2Fimage-dimensions%2F656x417%3Fv%3D1.0%22%20width%3D%22656%22%20height%3D%22417%22%20title%3D%22image009.png%22%20alt%3D%22image009.png%22%20%2F%3E%3C%2FSPAN%3E%3C%2FP%3E%0A%3COL%20start%3D%224%22%3E%0A%3CLI%3EBelow%20you%20can%20see%20the%20sample%20entries%20(script%20tasks)%20that%20you%20can%20use%20in%20your%20YAML%20pipelines%20to%20access%20the%20certificate%20from%20the%20secure%20files%20store.%3C%2FLI%3E%0A%3C%2FOL%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CPRE%20class%3D%22lia-code-sample%20language-yaml%22%3E%3CCODE%3E-%26nbsp%3Bscript%3A%26nbsp%3Becho%26nbsp%3BBuilding!%0A%0A%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B-%26nbsp%3Btask%3A%26nbsp%3BDownloadSecureFile%401%0A%0A%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3Bname%3A%26nbsp%3BcaCertificate%0A%0A%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3BdisplayName%3A%26nbsp%3B'Download%26nbsp%3BCA%26nbsp%3Bcertificate'%0A%0A%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3Binputs%3A%0A%0A%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3BsecureFile%3A%26nbsp%3B'protected.pfx'%0A%0A%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B-%26nbsp%3Bscript%3A%26nbsp%3B%7C%0A%0A%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3Becho%26nbsp%3BFound%26nbsp%3Bcert%26nbsp%3Bat%26nbsp%3B%24(caCertificate.secureFilePath)%26nbsp%3B%0A%0A%26nbsp%3B%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%0A%0A%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%23%23%26nbsp%3Blogin%26nbsp%3Bto%26nbsp%3BOffice%26nbsp%3B365%26nbsp%3BCLI%0A%0A%26nbsp%3B%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%0A%0A%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B-%26nbsp%3Bscript%3A%26nbsp%3Bo365%26nbsp%3Blogin%26nbsp%3B%24(o365_app_catalog_site_url)%26nbsp%3B--authType%26nbsp%3Bcertificate%26nbsp%3B--certificateFile%26nbsp%3B%24(caCertificate.secureFilePath)%26nbsp%3B--thumbprint%26nbsp%3B%24(cert_thumbprint)%26nbsp%3B--password%26nbsp%3Bpass%40word1%0A%0A%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3BdisplayName%3A%26nbsp%3BLogin%26nbsp%3Bto%26nbsp%3BOffice365%3C%2FCODE%3E%3C%2FPRE%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3COL%20start%3D%225%22%3E%0A%3CLI%3EWhen%20the%20pipeline%20executes%20the%20first%20time%2C%20you%20will%20see%20a%20prompt%20to%20approve%20the%20usage%20of%20the%20certificate.%20See%20below%20screenshot%3A%3C%2FLI%3E%0A%3C%2FOL%3E%0A%3CP%20class%3D%22lia-indent-padding-left-30px%22%3E%3CSPAN%20class%3D%22lia-inline-image-display-wrapper%20lia-image-align-inline%22%20image-alt%3D%22image010.png%22%20style%3D%22width%3A%20999px%3B%22%3E%3CIMG%20src%3D%22https%3A%2F%2Fgxcuf89792.i.lithium.com%2Ft5%2Fimage%2Fserverpage%2Fimage-id%2F207297iD0DEF892506CF882%2Fimage-size%2Flarge%3Fv%3D1.0%26amp%3Bpx%3D999%22%20title%3D%22image010.png%22%20alt%3D%22image010.png%22%20%2F%3E%3C%2FSPAN%3E%3C%2FP%3E%0A%3CP%20class%3D%22lia-indent-padding-left-30px%22%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%20class%3D%22lia-indent-padding-left-30px%22%3E%3CSPAN%20class%3D%22lia-inline-image-display-wrapper%20lia-image-align-inline%22%20image-alt%3D%22image011.png%22%20style%3D%22width%3A%20464px%3B%22%3E%3CIMG%20src%3D%22https%3A%2F%2Fgxcuf89792.i.lithium.com%2Ft5%2Fimage%2Fserverpage%2Fimage-id%2F207296i4FC3008D7C58D74F%2Fimage-size%2Flarge%3Fv%3D1.0%26amp%3Bpx%3D999%22%20title%3D%22image011.png%22%20alt%3D%22image011.png%22%20%2F%3E%3C%2FSPAN%3E%3C%2FP%3E%0A%3CP%20class%3D%22lia-indent-padding-left-30px%22%3E%26nbsp%3B%3C%2FP%3E%0A%3CH2%20id%3D%22toc-hId--1746243799%22%20id%3D%22toc-hId--1746243799%22%3E%3CA%20target%3D%22_blank%22%20name%3D%22_Toc44343291%22%3E%3C%2FA%3ESAMPLE%20PIPELINE%3C%2FH2%3E%0A%3CP%3EBelow%20you%20can%20see%20the%20Azure%20pipeline%20in%20full.%20You%20can%20access%20this%20pipeline%20on%20GitHub%20-ERR%3AREF-NOT-FOUND-here.%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CPRE%20class%3D%22lia-code-sample%20language-yaml%22%3E%3CCODE%3Etrigger%3A%0A%20%20branches%3A%0A%20%20%20%20include%3A%0A%20%20%20%20%20%20-%20'*'%0A%0Avariables%3A%0A%20%20OFFICE365CLI_AADAPPID%3A%20'80fdc955-8677-4251-8d49-050d02071c15'%0A%20%20OFFICE365CLI_TENANT%3A%20'216e190d-67e4-4a6e-98bd-15b8468e5928'%0A%20%20o365_app_catalog_site_url%3A%20'https%3A%2F%2FYOURTENANT.sharepoint.com%2Fsites%2FAPPCATALOGSITENAME'%0A%20%20o365cli_app_catalog_scope%3A%20'tenant'%0A%20%20node_version%3A%20'10.x'%0A%20%20cert_thumbprint%3A%20'5D500FE3B7543FCC61D4DCFD0C164563173009BC'%0A%20%20spfx-pkg%3A%20'azure-app-insights.sppkg'%0A%0Apool%3A%0A%20%20vmImage%3A%20ubuntu-latest%0A%0Astages%3A%0A-%20stage%3A%20Build%0A%20%20jobs%3A%0A%20%20-%20job%3A%20BuildJob%0A%20%20%20%20steps%3A%0A%20%20%20%20-%20script%3A%20echo%20Building!%0A%20%20%20%20-%20task%3A%20DownloadSecureFile%401%0A%20%20%20%20%20%20name%3A%20caCertificate%0A%20%20%20%20%20%20displayName%3A%20'Download%20CA%20certificate'%0A%20%20%20%20%20%20inputs%3A%0A%20%20%20%20%20%20%20%20secureFile%3A%20'protected.pfx'%0A%20%20%20%20-%20script%3A%20%7C%0A%20%20%20%20%20%20%20%20echo%20Found%20cert%20at%20%24(caCertificate.secureFilePath)%20%0A%20%20%20%20%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%0A%20%20%20%20%23%23%20specify%20which%20node%20version%20to%20use%0A%20%20%20%20%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%0A%20%20%20%20-%20task%3A%20UseNode%401%0A%20%20%20%20%20%20displayName%3A%20Set%20to%20Node.js%20%24(node_version)%0A%20%20%20%20%20%20inputs%3A%0A%20%20%20%20%20%20%20%20version%3A%20%24(node_version)%0A%20%20%20%20%20%20condition%3A%20ne('%24(node_version)'%2C%20'')%0A%0A%20%20%20%20%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%0A%20%20%20%20%23%23%20install%20Office%20365%20CLI%0A%20%20%20%20%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%0A%20%20%20%20-%20script%3A%20sudo%20npm%20install%20--global%20%40pnp%2Foffice365-cli%0A%20%20%20%20%20%20displayName%3A%20Install%20Office365%20CLI%0A%0A%20%20%20%20%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%0A%20%20%20%20%23%23%20login%20to%20Office%20365%20CLI%0A%20%20%20%20%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%0A%20%20%20%20-%20script%3A%20o365%20login%20%24(o365_app_catalog_site_url)%20--authType%20certificate%20--certificateFile%20%24(caCertificate.secureFilePath)%20--thumbprint%20%24(cert_thumbprint)%20--password%20pass%40word1%0A%20%20%20%20%20%20displayName%3A%20Login%20to%20Office365%0A%0A%20%20%20%20%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%0A%20%20%20%20%23%23%20upload%20*.sppkg%20to%20the%20target%20app%20catalog%0A%20%20%20%20%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%0A%20%20%20%20-%20script%3A%20o365%20spo%20app%20add%20--filePath%20%24(spfx_pkg)%20--appCatalogUrl%20%24(o365_app_catalog_site_url)%20--scope%20tenant%20--overwrite%0A%20%20%20%20%20%20displayName%3A%20Upload%20SharePoint%20package%20to%20Site%20Collection%20App%20Catalog%0A%0A%20%20%20%20%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%0A%20%20%20%20%23%23deploy%20the%20package%0A%20%20%20%20%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%0A%20%20%20%20-%20script%3A%20o365%20spo%20app%20deploy%20--name%20%24(spfx_pkg)%20--appCatalogUrl%20%24(o365_app_catalog_site_url)%20--scope%20tenant%0A%20%20%20%20%20%20displayName%3A%20Deploy%20SharePoint%20package%20%20%20%20%20%20%3C%2FCODE%3E%3C%2FPRE%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3EThanks%20for%20reading.%20I%20hope%20this%20helps%20you%20out.%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%3CSTRONG%3E%3CSTRONG%3E%3CFONT%20size%3D%221%202%203%204%205%206%207%22%3EDisclaimer%3C%2FFONT%3E%3C%2FSTRONG%3E%3CBR%20%2F%3E%3CFONT%20size%3D%221%202%203%204%205%206%207%22%3E%3C%2FFONT%3E%3C%2FSTRONG%3E%3CFONT%3E%3CBR%20%2F%3E%3CFONT%20size%3D%222%22%3EThe%20sample%20scripts%20are%20not%20supported%20under%20any%20Microsoft%20standard%20support%20program%20or%20service.%20The%20sample%20scripts%20are%20provided%20AS%20IS%20without%20warranty%20of%20any%20kind.%20Microsoft%20further%20disclaims%20all%20implied%20warranties%20including%2C%20without%20limitation%2C%20any%20implied%20warranties%20of%20merchantability%20or%20of%20fitness%20for%20a%20particular%20purpose.%20The%20entire%20risk%20arising%20out%20of%20the%20use%20or%20performance%20of%20the%20sample%20scripts%20and%20documentation%20remains%20with%20you.%20In%20no%20event%20shall%20Microsoft%2C%20its%20authors%2C%20or%20anyone%20else%20involved%20in%20the%20creation%2C%20production%2C%20or%20delivery%20of%20the%20scripts%20be%20liable%20for%20any%20damages%20whatsoever%20(including%2C%20without%20limitation%2C%20damages%20for%20loss%20of%20business%20profits%2C%20business%20interruption%2C%20loss%20of%20business%20information%2C%20or%20other%20pecuniary%20loss)%20arising%20out%20of%20the%20use%20of%20or%20inability%20to%20use%20the%20sample%20scripts%20or%20documentation%2C%20even%20if%20Microsoft%20has%20been%20advised%20of%20the%20possibility%20of%20such%20damages.%3C%2FFONT%3E%3C%2FFONT%3E%3C%2FP%3E%3C%2FLINGO-BODY%3E%3CLINGO-TEASER%20id%3D%22lingo-teaser-1539553%22%20slang%3D%22en-US%22%3E%3CDIV%3E%0A%3CDIV%3E%3CSPAN%3EHighlighting%202%20areas%3A%26nbsp%3B%3C%2FSPAN%3E%3CSPAN%3ESetup%20O365%26nbsp%3BCLI%26nbsp%3Bwith%26nbsp%3BAzure%26nbsp%3BAD%26nbsp%3BApp%26nbsp%3Band%26nbsp%3BCertificate%26nbsp%3Bbased%26nbsp%3BauthN%26nbsp%3Band%26nbsp%3B%3C%2FSPAN%3E%3CSPAN%3Euse%20it%20in%26nbsp%3BAzure%26nbsp%3BDevOps%20pipelines%3C%2FSPAN%3E%3C%2FDIV%3E%0A%3CDIV%3E%3CSPAN%3E%3CSPAN%20class%3D%22lia-inline-image-display-wrapper%20lia-image-align-inline%22%20image-alt%3D%22image001.png%22%20style%3D%22width%3A%20999px%3B%22%3E%3CIMG%20src%3D%22https%3A%2F%2Fgxcuf89792.i.lithium.com%2Ft5%2Fimage%2Fserverpage%2Fimage-id%2F207276iAA2062956822D37E%2Fimage-size%2Flarge%3Fv%3D1.0%26amp%3Bpx%3D999%22%20title%3D%22image001.png%22%20alt%3D%22image001.png%22%20%2F%3E%3C%2FSPAN%3E%3C%2FSPAN%3E%3C%2FDIV%3E%0A%3C%2FDIV%3E%3C%2FLINGO-TEASER%3E%3CLINGO-LABS%20id%3D%22lingo-labs-1539553%22%20slang%3D%22en-US%22%3E%3CLINGO-LABEL%3ESrinivasVarukala%3C%2FLINGO-LABEL%3E%3C%2FLINGO-LABS%3E

 

INTRODUCTION

While using Azure DevOps Continuous Integration and Continuous Delivery (CICD) pipelines, most of the documentation and articles show how to use Office 365 Command Line Interface (CLI) to upload, add and deploy the SPFx packages. It’s because Office 365 CLI is a cross-platform command line tool and thus you get the benefit of using either a Windows or a Linux machine as your build agent. To login with Office 365 CLI using username and password:

 

login --authType password --userName user@contoso.com --password pass@word1

 

There are ways to secure the password in Azure DevOps using variables or Azure Key Vault. However, enterprise organizations who are still not comfortable to use passwords and looking for other secure means like certificates.

 

With this blog post I highlight two aspects:

  1. How to setup Office 365 CLI with Azure AD App and Certificate based authentication and
  2. How to login using O365 CLI and certificates in Azure DevOps YAML pipelines

You can find the documentation on how to use certificate to login using Office 365 CLI. This article goes into detailed steps complementing the documentation. I will also touch upon some issues that I faced while setting this up.

 

Note: Another advantage that you get from following these steps will be the ability to define fine grained permissions limited for the required for use case (Example: deploy to SPO app catalog).

 

CERTIFICATE GENERATION

  1. Create self-signed certificate of type Personal Information Exchange (PFX) or Privacy Enhanced Mail (PEM)
  2. For windows, install openssl client. I used: http://slproweb.com/products/Win32OpenSSL.html

Instructions are assuming openssl client is extracted to c:\OpenSSL folder.

 

NOTE: After trying couple of openssl clients, I had success with this ssl client. I hope that saves some time for you in researching which client works. If you WSL enabled/configured, then this is a non-issue.

 

  1. Navigate to the OpenSSL bin directory.
    1. c:\OpenSSL\bin\ in our example.
  2. Right-click the openssl.exe file and select Run as administrator.
  3. Enter the following command to begin generating a certificate and private key

 

req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout privateKey.key -out certificate.cer

 

 

  1. You will then be prompted to enter applicable Distinguished Name (DN) information, totaling seven fields:

openssl-dn.png

  1. Once completed, you will find the certificate.crt and privateKey.key files created under the \OpenSSL\bin\ directory.
  2. Create a new Personal Information Exchange (.PFX) file using the certificate and private key as inputs from above step.

 

pkcs12 -export -out protected.pfx -inkey privateKey.key -in certificate.cer -password pass:pass@word1

 

NOTE: I’d would like to highlight and note that I spent many hours troubleshooting an issue related to this command. If you use double quotes for the password string as documented (Example: openssl pkcs12 -export -out protected.pfx -inkey privateKey.key -in certificate.cer -password pass:"pass@word1" ), the quotes are also considered to be part of the password.

 

  1. At this point the protected.pfx file can be used to log in the Office 365 CLI. We will come back to this step later.

Artifacts from this section:

  1. Certificate.cer
  2. privateKey.key
  3. protected.pfx

 

AZURE AD APPLICATION REGISTRATION

  1. Creating AAD app is well documented in many articles, so I sparsely documented it here. Also, please check out Garry Tinder’s post which goes into details on how to create AAD app to log in using Office 365 CLI.
  2. Create new Azure AD App with a valid name. Leave all other fields/options as-is.

image003.png

  1. Save the app id and tenant id.

image004.png

  1. Give below “application” permissions to the app

image005.png

NOTE: Microsoft Graph permission is not a prerequisite. Ignore it.

 

  1. Make sure the Admin Consent is provided for all the permissions.
  2. Go to “Certificates & Secrets” and choose “Upload certificate” to upload the certificate.cer file created in step 7 in first section.

image006.png

NOTE: Instead of upload certificate, it’s also possible to manually update the manifest file.

 

  1. Save the thumbprint to use later.

 

Artifacts from this section:

  1. App Id
  2. Tenant ID
  3. Thumbprint

 

TEST LOCALLY

  1. Before we can use these artifacts in Azure DevOps pipeline, lets test locally to ensure the certificate is usable with Office 365 CLI login. We need to make the AAD App ID and the Tenant ID available to Office 365 CLI using environment variables. If you are looking to script this or looking for steps to do in other operating systems, I’d refer to Garry  Tinder’s blog post.
  2. Add below environment variables on your PC.
    1. OFFICE365CLI_AADAPPID = App Id
    2. OFFICE365CLI_TENANT = Tenant ID

image007.png

 

  1. Test your certificate by trying to login using O365 CLI in terminal window (PS or Command Win)

 

login --authType certificate --certificateFile C:\OpenSSL-Win64\bin\protected.pfx --thumbprint 5D500FE3BTRUNCATED563173009BC --password pass@word1

 

Note: Change the certificateFile, thumbprint, password as per your environment

 

  1. Run some sample commands. Example:
    1. Status
    2. Spo app list

image008.png

 

USE CERTIFICATE IN AZURE DEVOPS PIPELINE

  1. In this section, we will configure Azure DevOps repository so that the pipelines can use the certificate when logging with Office 365 CLI. Here is a demo repository on GitHub that contains two files:
    1. SPFX Package file (sppkg file)
      1. This is a sample SPFx application customizer extension that adds Azure Application Insights to SPO sites. Note: It can be any other SPFx package file.
    2. Azure-pipelines.yml
      1. YAML pipeline that uses the certificate to login using Office 365 CLI. This pipeline takes the SPFx package, uploads, deploys to SharePoint Online App Catalog site.
  2. First, we need to upload the certificate to the repository. Open your Azure DevOps (ADO) project. Go to Pipelines > Library page.
  3. Select “Secure files” tab. Use the + Secure file button to upload the pfx file.

image009.png

  1. Below you can see the sample entries (script tasks) that you can use in your YAML pipelines to access the certificate from the secure files store.

 

- script: echo Building!

    - task: DownloadSecureFile@1

      name: caCertificate

      displayName: 'Download CA certificate'

      inputs:

        secureFile: 'protected.pfx'

    - script: |

        echo Found cert at $(caCertificate.secureFilePath) 

 ##########################################

    ## login to Office 365 CLI

 ##########################################

    - script: o365 login $(o365_app_catalog_site_url) --authType certificate --certificateFile $(caCertificate.secureFilePath) --thumbprint $(cert_thumbprint) --password pass@word1

      displayName: Login to Office365

 

 

 

  1. When the pipeline executes the first time, you will see a prompt to approve the usage of the certificate. See below screenshot:

image010.png

 

image011.png

 

SAMPLE PIPELINE

Below you can see the Azure pipeline in full. You can access this pipeline on GitHub here.

 

trigger:
  branches:
    include:
      - '*'

variables:
  OFFICE365CLI_AADAPPID: '80fdc955-8677-4251-8d49-050d02071c15'
  OFFICE365CLI_TENANT: '216e190d-67e4-4a6e-98bd-15b8468e5928'
  o365_app_catalog_site_url: 'https://YOURTENANT.sharepoint.com/sites/APPCATALOGSITENAME'
  o365cli_app_catalog_scope: 'tenant'
  node_version: '10.x'
  cert_thumbprint: '5D500FE3B7543FCC61D4DCFD0C164563173009BC'
  spfx-pkg: 'azure-app-insights.sppkg'

pool:
  vmImage: ubuntu-latest

stages:
- stage: Build
  jobs:
  - job: BuildJob
    steps:
    - script: echo Building!
    - task: DownloadSecureFile@1
      name: caCertificate
      displayName: 'Download CA certificate'
      inputs:
        secureFile: 'protected.pfx'
    - script: |
        echo Found cert at $(caCertificate.secureFilePath) 
    ##########################################
    ## specify which node version to use
    ##########################################
    - task: UseNode@1
      displayName: Set to Node.js $(node_version)
      inputs:
        version: $(node_version)
      condition: ne('$(node_version)', '')

    ##########################################
    ## install Office 365 CLI
    ##########################################
    - script: sudo npm install --global @pnp/office365-cli
      displayName: Install Office365 CLI

    ##########################################
    ## login to Office 365 CLI
    ##########################################
    - script: o365 login $(o365_app_catalog_site_url) --authType certificate --certificateFile $(caCertificate.secureFilePath) --thumbprint $(cert_thumbprint) --password pass@word1
      displayName: Login to Office365

    ##########################################
    ## upload *.sppkg to the target app catalog
    ##########################################
    - script: o365 spo app add --filePath $(spfx_pkg) --appCatalogUrl $(o365_app_catalog_site_url) --scope tenant --overwrite
      displayName: Upload SharePoint package to Site Collection App Catalog

    ##########################################
    ##deploy the package
    ##########################################
    - script: o365 spo app deploy --name $(spfx_pkg) --appCatalogUrl $(o365_app_catalog_site_url) --scope tenant
      displayName: Deploy SharePoint package      

 

 

 

 

Thanks for reading. I hope this helps you out.

 

Disclaimer
The sample scripts are not supported under any Microsoft standard support program or service. The sample scripts are provided AS IS without warranty of any kind. Microsoft further disclaims all implied warranties including, without limitation, any implied warranties of merchantability or of fitness for a particular purpose. The entire risk arising out of the use or performance of the sample scripts and documentation remains with you. In no event shall Microsoft, its authors, or anyone else involved in the creation, production, or delivery of the scripts be liable for any damages whatsoever (including, without limitation, damages for loss of business profits, business interruption, loss of business information, or other pecuniary loss) arising out of the use of or inability to use the sample scripts or documentation, even if Microsoft has been advised of the possibility of such damages.