For uploading and deploying SPFx packages I found these permissions to be the bare minimum:
Delegated Microsoft Graph User.Read
Delegated SharePoint AllSites.FullControl
The second part is the service account that just has access to one site collection – Tenant App Catalog. That plus Delegated AllSites.FullControl of the app registration narrows the access to just that site. To install apps the Uploader Account needs to be Site Collection Administrator.
In our project we use Azure Pipelines where we also define the release using .yml. The deployment consists of series of bash inline scripts.
I am not going to describe all the steps for setting up node, npm and installing the office 365 cli. If you already have used Office 365 CLI with the default AAD APP it might look like this:
Now comes the tricky part! If you followed the guide mentioned above, you must have noticed the two environment variables that you need to have:
That’s straight forward when you run the cli in your own console. But the fact is (or at least from what I can see), you cannot “export” variables to other pipeline tasks.
Instead of setting the variables in the inline script, we can take advantage of the Bash task parameter called env:.
Some other findings:
Office 365 CLI needs them in all three commands: login, spo app add, and spo app deploy
If you create and export a variable in a pipeline task, it won’t persist, because every task starts a new shell session.
That means that we need to provide environment variables in every task in the pipeline, that uses Office 365 CLI with a custom Azure AD App. Or is there a better way? Anyway, the version below (the same tasks plus `env`) will work:
Eliminating Legacy Authentication
My goal is to remove the need of legacy authentication. Previously we installed spfx packages using PnP PowerShell. PnP PowerShell in Pipelines causes Legacy Authentication, it can be solved, though:
Sometimes all you need is just a simple static web page: instructions, a landing page, a collection of links. I think I have a perfect use case for Sway. Consider a scenario similar to what Laura Kokkarinen writes in her blog post:
An external user invitation needs an inviteRedirectUrl. Usually it is myapps.microsoft.com. In Laura’s case it was a given extranet url.
In our case we don’t know where an external user will land. After the invitation the external user will be added to some team or a collaboration site.
The default myapps.microsoft.com is a tool where a user can administer his account and accesses, but it might be a confusing place to be sent to after the invitation acceptance process.
A simple static page with clear information is just enough in our case. Fortunately, there is Sway, a simple (but still great) web page builder.
Following alternatives were considered for our landing page:
An “extranet” page in SharePoint Online. It takes time to set up if you don’t have an extranet.
A page in a public portal. Comms and IT must be involved.
A static web page in a blob storage / Azure CDN. It requires some basic web development for design and IT-driven deployment.
Azure App or Azure Function. Actually here it would mean going beyond static. For the initial phase, serving a static page, would also mean basic development and deployment by IT.
Advantages of a Sway page
Easy to create a static web page
Beautiful templates and an easy way to alter the design
Can be driven by the business/comms completely. We only need the url (to put into the invitation call to MS Graph).
Does not require any development or deployment.
Videos, documents can be embedded easily
A sway can be shared with anyone using the link. It means no additional infrastructure steps for this to work (such as firewall, dns etc).
There are some disadvantages, too:
The domain is too generic: sway.office.com. It might look suspicious to some users. Maybe there is a way to use own domain?
A Sway cannot have different languages and switch them based on the user’s locale. It would be great to have something similar to the “Multilingual” functionality in Forms. But still, as a static web page, Sway is doing great, even without the “Multilinguality”.
Sway is an easy “business friendly”, no-code solution for simple, still good-looking web pages, that can be created and updated in no time and shared easily. Being a member of the bigger Microsoft 365 ecosystem, it fills a certain gap where the business can work together with IT and deliver solutions faster.
An encoded value like blankspace (%20) is treated as one character, not three.
A unicode character, and an emoji is treated as one character. Good news for Non-English Names.
Url Parameters, like “?Web=1” are not calculated.
The site url and the document library url is taken into account
All slashes are included
A file extension is also included, and even the dot, e.g. “.docx”
Other related information
A site url and a group name can only be 64 characters max.
The path in the “Copy Link” is much shorter than the “real” path
There is no limit (as of time of writing – 2019-10-30) on the folder name length (other than the bigger limit of 400 characters), I had no issues to add a folder name with 312 characters.
A calculation example
Recommendations for Folder-heavy document management
I don’t want to discuss whether to folder not to folder. On that topic, my favorite is the slide deck with the same name by Bobby Chang: To Folder or Not To Folder. For those who need to use folders I would recommend:
Try to have a short site url/group name
Try to have a short document library url. Why not creating just “docs” instead of “Our very important documents”? Note, that I am talking about the url, not the display name. The trick is to call it “docs” (or some other short word) initially (which will turn to the url), and then you can name it to whatever you please.
Even if you use folders, try to flatten the structure.
I saw a demo of it on the European SharePoint Conference in Copenhagen in 2018. Sebastian Fouillade, who showed this, compared this big change with brain surgery. All the urls, all the connections. But now it is possible. Today I have seen it even in my standard release tenant.
It is really appreciated. Soon it will be possible to rename misspelled sites, like “devlepment” to “development” etc.
I also can image, it will be very handy to change the url of a SharePoint site that was automatically created for a Team (through the Office 365 Group). The team might have some longer name, but a simpler url is often appreciated.
I have tried and seen that also the automatic redirects from an old site url to a new site url works.
Caveats and Limitations
mailNickname ≠ site url
Now it is even more important to not to rely on the fact that mailNickname of an Office 365 Group and Site url are the same. As Elio Struyf describes, it is not a good idea to compose a URL from the group name. I have used in PoCs the site url to get the group id:
A non-admin user can create no more than 250 resources in Azure AD. That is one of the many Azure AD service limits and restrictions. A “resource” can be an app registration, an Office 365 Group etc. But I would like to discuss Groups more in detail.
Imagine the following scenario: Your organization has disabled Office 365 Group Creation. Only IT can create new groups. A service account has been set up for creation of team sites. The application permissions are “binary”, either everything or nothing: Group.ReadWrite.All. This service account will hit the limit very soon.
To prove that, I have created a small script that creates 251 groups.
By the way, just for clarification, when create a new group, that will also create a SharePoint site.
Please don’t try this with your real account in production. The 251st request will fail:
The directory object quota limit for the Principal has been exceeded. Please ask your ad ministrator to increase the quota limit or delete objects to reduce the used quota.
Even if you remove, it will take time to get free slots in this limit:
Deleted Azure AD resources that are no longer available to restore count toward this quota at a value of one-quarter for 30 days.
There is not much to do about it. For App Registrations you can create and assign a custom role. But for groups there is no custom roles available.
It might be obvious, but still:
Admins do not have this limit. But not all “admin roles” are really admins. Those roles are excepted:
Those roles are not excepted:
Message Center Reader
I don’t have time to try every admin role, but I suppose only admins that can change global configuration, are excepted, not the reader ones.
Since communication sites do not have an Office 365 Group behind the scenes, a non-admin user will still be able to create such sites even after the limit is hit.
Workarounds and Solutions
Since my scenario for creating groups with a service account does not work, we need to seek workarounds and solutions.
Do not restrict Group Creation
That is the best one. If users can create groups/sites by themselves, then none of this would be a problem. But still, in my scenario, there is a business requirement to control the creation of groups.
Application Permissions Group.ReadWrite.All
That is exactly the opposite of my scenario. This gives that application full access to all groups and files (!). This means, that application can access all Group-Connected SharePoint Sites as well.
Microsoft creates permissions for groups
If we also had “groups” permissions for custom roles, then we could do the same way as with app registrations. Today (2019-10-25), there are only permissions for applications.
Microsoft creates new permission Group.Create.All
If there were a permission for only creating groups, that would solve the problem.
There is a similar role: User.Invite.All, it allows only invitations, not editing All Users.
Microsoft allows exceptions per user
If there were a switch for the 250-limit per user, that would also solve the problem.
Granting the service account admin rights
Granting SharePoint Admin would solve the problem, but at what price? That is safer than Application Permissions Group.ReadWrite.All, since you need to actively add this account to the groups in order to read all the files, but this is still less secure than just a non-admin account.
Having multiple service accounts
If we had account 1..100 and we used every account 250 times. Theoretically it should work, but it is a cumbersome process. You need to keep track of how many groups an account as created, or having the right error handling. How should the password be kept safely. Should the accounts be removed when they have reached the 250 limit?
Group Creation Microservice
To overcome the limits and the ungranularity in the built-in permissions in Office 365, one way to solve it would be a tiny, but a dedicated, and secured service for creation of groups (and sites). It would still need the “hefty” Group.ReadWrite.All Application Permissions, but making it do the only thing and do it right, would mitigate the risks.
It could be a simple Azure Function that few have access to. That could be just a couple of lines of code.
Tip #1 You don’t need Tenant Admin rights to add a new Site Collection App Catalog
I have seen many blogs, forum threads etc that state that only Global Tenant Administrators can add new Site Collection App Catalogs. The truth is that a SharePoint Admin rights are enough. The trick is to make that SharePoint Admin Account to a site collection administrator of the app catalog site. To be precise the account that adds a new SCAC must have Manage Web Permissions, as stated in error message:
Add-SPOSiteCollectionAppCatalog : Must have Manage Web Site permissions or be a tenant admin in order to add or remove sites from the site collection app catalog allow list
Tip #2 List all Site Collection App Catalogs
To list all the SCACs in your tenant navigate to that url:
Currently, it’s not possible to list all site collections in the tenant that have the site collection app catalog enabled.
The fun fact was that I sherlocked it since I knew my account needed access to the main App Catalog site. So there must be some information that is stored. How is it done a là SharePoint – yes, it is stored in a hidden list. Like in the olden days. 🧐
This is about a topic brought up by Waldek Mastykarz: Just because you can should you use the Office 365 CDN. In my post I want to take a closer look at the private CDN option in Office 365. Please note, the whole thing is subject to change, and it reflects the circumstances at the time of writing – 2019-08-26.
I use Modern Team Sites and Communication Sites. Is the Private Office 365 CDN something for me?
No, the urls are changing. You cannot “hardcode” them. Automatic URL Rewrite works only on classic Publishing Sites.
I have Provider Hosted Add-Ins. Is the Private Office 365 CDN something for me?
No, the referrer needs to be a subdomain of sharepoint.com.
The whole point of having a private CDN is that it is not available for strangers. But when you enable it, you’ll see an eligible warning:
WARNING: This is a feature built on a 3rd party application with privacy and compliance standards that differ from the commitments outlined by the Microsoft Office365 Trust Center. Any data cached through this service does not conform to the Microsoft Data Processing Terms (DPT) and is outside of the Microsoft Office365 Trust Center compliance boundaries.
If you remove an asset from the private cdn origins, it takes up to 15 minutes for the link to be invalidated. Opposed to an immediate effect for a direct link to an asset in a document library.
To keep it more secure, the default private cdn origins should not be included, especially */SITEASSETS, Because site assets can have important information, and this makes every single site assets library vulnerable, asterisk means all.
Even the CDN Policies should be restrictive.
Overall, if the usage area is small, the performance gain is little, we should not enable it at all. Because: any cached data in a private Office 365 CDN is outside of the Microsoft Office365 Trust Center compliance boundaries.
I have tried the private CDN. My setup was a document library with three versions of a picture that was 2,4MB that I put to three different libraries:
On the publishing site I inserted three images on a page and compared the load time in the DevTools. During this test I had Cache Disabled. I got following results:
private, public, nocdn
3.04s, 3.03s, 3.24s
1.78s, 1.77s, 1.75s
1.99s, 1,95s, 3.32s
1.67s, 0.73s, 0.72s
1.73s, 1.71s, 1.97s
1.60s, 1.58s, 1.67s
So only once I got a bigger difference, otherwise it took the same time to load a picture from a document library without CDN.
To be fair, it is a very simple performance test. Tests with bigger files, different geographical locations would probably give a more detailed view of that. And still, without a URL Rewrite that is only present on Publishing sites, you cannot take use private cdn origins.
Private CDN in Office 365 can be interesting in future, but today, the usage is narrow (only publishing sites can refer to assets in a private CDN), the performance gain is little and lower security makes it to a bad choice.